aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/mc/mc-dev-allocator.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-09 09:47:22 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-09 09:47:22 -0700
commited63b9c873601ca113da5c7b1745e3946493e9f3 (patch)
tree94e96db2b79a8d123c0645dd64b3830bc4d20bfe /drivers/media/mc/mc-dev-allocator.c
parentMerge tag 'please-pull-for_5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/ras/ras (diff)
parentmedia: allegro: use new v4l2_m2m_ioctl_try_encoder_cmd funcs (diff)
downloadlinux-dev-ed63b9c873601ca113da5c7b1745e3946493e9f3.tar.xz
linux-dev-ed63b9c873601ca113da5c7b1745e3946493e9f3.zip
Merge tag 'media/v5.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab: - new Atmel microship ISC driver - coda has gained support for mpeg2 and mpeg4 - cxusb gained support for analog TV - rockchip staging driver was split into two separate staging drivers - added a new staging driver for Allegro DVT video IP core - added a new staging driver for Amlogic Meson video decoder - lots of improvements and cleanups * tag 'media/v5.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (398 commits) media: allegro: use new v4l2_m2m_ioctl_try_encoder_cmd funcs media: doc-rst: Fix typos media: radio-raremono: change devm_k*alloc to k*alloc media: stv0297: fix frequency range limit media: rc: Prefer KEY_NUMERIC_* for number buttons on remotes media: dvb_frontend: split dvb_frontend_handle_ioctl function media: mceusb: disable "nonsensical irdata" messages media: rc: remove redundant dev_err message media: cec-notifier: add new notifier functions media: cec: add struct cec_connector_info support media: cec-notifier: rename variables, check kstrdup and n->conn_name media: MAINTAINERS: Add maintainers for Media Controller media: staging: media: tegra-vde: Defer dmabuf's unmapping media: staging: media: tegra-vde: Add IOMMU support media: hdpvr: fix locking and a missing msleep media: v4l2: Test type instead of cfg->type in v4l2_ctrl_new_custom() media: atmel: atmel-isc: fix i386 build error media: v4l2-ctrl: Move compound control initialization media: hantro: Use vb2_get_buffer media: pci: cx88: Change the type of 'missed' to u64 ...
Diffstat (limited to 'drivers/media/mc/mc-dev-allocator.c')
-rw-r--r--drivers/media/mc/mc-dev-allocator.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/drivers/media/mc/mc-dev-allocator.c b/drivers/media/mc/mc-dev-allocator.c
new file mode 100644
index 000000000000..ae17887dec59
--- /dev/null
+++ b/drivers/media/mc/mc-dev-allocator.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * media-dev-allocator.c - Media Controller Device Allocator API
+ *
+ * Copyright (c) 2019 Shuah Khan <shuah@kernel.org>
+ *
+ * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+/*
+ * This file adds a global refcounted Media Controller Device Instance API.
+ * A system wide global media device list is managed and each media device
+ * includes a kref count. The last put on the media device releases the media
+ * device instance.
+ *
+ */
+
+#include <linux/kref.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include <media/media-device.h>
+#include <media/media-dev-allocator.h>
+
+static LIST_HEAD(media_device_list);
+static DEFINE_MUTEX(media_device_lock);
+
+struct media_device_instance {
+ struct media_device mdev;
+ struct module *owner;
+ struct list_head list;
+ struct kref refcount;
+};
+
+static inline struct media_device_instance *
+to_media_device_instance(struct media_device *mdev)
+{
+ return container_of(mdev, struct media_device_instance, mdev);
+}
+
+static void media_device_instance_release(struct kref *kref)
+{
+ struct media_device_instance *mdi =
+ container_of(kref, struct media_device_instance, refcount);
+
+ dev_dbg(mdi->mdev.dev, "%s: releasing Media Device\n", __func__);
+
+ mutex_lock(&media_device_lock);
+
+ media_device_unregister(&mdi->mdev);
+ media_device_cleanup(&mdi->mdev);
+
+ list_del(&mdi->list);
+ mutex_unlock(&media_device_lock);
+
+ kfree(mdi);
+}
+
+/* Callers should hold media_device_lock when calling this function */
+static struct media_device *__media_device_get(struct device *dev,
+ const char *module_name,
+ struct module *owner)
+{
+ struct media_device_instance *mdi;
+
+ list_for_each_entry(mdi, &media_device_list, list) {
+ if (mdi->mdev.dev != dev)
+ continue;
+
+ kref_get(&mdi->refcount);
+
+ /* get module reference for the media_device owner */
+ if (owner != mdi->owner && !try_module_get(mdi->owner))
+ dev_err(dev,
+ "%s: module %s get owner reference error\n",
+ __func__, module_name);
+ else
+ dev_dbg(dev, "%s: module %s got owner reference\n",
+ __func__, module_name);
+ return &mdi->mdev;
+ }
+
+ mdi = kzalloc(sizeof(*mdi), GFP_KERNEL);
+ if (!mdi)
+ return NULL;
+
+ mdi->owner = owner;
+ kref_init(&mdi->refcount);
+ list_add_tail(&mdi->list, &media_device_list);
+
+ dev_dbg(dev, "%s: Allocated media device for owner %s\n",
+ __func__, module_name);
+ return &mdi->mdev;
+}
+
+struct media_device *media_device_usb_allocate(struct usb_device *udev,
+ const char *module_name,
+ struct module *owner)
+{
+ struct media_device *mdev;
+
+ mutex_lock(&media_device_lock);
+ mdev = __media_device_get(&udev->dev, module_name, owner);
+ if (!mdev) {
+ mutex_unlock(&media_device_lock);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* check if media device is already initialized */
+ if (!mdev->dev)
+ __media_device_usb_init(mdev, udev, udev->product,
+ module_name);
+ mutex_unlock(&media_device_lock);
+ return mdev;
+}
+EXPORT_SYMBOL_GPL(media_device_usb_allocate);
+
+void media_device_delete(struct media_device *mdev, const char *module_name,
+ struct module *owner)
+{
+ struct media_device_instance *mdi = to_media_device_instance(mdev);
+
+ mutex_lock(&media_device_lock);
+ /* put module reference for the media_device owner */
+ if (mdi->owner != owner) {
+ module_put(mdi->owner);
+ dev_dbg(mdi->mdev.dev,
+ "%s: module %s put owner module reference\n",
+ __func__, module_name);
+ }
+ mutex_unlock(&media_device_lock);
+ kref_put(&mdi->refcount, media_device_instance_release);
+}
+EXPORT_SYMBOL_GPL(media_device_delete);