]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
media: move drivers/media/media-* to drivers/media/mc/mc-*
authorHans Verkuil <hverkuil@xs4all.nl>
Thu, 2 May 2019 13:42:31 +0000 (09:42 -0400)
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>
Tue, 28 May 2019 16:15:46 +0000 (12:15 -0400)
It is really weird that the media controller sources are all top-level
in drivers/media. It is a bit of a left-over from long ago when most
media sources were all at the top-level. At some point we reorganized
the directory structure, but the media-*.c sources where never moved
to their own directory.

So create a new mc directory and move all sources there. Also rename
the prefix from media- to mc-.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
14 files changed:
drivers/media/Kconfig
drivers/media/Makefile
drivers/media/mc/Kconfig [new file with mode: 0644]
drivers/media/mc/Makefile [new file with mode: 0644]
drivers/media/mc/mc-dev-allocator.c [new file with mode: 0644]
drivers/media/mc/mc-device.c [new file with mode: 0644]
drivers/media/mc/mc-devnode.c [new file with mode: 0644]
drivers/media/mc/mc-entity.c [new file with mode: 0644]
drivers/media/mc/mc-request.c [new file with mode: 0644]
drivers/media/media-dev-allocator.c [deleted file]
drivers/media/media-device.c [deleted file]
drivers/media/media-devnode.c [deleted file]
drivers/media/media-entity.c [deleted file]
drivers/media/media-request.c [deleted file]

index ce6782bc53ef95f73a205c0f62cc876420c254ae..21cd9c02960b8b96496b739159dac0c9a16a4e44 100644 (file)
@@ -89,39 +89,7 @@ config MEDIA_CEC_SUPPORT
 
 source "drivers/media/cec/Kconfig"
 
-#
-# Media controller
-#      Selectable only for webcam/grabbers, as other drivers don't use it
-#
-
-config MEDIA_CONTROLLER
-       bool "Media Controller API"
-       depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
-       help
-         Enable the media controller API used to query media devices internal
-         topology and configure it dynamically.
-
-         This API is mostly used by camera interfaces in embedded platforms.
-
-config MEDIA_CONTROLLER_DVB
-       bool "Enable Media controller for DVB (EXPERIMENTAL)"
-       depends on MEDIA_CONTROLLER && DVB_CORE
-       help
-         Enable the media controller API support for DVB.
-
-         This is currently experimental.
-
-config MEDIA_CONTROLLER_REQUEST_API
-       bool "Enable Media controller Request API (EXPERIMENTAL)"
-       depends on MEDIA_CONTROLLER && STAGING_MEDIA
-       help
-         DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING.
-
-         This option enables the Request API for the Media controller and V4L2
-         interfaces. It is currently needed by a few stateless codec drivers.
-
-         There is currently no intention to provide API or ABI stability for
-         this new API as of yet.
+source "drivers/media/mc/Kconfig"
 
 #
 # Video4Linux support
index 4a330d0e5e40002d60c480006b757aef3f49fbc7..f215f0a89f9e648eddde7f2d58fe2a2a58dee62f 100644 (file)
@@ -3,15 +3,6 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-media-objs     := media-device.o media-devnode.o media-entity.o \
-                  media-request.o
-
-ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
-       ifeq ($(CONFIG_USB),y)
-               media-objs += media-dev-allocator.o
-       endif
-endif
-
 #
 # I2C drivers should come before other drivers, otherwise they'll fail
 # when compiled as builtin drivers
@@ -20,10 +11,10 @@ obj-y += i2c/ tuners/
 obj-$(CONFIG_DVB_CORE)  += dvb-frontends/
 
 #
-# Now, let's link-in the media core
+# Now, let's link-in the media controller core
 #
 ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
-  obj-$(CONFIG_MEDIA_SUPPORT) += media.o
+  obj-$(CONFIG_MEDIA_SUPPORT) += mc/
 endif
 
 obj-$(CONFIG_VIDEO_DEV) += v4l2-core/
diff --git a/drivers/media/mc/Kconfig b/drivers/media/mc/Kconfig
new file mode 100644 (file)
index 0000000..3b9795c
--- /dev/null
@@ -0,0 +1,33 @@
+#
+# Media controller
+#      Selectable only for webcam/grabbers, as other drivers don't use it
+#
+
+config MEDIA_CONTROLLER
+       bool "Media Controller API"
+       depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
+       help
+         Enable the media controller API used to query media devices internal
+         topology and configure it dynamically.
+
+         This API is mostly used by camera interfaces in embedded platforms.
+
+config MEDIA_CONTROLLER_DVB
+       bool "Enable Media controller for DVB (EXPERIMENTAL)"
+       depends on MEDIA_CONTROLLER && DVB_CORE
+       help
+         Enable the media controller API support for DVB.
+
+         This is currently experimental.
+
+config MEDIA_CONTROLLER_REQUEST_API
+       bool "Enable Media controller Request API (EXPERIMENTAL)"
+       depends on MEDIA_CONTROLLER && STAGING_MEDIA
+       help
+         DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING.
+
+         This option enables the Request API for the Media controller and V4L2
+         interfaces. It is currently needed by a few stateless codec drivers.
+
+         There is currently no intention to provide API or ABI stability for
+         this new API as of yet.
diff --git a/drivers/media/mc/Makefile b/drivers/media/mc/Makefile
new file mode 100644 (file)
index 0000000..119037f
--- /dev/null
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+
+mc-objs        := mc-device.o mc-devnode.o mc-entity.o \
+          mc-request.o
+
+ifeq ($(CONFIG_USB),y)
+       mc-objs += mc-dev-allocator.o
+endif
+
+obj-$(CONFIG_MEDIA_SUPPORT) += mc.o
diff --git a/drivers/media/mc/mc-dev-allocator.c b/drivers/media/mc/mc-dev-allocator.c
new file mode 100644 (file)
index 0000000..ae17887
--- /dev/null
@@ -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);
diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c
new file mode 100644 (file)
index 0000000..6893843
--- /dev/null
@@ -0,0 +1,909 @@
+/*
+ * Media device
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/compat.h>
+#include <linux/export.h>
+#include <linux/idr.h>
+#include <linux/ioctl.h>
+#include <linux/media.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+
+#include <media/media-device.h>
+#include <media/media-devnode.h>
+#include <media/media-entity.h>
+#include <media/media-request.h>
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+
+/*
+ * Legacy defines from linux/media.h. This is the only place we need this
+ * so we just define it here. The media.h header doesn't expose it to the
+ * kernel to prevent it from being used by drivers, but here (and only here!)
+ * we need it to handle the legacy behavior.
+ */
+#define MEDIA_ENT_SUBTYPE_MASK                 0x0000ffff
+#define MEDIA_ENT_T_DEVNODE_UNKNOWN            (MEDIA_ENT_F_OLD_BASE | \
+                                                MEDIA_ENT_SUBTYPE_MASK)
+
+/* -----------------------------------------------------------------------------
+ * Userspace API
+ */
+
+static inline void __user *media_get_uptr(__u64 arg)
+{
+       return (void __user *)(uintptr_t)arg;
+}
+
+static int media_device_open(struct file *filp)
+{
+       return 0;
+}
+
+static int media_device_close(struct file *filp)
+{
+       return 0;
+}
+
+static long media_device_get_info(struct media_device *dev, void *arg)
+{
+       struct media_device_info *info = arg;
+
+       memset(info, 0, sizeof(*info));
+
+       if (dev->driver_name[0])
+               strscpy(info->driver, dev->driver_name, sizeof(info->driver));
+       else
+               strscpy(info->driver, dev->dev->driver->name,
+                       sizeof(info->driver));
+
+       strscpy(info->model, dev->model, sizeof(info->model));
+       strscpy(info->serial, dev->serial, sizeof(info->serial));
+       strscpy(info->bus_info, dev->bus_info, sizeof(info->bus_info));
+
+       info->media_version = LINUX_VERSION_CODE;
+       info->driver_version = info->media_version;
+       info->hw_revision = dev->hw_revision;
+
+       return 0;
+}
+
+static struct media_entity *find_entity(struct media_device *mdev, u32 id)
+{
+       struct media_entity *entity;
+       int next = id & MEDIA_ENT_ID_FLAG_NEXT;
+
+       id &= ~MEDIA_ENT_ID_FLAG_NEXT;
+
+       media_device_for_each_entity(entity, mdev) {
+               if (((media_entity_id(entity) == id) && !next) ||
+                   ((media_entity_id(entity) > id) && next)) {
+                       return entity;
+               }
+       }
+
+       return NULL;
+}
+
+static long media_device_enum_entities(struct media_device *mdev, void *arg)
+{
+       struct media_entity_desc *entd = arg;
+       struct media_entity *ent;
+
+       ent = find_entity(mdev, entd->id);
+       if (ent == NULL)
+               return -EINVAL;
+
+       memset(entd, 0, sizeof(*entd));
+
+       entd->id = media_entity_id(ent);
+       if (ent->name)
+               strscpy(entd->name, ent->name, sizeof(entd->name));
+       entd->type = ent->function;
+       entd->revision = 0;             /* Unused */
+       entd->flags = ent->flags;
+       entd->group_id = 0;             /* Unused */
+       entd->pads = ent->num_pads;
+       entd->links = ent->num_links - ent->num_backlinks;
+
+       /*
+        * Workaround for a bug at media-ctl <= v1.10 that makes it to
+        * do the wrong thing if the entity function doesn't belong to
+        * either MEDIA_ENT_F_OLD_BASE or MEDIA_ENT_F_OLD_SUBDEV_BASE
+        * Ranges.
+        *
+        * Non-subdevices are expected to be at the MEDIA_ENT_F_OLD_BASE,
+        * or, otherwise, will be silently ignored by media-ctl when
+        * printing the graphviz diagram. So, map them into the devnode
+        * old range.
+        */
+       if (ent->function < MEDIA_ENT_F_OLD_BASE ||
+           ent->function > MEDIA_ENT_F_TUNER) {
+               if (is_media_entity_v4l2_subdev(ent))
+                       entd->type = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+               else if (ent->function != MEDIA_ENT_F_IO_V4L)
+                       entd->type = MEDIA_ENT_T_DEVNODE_UNKNOWN;
+       }
+
+       memcpy(&entd->raw, &ent->info, sizeof(ent->info));
+
+       return 0;
+}
+
+static void media_device_kpad_to_upad(const struct media_pad *kpad,
+                                     struct media_pad_desc *upad)
+{
+       upad->entity = media_entity_id(kpad->entity);
+       upad->index = kpad->index;
+       upad->flags = kpad->flags;
+}
+
+static long media_device_enum_links(struct media_device *mdev, void *arg)
+{
+       struct media_links_enum *links = arg;
+       struct media_entity *entity;
+
+       entity = find_entity(mdev, links->entity);
+       if (entity == NULL)
+               return -EINVAL;
+
+       if (links->pads) {
+               unsigned int p;
+
+               for (p = 0; p < entity->num_pads; p++) {
+                       struct media_pad_desc pad;
+
+                       memset(&pad, 0, sizeof(pad));
+                       media_device_kpad_to_upad(&entity->pads[p], &pad);
+                       if (copy_to_user(&links->pads[p], &pad, sizeof(pad)))
+                               return -EFAULT;
+               }
+       }
+
+       if (links->links) {
+               struct media_link *link;
+               struct media_link_desc __user *ulink_desc = links->links;
+
+               list_for_each_entry(link, &entity->links, list) {
+                       struct media_link_desc klink_desc;
+
+                       /* Ignore backlinks. */
+                       if (link->source->entity != entity)
+                               continue;
+                       memset(&klink_desc, 0, sizeof(klink_desc));
+                       media_device_kpad_to_upad(link->source,
+                                                 &klink_desc.source);
+                       media_device_kpad_to_upad(link->sink,
+                                                 &klink_desc.sink);
+                       klink_desc.flags = link->flags;
+                       if (copy_to_user(ulink_desc, &klink_desc,
+                                        sizeof(*ulink_desc)))
+                               return -EFAULT;
+                       ulink_desc++;
+               }
+       }
+       memset(links->reserved, 0, sizeof(links->reserved));
+
+       return 0;
+}
+
+static long media_device_setup_link(struct media_device *mdev, void *arg)
+{
+       struct media_link_desc *linkd = arg;
+       struct media_link *link = NULL;
+       struct media_entity *source;
+       struct media_entity *sink;
+
+       /* Find the source and sink entities and link.
+        */
+       source = find_entity(mdev, linkd->source.entity);
+       sink = find_entity(mdev, linkd->sink.entity);
+
+       if (source == NULL || sink == NULL)
+               return -EINVAL;
+
+       if (linkd->source.index >= source->num_pads ||
+           linkd->sink.index >= sink->num_pads)
+               return -EINVAL;
+
+       link = media_entity_find_link(&source->pads[linkd->source.index],
+                                     &sink->pads[linkd->sink.index]);
+       if (link == NULL)
+               return -EINVAL;
+
+       memset(linkd->reserved, 0, sizeof(linkd->reserved));
+
+       /* Setup the link on both entities. */
+       return __media_entity_setup_link(link, linkd->flags);
+}
+
+static long media_device_get_topology(struct media_device *mdev, void *arg)
+{
+       struct media_v2_topology *topo = arg;
+       struct media_entity *entity;
+       struct media_interface *intf;
+       struct media_pad *pad;
+       struct media_link *link;
+       struct media_v2_entity kentity, __user *uentity;
+       struct media_v2_interface kintf, __user *uintf;
+       struct media_v2_pad kpad, __user *upad;
+       struct media_v2_link klink, __user *ulink;
+       unsigned int i;
+       int ret = 0;
+
+       topo->topology_version = mdev->topology_version;
+
+       /* Get entities and number of entities */
+       i = 0;
+       uentity = media_get_uptr(topo->ptr_entities);
+       media_device_for_each_entity(entity, mdev) {
+               i++;
+               if (ret || !uentity)
+                       continue;
+
+               if (i > topo->num_entities) {
+                       ret = -ENOSPC;
+                       continue;
+               }
+
+               /* Copy fields to userspace struct if not error */
+               memset(&kentity, 0, sizeof(kentity));
+               kentity.id = entity->graph_obj.id;
+               kentity.function = entity->function;
+               kentity.flags = entity->flags;
+               strscpy(kentity.name, entity->name,
+                       sizeof(kentity.name));
+
+               if (copy_to_user(uentity, &kentity, sizeof(kentity)))
+                       ret = -EFAULT;
+               uentity++;
+       }
+       topo->num_entities = i;
+       topo->reserved1 = 0;
+
+       /* Get interfaces and number of interfaces */
+       i = 0;
+       uintf = media_get_uptr(topo->ptr_interfaces);
+       media_device_for_each_intf(intf, mdev) {
+               i++;
+               if (ret || !uintf)
+                       continue;
+
+               if (i > topo->num_interfaces) {
+                       ret = -ENOSPC;
+                       continue;
+               }
+
+               memset(&kintf, 0, sizeof(kintf));
+
+               /* Copy intf fields to userspace struct */
+               kintf.id = intf->graph_obj.id;
+               kintf.intf_type = intf->type;
+               kintf.flags = intf->flags;
+
+               if (media_type(&intf->graph_obj) == MEDIA_GRAPH_INTF_DEVNODE) {
+                       struct media_intf_devnode *devnode;
+
+                       devnode = intf_to_devnode(intf);
+
+                       kintf.devnode.major = devnode->major;
+                       kintf.devnode.minor = devnode->minor;
+               }
+
+               if (copy_to_user(uintf, &kintf, sizeof(kintf)))
+                       ret = -EFAULT;
+               uintf++;
+       }
+       topo->num_interfaces = i;
+       topo->reserved2 = 0;
+
+       /* Get pads and number of pads */
+       i = 0;
+       upad = media_get_uptr(topo->ptr_pads);
+       media_device_for_each_pad(pad, mdev) {
+               i++;
+               if (ret || !upad)
+                       continue;
+
+               if (i > topo->num_pads) {
+                       ret = -ENOSPC;
+                       continue;
+               }
+
+               memset(&kpad, 0, sizeof(kpad));
+
+               /* Copy pad fields to userspace struct */
+               kpad.id = pad->graph_obj.id;
+               kpad.entity_id = pad->entity->graph_obj.id;
+               kpad.flags = pad->flags;
+               kpad.index = pad->index;
+
+               if (copy_to_user(upad, &kpad, sizeof(kpad)))
+                       ret = -EFAULT;
+               upad++;
+       }
+       topo->num_pads = i;
+       topo->reserved3 = 0;
+
+       /* Get links and number of links */
+       i = 0;
+       ulink = media_get_uptr(topo->ptr_links);
+       media_device_for_each_link(link, mdev) {
+               if (link->is_backlink)
+                       continue;
+
+               i++;
+
+               if (ret || !ulink)
+                       continue;
+
+               if (i > topo->num_links) {
+                       ret = -ENOSPC;
+                       continue;
+               }
+
+               memset(&klink, 0, sizeof(klink));
+
+               /* Copy link fields to userspace struct */
+               klink.id = link->graph_obj.id;
+               klink.source_id = link->gobj0->id;
+               klink.sink_id = link->gobj1->id;
+               klink.flags = link->flags;
+
+               if (copy_to_user(ulink, &klink, sizeof(klink)))
+                       ret = -EFAULT;
+               ulink++;
+       }
+       topo->num_links = i;
+       topo->reserved4 = 0;
+
+       return ret;
+}
+
+static long media_device_request_alloc(struct media_device *mdev,
+                                      int *alloc_fd)
+{
+#ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API
+       if (!mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue)
+               return -ENOTTY;
+
+       return media_request_alloc(mdev, alloc_fd);
+#else
+       return -ENOTTY;
+#endif
+}
+
+static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd)
+{
+       if ((_IOC_DIR(cmd) & _IOC_WRITE) &&
+           copy_from_user(karg, uarg, _IOC_SIZE(cmd)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static long copy_arg_to_user(void __user *uarg, void *karg, unsigned int cmd)
+{
+       if ((_IOC_DIR(cmd) & _IOC_READ) &&
+           copy_to_user(uarg, karg, _IOC_SIZE(cmd)))
+               return -EFAULT;
+
+       return 0;
+}
+
+/* Do acquire the graph mutex */
+#define MEDIA_IOC_FL_GRAPH_MUTEX       BIT(0)
+
+#define MEDIA_IOC_ARG(__cmd, func, fl, from_user, to_user)             \
+       [_IOC_NR(MEDIA_IOC_##__cmd)] = {                                \
+               .cmd = MEDIA_IOC_##__cmd,                               \
+               .fn = (long (*)(struct media_device *, void *))func,    \
+               .flags = fl,                                            \
+               .arg_from_user = from_user,                             \
+               .arg_to_user = to_user,                                 \
+       }
+
+#define MEDIA_IOC(__cmd, func, fl)                                     \
+       MEDIA_IOC_ARG(__cmd, func, fl, copy_arg_from_user, copy_arg_to_user)
+
+/* the table is indexed by _IOC_NR(cmd) */
+struct media_ioctl_info {
+       unsigned int cmd;
+       unsigned short flags;
+       long (*fn)(struct media_device *dev, void *arg);
+       long (*arg_from_user)(void *karg, void __user *uarg, unsigned int cmd);
+       long (*arg_to_user)(void __user *uarg, void *karg, unsigned int cmd);
+};
+
+static const struct media_ioctl_info ioctl_info[] = {
+       MEDIA_IOC(DEVICE_INFO, media_device_get_info, MEDIA_IOC_FL_GRAPH_MUTEX),
+       MEDIA_IOC(ENUM_ENTITIES, media_device_enum_entities, MEDIA_IOC_FL_GRAPH_MUTEX),
+       MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX),
+       MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_FL_GRAPH_MUTEX),
+       MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX),
+       MEDIA_IOC(REQUEST_ALLOC, media_device_request_alloc, 0),
+};
+
+static long media_device_ioctl(struct file *filp, unsigned int cmd,
+                              unsigned long __arg)
+{
+       struct media_devnode *devnode = media_devnode_data(filp);
+       struct media_device *dev = devnode->media_dev;
+       const struct media_ioctl_info *info;
+       void __user *arg = (void __user *)__arg;
+       char __karg[256], *karg = __karg;
+       long ret;
+
+       if (_IOC_NR(cmd) >= ARRAY_SIZE(ioctl_info)
+           || ioctl_info[_IOC_NR(cmd)].cmd != cmd)
+               return -ENOIOCTLCMD;
+
+       info = &ioctl_info[_IOC_NR(cmd)];
+
+       if (_IOC_SIZE(info->cmd) > sizeof(__karg)) {
+               karg = kmalloc(_IOC_SIZE(info->cmd), GFP_KERNEL);
+               if (!karg)
+                       return -ENOMEM;
+       }
+
+       if (info->arg_from_user) {
+               ret = info->arg_from_user(karg, arg, cmd);
+               if (ret)
+                       goto out_free;
+       }
+
+       if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX)
+               mutex_lock(&dev->graph_mutex);
+
+       ret = info->fn(dev, karg);
+
+       if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX)
+               mutex_unlock(&dev->graph_mutex);
+
+       if (!ret && info->arg_to_user)
+               ret = info->arg_to_user(arg, karg, cmd);
+
+out_free:
+       if (karg != __karg)
+               kfree(karg);
+
+       return ret;
+}
+
+#ifdef CONFIG_COMPAT
+
+struct media_links_enum32 {
+       __u32 entity;
+       compat_uptr_t pads; /* struct media_pad_desc * */
+       compat_uptr_t links; /* struct media_link_desc * */
+       __u32 reserved[4];
+};
+
+static long media_device_enum_links32(struct media_device *mdev,
+                                     struct media_links_enum32 __user *ulinks)
+{
+       struct media_links_enum links;
+       compat_uptr_t pads_ptr, links_ptr;
+       int ret;
+
+       memset(&links, 0, sizeof(links));
+
+       if (get_user(links.entity, &ulinks->entity)
+           || get_user(pads_ptr, &ulinks->pads)
+           || get_user(links_ptr, &ulinks->links))
+               return -EFAULT;
+
+       links.pads = compat_ptr(pads_ptr);
+       links.links = compat_ptr(links_ptr);
+
+       ret = media_device_enum_links(mdev, &links);
+       if (ret)
+               return ret;
+
+       memset(ulinks->reserved, 0, sizeof(ulinks->reserved));
+
+       return 0;
+}
+
+#define MEDIA_IOC_ENUM_LINKS32         _IOWR('|', 0x02, struct media_links_enum32)
+
+static long media_device_compat_ioctl(struct file *filp, unsigned int cmd,
+                                     unsigned long arg)
+{
+       struct media_devnode *devnode = media_devnode_data(filp);
+       struct media_device *dev = devnode->media_dev;
+       long ret;
+
+       switch (cmd) {
+       case MEDIA_IOC_ENUM_LINKS32:
+               mutex_lock(&dev->graph_mutex);
+               ret = media_device_enum_links32(dev,
+                               (struct media_links_enum32 __user *)arg);
+               mutex_unlock(&dev->graph_mutex);
+               break;
+
+       default:
+               return media_device_ioctl(filp, cmd, arg);
+       }
+
+       return ret;
+}
+#endif /* CONFIG_COMPAT */
+
+static const struct media_file_operations media_device_fops = {
+       .owner = THIS_MODULE,
+       .open = media_device_open,
+       .ioctl = media_device_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = media_device_compat_ioctl,
+#endif /* CONFIG_COMPAT */
+       .release = media_device_close,
+};
+
+/* -----------------------------------------------------------------------------
+ * sysfs
+ */
+
+static ssize_t show_model(struct device *cd,
+                         struct device_attribute *attr, char *buf)
+{
+       struct media_devnode *devnode = to_media_devnode(cd);
+       struct media_device *mdev = devnode->media_dev;
+
+       return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
+}
+
+static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
+
+/* -----------------------------------------------------------------------------
+ * Registration/unregistration
+ */
+
+static void media_device_release(struct media_devnode *devnode)
+{
+       dev_dbg(devnode->parent, "Media device released\n");
+}
+
+/**
+ * media_device_register_entity - Register an entity with a media device
+ * @mdev:      The media device
+ * @entity:    The entity
+ */
+int __must_check media_device_register_entity(struct media_device *mdev,
+                                             struct media_entity *entity)
+{
+       struct media_entity_notify *notify, *next;
+       unsigned int i;
+       int ret;
+
+       if (entity->function == MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN ||
+           entity->function == MEDIA_ENT_F_UNKNOWN)
+               dev_warn(mdev->dev,
+                        "Entity type for entity %s was not initialized!\n",
+                        entity->name);
+
+       /* Warn if we apparently re-register an entity */
+       WARN_ON(entity->graph_obj.mdev != NULL);
+       entity->graph_obj.mdev = mdev;
+       INIT_LIST_HEAD(&entity->links);
+       entity->num_links = 0;
+       entity->num_backlinks = 0;
+
+       ret = ida_alloc_min(&mdev->entity_internal_idx, 1, GFP_KERNEL);
+       if (ret < 0)
+               return ret;
+       entity->internal_idx = ret;
+
+       mutex_lock(&mdev->graph_mutex);
+       mdev->entity_internal_idx_max =
+               max(mdev->entity_internal_idx_max, entity->internal_idx);
+
+       /* Initialize media_gobj embedded at the entity */
+       media_gobj_create(mdev, MEDIA_GRAPH_ENTITY, &entity->graph_obj);
+
+       /* Initialize objects at the pads */
+       for (i = 0; i < entity->num_pads; i++)
+               media_gobj_create(mdev, MEDIA_GRAPH_PAD,
+                              &entity->pads[i].graph_obj);
+
+       /* invoke entity_notify callbacks */
+       list_for_each_entry_safe(notify, next, &mdev->entity_notify, list)
+               notify->notify(entity, notify->notify_data);
+
+       if (mdev->entity_internal_idx_max
+           >= mdev->pm_count_walk.ent_enum.idx_max) {
+               struct media_graph new = { .top = 0 };
+
+               /*
+                * Initialise the new graph walk before cleaning up
+                * the old one in order not to spoil the graph walk
+                * object of the media device if graph walk init fails.
+                */
+               ret = media_graph_walk_init(&new, mdev);
+               if (ret) {
+                       mutex_unlock(&mdev->graph_mutex);
+                       return ret;
+               }
+               media_graph_walk_cleanup(&mdev->pm_count_walk);
+               mdev->pm_count_walk = new;
+       }
+       mutex_unlock(&mdev->graph_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(media_device_register_entity);
+
+static void __media_device_unregister_entity(struct media_entity *entity)
+{
+       struct media_device *mdev = entity->graph_obj.mdev;
+       struct media_link *link, *tmp;
+       struct media_interface *intf;
+       unsigned int i;
+
+       ida_free(&mdev->entity_internal_idx, entity->internal_idx);
+
+       /* Remove all interface links pointing to this entity */
+       list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) {
+               list_for_each_entry_safe(link, tmp, &intf->links, list) {
+                       if (link->entity == entity)
+                               __media_remove_intf_link(link);
+               }
+       }
+
+       /* Remove all data links that belong to this entity */
+       __media_entity_remove_links(entity);
+
+       /* Remove all pads that belong to this entity */
+       for (i = 0; i < entity->num_pads; i++)
+               media_gobj_destroy(&entity->pads[i].graph_obj);
+
+       /* Remove the entity */
+       media_gobj_destroy(&entity->graph_obj);
+
+       /* invoke entity_notify callbacks to handle entity removal?? */
+
+       entity->graph_obj.mdev = NULL;
+}
+
+void media_device_unregister_entity(struct media_entity *entity)
+{
+       struct media_device *mdev = entity->graph_obj.mdev;
+
+       if (mdev == NULL)
+               return;
+
+       mutex_lock(&mdev->graph_mutex);
+       __media_device_unregister_entity(entity);
+       mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_device_unregister_entity);
+
+/**
+ * media_device_init() - initialize a media device
+ * @mdev:      The media device
+ *
+ * The caller is responsible for initializing the media device before
+ * registration. The following fields must be set:
+ *
+ * - dev must point to the parent device
+ * - model must be filled with the device model name
+ */
+void media_device_init(struct media_device *mdev)
+{
+       INIT_LIST_HEAD(&mdev->entities);
+       INIT_LIST_HEAD(&mdev->interfaces);
+       INIT_LIST_HEAD(&mdev->pads);
+       INIT_LIST_HEAD(&mdev->links);
+       INIT_LIST_HEAD(&mdev->entity_notify);
+
+       mutex_init(&mdev->req_queue_mutex);
+       mutex_init(&mdev->graph_mutex);
+       ida_init(&mdev->entity_internal_idx);
+
+       atomic_set(&mdev->request_id, 0);
+
+       dev_dbg(mdev->dev, "Media device initialized\n");
+}
+EXPORT_SYMBOL_GPL(media_device_init);
+
+void media_device_cleanup(struct media_device *mdev)
+{
+       ida_destroy(&mdev->entity_internal_idx);
+       mdev->entity_internal_idx_max = 0;
+       media_graph_walk_cleanup(&mdev->pm_count_walk);
+       mutex_destroy(&mdev->graph_mutex);
+       mutex_destroy(&mdev->req_queue_mutex);
+}
+EXPORT_SYMBOL_GPL(media_device_cleanup);
+
+int __must_check __media_device_register(struct media_device *mdev,
+                                        struct module *owner)
+{
+       struct media_devnode *devnode;
+       int ret;
+
+       devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
+       if (!devnode)
+               return -ENOMEM;
+
+       /* Register the device node. */
+       mdev->devnode = devnode;
+       devnode->fops = &media_device_fops;
+       devnode->parent = mdev->dev;
+       devnode->release = media_device_release;
+
+       /* Set version 0 to indicate user-space that the graph is static */
+       mdev->topology_version = 0;
+
+       ret = media_devnode_register(mdev, devnode, owner);
+       if (ret < 0) {
+               /* devnode free is handled in media_devnode_*() */
+               mdev->devnode = NULL;
+               return ret;
+       }
+
+       ret = device_create_file(&devnode->dev, &dev_attr_model);
+       if (ret < 0) {
+               /* devnode free is handled in media_devnode_*() */
+               mdev->devnode = NULL;
+               media_devnode_unregister_prepare(devnode);
+               media_devnode_unregister(devnode);
+               return ret;
+       }
+
+       dev_dbg(mdev->dev, "Media device registered\n");
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__media_device_register);
+
+int __must_check media_device_register_entity_notify(struct media_device *mdev,
+                                       struct media_entity_notify *nptr)
+{
+       mutex_lock(&mdev->graph_mutex);
+       list_add_tail(&nptr->list, &mdev->entity_notify);
+       mutex_unlock(&mdev->graph_mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(media_device_register_entity_notify);
+
+/*
+ * Note: Should be called with mdev->lock held.
+ */
+static void __media_device_unregister_entity_notify(struct media_device *mdev,
+                                       struct media_entity_notify *nptr)
+{
+       list_del(&nptr->list);
+}
+
+void media_device_unregister_entity_notify(struct media_device *mdev,
+                                       struct media_entity_notify *nptr)
+{
+       mutex_lock(&mdev->graph_mutex);
+       __media_device_unregister_entity_notify(mdev, nptr);
+       mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify);
+
+void media_device_unregister(struct media_device *mdev)
+{
+       struct media_entity *entity;
+       struct media_entity *next;
+       struct media_interface *intf, *tmp_intf;
+       struct media_entity_notify *notify, *nextp;
+
+       if (mdev == NULL)
+               return;
+
+       mutex_lock(&mdev->graph_mutex);
+
+       /* Check if mdev was ever registered at all */
+       if (!media_devnode_is_registered(mdev->devnode)) {
+               mutex_unlock(&mdev->graph_mutex);
+               return;
+       }
+
+       /* Clear the devnode register bit to avoid races with media dev open */
+       media_devnode_unregister_prepare(mdev->devnode);
+
+       /* Remove all entities from the media device */
+       list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list)
+               __media_device_unregister_entity(entity);
+
+       /* Remove all entity_notify callbacks from the media device */
+       list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list)
+               __media_device_unregister_entity_notify(mdev, notify);
+
+       /* Remove all interfaces from the media device */
+       list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces,
+                                graph_obj.list) {
+               /*
+                * Unlink the interface, but don't free it here; the
+                * module which created it is responsible for freeing
+                * it
+                */
+               __media_remove_intf_links(intf);
+               media_gobj_destroy(&intf->graph_obj);
+       }
+
+       mutex_unlock(&mdev->graph_mutex);
+
+       dev_dbg(mdev->dev, "Media device unregistered\n");
+
+       device_remove_file(&mdev->devnode->dev, &dev_attr_model);
+       media_devnode_unregister(mdev->devnode);
+       /* devnode free is handled in media_devnode_*() */
+       mdev->devnode = NULL;
+}
+EXPORT_SYMBOL_GPL(media_device_unregister);
+
+#if IS_ENABLED(CONFIG_PCI)
+void media_device_pci_init(struct media_device *mdev,
+                          struct pci_dev *pci_dev,
+                          const char *name)
+{
+       mdev->dev = &pci_dev->dev;
+
+       if (name)
+               strscpy(mdev->model, name, sizeof(mdev->model));
+       else
+               strscpy(mdev->model, pci_name(pci_dev), sizeof(mdev->model));
+
+       sprintf(mdev->bus_info, "PCI:%s", pci_name(pci_dev));
+
+       mdev->hw_revision = (pci_dev->subsystem_vendor << 16)
+                           | pci_dev->subsystem_device;
+
+       media_device_init(mdev);
+}
+EXPORT_SYMBOL_GPL(media_device_pci_init);
+#endif
+
+#if IS_ENABLED(CONFIG_USB)
+void __media_device_usb_init(struct media_device *mdev,
+                            struct usb_device *udev,
+                            const char *board_name,
+                            const char *driver_name)
+{
+       mdev->dev = &udev->dev;
+
+       if (driver_name)
+               strscpy(mdev->driver_name, driver_name,
+                       sizeof(mdev->driver_name));
+
+       if (board_name)
+               strscpy(mdev->model, board_name, sizeof(mdev->model));
+       else if (udev->product)
+               strscpy(mdev->model, udev->product, sizeof(mdev->model));
+       else
+               strscpy(mdev->model, "unknown model", sizeof(mdev->model));
+       if (udev->serial)
+               strscpy(mdev->serial, udev->serial, sizeof(mdev->serial));
+       usb_make_path(udev, mdev->bus_info, sizeof(mdev->bus_info));
+       mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
+
+       media_device_init(mdev);
+}
+EXPORT_SYMBOL_GPL(__media_device_usb_init);
+#endif
+
+
+#endif /* CONFIG_MEDIA_CONTROLLER */
diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c
new file mode 100644 (file)
index 0000000..d5aa30e
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Media device node
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Based on drivers/media/video/v4l2_dev.c code authored by
+ *     Mauro Carvalho Chehab <mchehab@kernel.org> (version 2)
+ *     Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * --
+ *
+ * Generic media device node infrastructure to register and unregister
+ * character devices using a dynamic major number and proper reference
+ * counting.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+#include <media/media-devnode.h>
+#include <media/media-device.h>
+
+#define MEDIA_NUM_DEVICES      256
+#define MEDIA_NAME             "media"
+
+static dev_t media_dev_t;
+
+/*
+ *     Active devices
+ */
+static DEFINE_MUTEX(media_devnode_lock);
+static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES);
+
+/* Called when the last user of the media device exits. */
+static void media_devnode_release(struct device *cd)
+{
+       struct media_devnode *devnode = to_media_devnode(cd);
+
+       mutex_lock(&media_devnode_lock);
+       /* Mark device node number as free */
+       clear_bit(devnode->minor, media_devnode_nums);
+       mutex_unlock(&media_devnode_lock);
+
+       /* Release media_devnode and perform other cleanups as needed. */
+       if (devnode->release)
+               devnode->release(devnode);
+
+       kfree(devnode);
+       pr_debug("%s: Media Devnode Deallocated\n", __func__);
+}
+
+static struct bus_type media_bus_type = {
+       .name = MEDIA_NAME,
+};
+
+static ssize_t media_read(struct file *filp, char __user *buf,
+               size_t sz, loff_t *off)
+{
+       struct media_devnode *devnode = media_devnode_data(filp);
+
+       if (!devnode->fops->read)
+               return -EINVAL;
+       if (!media_devnode_is_registered(devnode))
+               return -EIO;
+       return devnode->fops->read(filp, buf, sz, off);
+}
+
+static ssize_t media_write(struct file *filp, const char __user *buf,
+               size_t sz, loff_t *off)
+{
+       struct media_devnode *devnode = media_devnode_data(filp);
+
+       if (!devnode->fops->write)
+               return -EINVAL;
+       if (!media_devnode_is_registered(devnode))
+               return -EIO;
+       return devnode->fops->write(filp, buf, sz, off);
+}
+
+static __poll_t media_poll(struct file *filp,
+                              struct poll_table_struct *poll)
+{
+       struct media_devnode *devnode = media_devnode_data(filp);
+
+       if (!media_devnode_is_registered(devnode))
+               return EPOLLERR | EPOLLHUP;
+       if (!devnode->fops->poll)
+               return DEFAULT_POLLMASK;
+       return devnode->fops->poll(filp, poll);
+}
+
+static long
+__media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg,
+             long (*ioctl_func)(struct file *filp, unsigned int cmd,
+                                unsigned long arg))
+{
+       struct media_devnode *devnode = media_devnode_data(filp);
+
+       if (!ioctl_func)
+               return -ENOTTY;
+
+       if (!media_devnode_is_registered(devnode))
+               return -EIO;
+
+       return ioctl_func(filp, cmd, arg);
+}
+
+static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+       struct media_devnode *devnode = media_devnode_data(filp);
+
+       return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl);
+}
+
+#ifdef CONFIG_COMPAT
+
+static long media_compat_ioctl(struct file *filp, unsigned int cmd,
+                              unsigned long arg)
+{
+       struct media_devnode *devnode = media_devnode_data(filp);
+
+       return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl);
+}
+
+#endif /* CONFIG_COMPAT */
+
+/* Override for the open function */
+static int media_open(struct inode *inode, struct file *filp)
+{
+       struct media_devnode *devnode;
+       int ret;
+
+       /* Check if the media device is available. This needs to be done with
+        * the media_devnode_lock held to prevent an open/unregister race:
+        * without the lock, the device could be unregistered and freed between
+        * the media_devnode_is_registered() and get_device() calls, leading to
+        * a crash.
+        */
+       mutex_lock(&media_devnode_lock);
+       devnode = container_of(inode->i_cdev, struct media_devnode, cdev);
+       /* return ENXIO if the media device has been removed
+          already or if it is not registered anymore. */
+       if (!media_devnode_is_registered(devnode)) {
+               mutex_unlock(&media_devnode_lock);
+               return -ENXIO;
+       }
+       /* and increase the device refcount */
+       get_device(&devnode->dev);
+       mutex_unlock(&media_devnode_lock);
+
+       filp->private_data = devnode;
+
+       if (devnode->fops->open) {
+               ret = devnode->fops->open(filp);
+               if (ret) {
+                       put_device(&devnode->dev);
+                       filp->private_data = NULL;
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+/* Override for the release function */
+static int media_release(struct inode *inode, struct file *filp)
+{
+       struct media_devnode *devnode = media_devnode_data(filp);
+
+       if (devnode->fops->release)
+               devnode->fops->release(filp);
+
+       filp->private_data = NULL;
+
+       /* decrease the refcount unconditionally since the release()
+          return value is ignored. */
+       put_device(&devnode->dev);
+
+       pr_debug("%s: Media Release\n", __func__);
+       return 0;
+}
+
+static const struct file_operations media_devnode_fops = {
+       .owner = THIS_MODULE,
+       .read = media_read,
+       .write = media_write,
+       .open = media_open,
+       .unlocked_ioctl = media_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = media_compat_ioctl,
+#endif /* CONFIG_COMPAT */
+       .release = media_release,
+       .poll = media_poll,
+       .llseek = no_llseek,
+};
+
+int __must_check media_devnode_register(struct media_device *mdev,
+                                       struct media_devnode *devnode,
+                                       struct module *owner)
+{
+       int minor;
+       int ret;
+
+       /* Part 1: Find a free minor number */
+       mutex_lock(&media_devnode_lock);
+       minor = find_next_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES, 0);
+       if (minor == MEDIA_NUM_DEVICES) {
+               mutex_unlock(&media_devnode_lock);
+               pr_err("could not get a free minor\n");
+               kfree(devnode);
+               return -ENFILE;
+       }
+
+       set_bit(minor, media_devnode_nums);
+       mutex_unlock(&media_devnode_lock);
+
+       devnode->minor = minor;
+       devnode->media_dev = mdev;
+
+       /* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */
+       devnode->dev.bus = &media_bus_type;
+       devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
+       devnode->dev.release = media_devnode_release;
+       if (devnode->parent)
+               devnode->dev.parent = devnode->parent;
+       dev_set_name(&devnode->dev, "media%d", devnode->minor);
+       device_initialize(&devnode->dev);
+
+       /* Part 2: Initialize the character device */
+       cdev_init(&devnode->cdev, &media_devnode_fops);
+       devnode->cdev.owner = owner;
+       kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor);
+
+       /* Part 3: Add the media and char device */
+       ret = cdev_device_add(&devnode->cdev, &devnode->dev);
+       if (ret < 0) {
+               pr_err("%s: cdev_device_add failed\n", __func__);
+               goto cdev_add_error;
+       }
+
+       /* Part 4: Activate this minor. The char device can now be used. */
+       set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+
+       return 0;
+
+cdev_add_error:
+       mutex_lock(&media_devnode_lock);
+       clear_bit(devnode->minor, media_devnode_nums);
+       devnode->media_dev = NULL;
+       mutex_unlock(&media_devnode_lock);
+
+       put_device(&devnode->dev);
+       return ret;
+}
+
+void media_devnode_unregister_prepare(struct media_devnode *devnode)
+{
+       /* Check if devnode was ever registered at all */
+       if (!media_devnode_is_registered(devnode))
+               return;
+
+       mutex_lock(&media_devnode_lock);
+       clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
+       mutex_unlock(&media_devnode_lock);
+}
+
+void media_devnode_unregister(struct media_devnode *devnode)
+{
+       mutex_lock(&media_devnode_lock);
+       /* Delete the cdev on this minor as well */
+       cdev_device_del(&devnode->cdev, &devnode->dev);
+       devnode->media_dev = NULL;
+       mutex_unlock(&media_devnode_lock);
+
+       put_device(&devnode->dev);
+}
+
+/*
+ *     Initialise media for linux
+ */
+static int __init media_devnode_init(void)
+{
+       int ret;
+
+       pr_info("Linux media interface: v0.10\n");
+       ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES,
+                                 MEDIA_NAME);
+       if (ret < 0) {
+               pr_warn("unable to allocate major\n");
+               return ret;
+       }
+
+       ret = bus_register(&media_bus_type);
+       if (ret < 0) {
+               unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
+               pr_warn("bus_register failed\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void __exit media_devnode_exit(void)
+{
+       bus_unregister(&media_bus_type);
+       unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
+}
+
+subsys_initcall(media_devnode_init);
+module_exit(media_devnode_exit)
+
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_DESCRIPTION("Device node registration for media drivers");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
new file mode 100644 (file)
index 0000000..a998a2e
--- /dev/null
@@ -0,0 +1,1036 @@
+/*
+ * Media entity
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *          Sakari Ailus <sakari.ailus@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitmap.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <media/media-entity.h>
+#include <media/media-device.h>
+
+static inline const char *gobj_type(enum media_gobj_type type)
+{
+       switch (type) {
+       case MEDIA_GRAPH_ENTITY:
+               return "entity";
+       case MEDIA_GRAPH_PAD:
+               return "pad";
+       case MEDIA_GRAPH_LINK:
+               return "link";
+       case MEDIA_GRAPH_INTF_DEVNODE:
+               return "intf-devnode";
+       default:
+               return "unknown";
+       }
+}
+
+static inline const char *intf_type(struct media_interface *intf)
+{
+       switch (intf->type) {
+       case MEDIA_INTF_T_DVB_FE:
+               return "dvb-frontend";
+       case MEDIA_INTF_T_DVB_DEMUX:
+               return "dvb-demux";
+       case MEDIA_INTF_T_DVB_DVR:
+               return "dvb-dvr";
+       case MEDIA_INTF_T_DVB_CA:
+               return  "dvb-ca";
+       case MEDIA_INTF_T_DVB_NET:
+               return "dvb-net";
+       case MEDIA_INTF_T_V4L_VIDEO:
+               return "v4l-video";
+       case MEDIA_INTF_T_V4L_VBI:
+               return "v4l-vbi";
+       case MEDIA_INTF_T_V4L_RADIO:
+               return "v4l-radio";
+       case MEDIA_INTF_T_V4L_SUBDEV:
+               return "v4l-subdev";
+       case MEDIA_INTF_T_V4L_SWRADIO:
+               return "v4l-swradio";
+       case MEDIA_INTF_T_V4L_TOUCH:
+               return "v4l-touch";
+       default:
+               return "unknown-intf";
+       }
+};
+
+__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
+                                         int idx_max)
+{
+       idx_max = ALIGN(idx_max, BITS_PER_LONG);
+       ent_enum->bmap = kcalloc(idx_max / BITS_PER_LONG, sizeof(long),
+                                GFP_KERNEL);
+       if (!ent_enum->bmap)
+               return -ENOMEM;
+
+       bitmap_zero(ent_enum->bmap, idx_max);
+       ent_enum->idx_max = idx_max;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__media_entity_enum_init);
+
+void media_entity_enum_cleanup(struct media_entity_enum *ent_enum)
+{
+       kfree(ent_enum->bmap);
+}
+EXPORT_SYMBOL_GPL(media_entity_enum_cleanup);
+
+/**
+ *  dev_dbg_obj - Prints in debug mode a change on some object
+ *
+ * @event_name:        Name of the event to report. Could be __func__
+ * @gobj:      Pointer to the object
+ *
+ * Enabled only if DEBUG or CONFIG_DYNAMIC_DEBUG. Otherwise, it
+ * won't produce any code.
+ */
+static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
+{
+#if defined(DEBUG) || defined (CONFIG_DYNAMIC_DEBUG)
+       switch (media_type(gobj)) {
+       case MEDIA_GRAPH_ENTITY:
+               dev_dbg(gobj->mdev->dev,
+                       "%s id %u: entity '%s'\n",
+                       event_name, media_id(gobj),
+                       gobj_to_entity(gobj)->name);
+               break;
+       case MEDIA_GRAPH_LINK:
+       {
+               struct media_link *link = gobj_to_link(gobj);
+
+               dev_dbg(gobj->mdev->dev,
+                       "%s id %u: %s link id %u ==> id %u\n",
+                       event_name, media_id(gobj),
+                       media_type(link->gobj0) == MEDIA_GRAPH_PAD ?
+                               "data" : "interface",
+                       media_id(link->gobj0),
+                       media_id(link->gobj1));
+               break;
+       }
+       case MEDIA_GRAPH_PAD:
+       {
+               struct media_pad *pad = gobj_to_pad(gobj);
+
+               dev_dbg(gobj->mdev->dev,
+                       "%s id %u: %s%spad '%s':%d\n",
+                       event_name, media_id(gobj),
+                       pad->flags & MEDIA_PAD_FL_SINK   ? "sink " : "",
+                       pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "",
+                       pad->entity->name, pad->index);
+               break;
+       }
+       case MEDIA_GRAPH_INTF_DEVNODE:
+       {
+               struct media_interface *intf = gobj_to_intf(gobj);
+               struct media_intf_devnode *devnode = intf_to_devnode(intf);
+
+               dev_dbg(gobj->mdev->dev,
+                       "%s id %u: intf_devnode %s - major: %d, minor: %d\n",
+                       event_name, media_id(gobj),
+                       intf_type(intf),
+                       devnode->major, devnode->minor);
+               break;
+       }
+       }
+#endif
+}
+
+void media_gobj_create(struct media_device *mdev,
+                          enum media_gobj_type type,
+                          struct media_gobj *gobj)
+{
+       BUG_ON(!mdev);
+
+       gobj->mdev = mdev;
+
+       /* Create a per-type unique object ID */
+       gobj->id = media_gobj_gen_id(type, ++mdev->id);
+
+       switch (type) {
+       case MEDIA_GRAPH_ENTITY:
+               list_add_tail(&gobj->list, &mdev->entities);
+               break;
+       case MEDIA_GRAPH_PAD:
+               list_add_tail(&gobj->list, &mdev->pads);
+               break;
+       case MEDIA_GRAPH_LINK:
+               list_add_tail(&gobj->list, &mdev->links);
+               break;
+       case MEDIA_GRAPH_INTF_DEVNODE:
+               list_add_tail(&gobj->list, &mdev->interfaces);
+               break;
+       }
+
+       mdev->topology_version++;
+
+       dev_dbg_obj(__func__, gobj);
+}
+
+void media_gobj_destroy(struct media_gobj *gobj)
+{
+       /* Do nothing if the object is not linked. */
+       if (gobj->mdev == NULL)
+               return;
+
+       dev_dbg_obj(__func__, gobj);
+
+       gobj->mdev->topology_version++;
+
+       /* Remove the object from mdev list */
+       list_del(&gobj->list);
+
+       gobj->mdev = NULL;
+}
+
+/*
+ * TODO: Get rid of this.
+ */
+#define MEDIA_ENTITY_MAX_PADS          512
+
+int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
+                          struct media_pad *pads)
+{
+       struct media_device *mdev = entity->graph_obj.mdev;
+       unsigned int i;
+
+       if (num_pads >= MEDIA_ENTITY_MAX_PADS)
+               return -E2BIG;
+
+       entity->num_pads = num_pads;
+       entity->pads = pads;
+
+       if (mdev)
+               mutex_lock(&mdev->graph_mutex);
+
+       for (i = 0; i < num_pads; i++) {
+               pads[i].entity = entity;
+               pads[i].index = i;
+               if (mdev)
+                       media_gobj_create(mdev, MEDIA_GRAPH_PAD,
+                                       &entity->pads[i].graph_obj);
+       }
+
+       if (mdev)
+               mutex_unlock(&mdev->graph_mutex);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(media_entity_pads_init);
+
+/* -----------------------------------------------------------------------------
+ * Graph traversal
+ */
+
+static struct media_entity *
+media_entity_other(struct media_entity *entity, struct media_link *link)
+{
+       if (link->source->entity == entity)
+               return link->sink->entity;
+       else
+               return link->source->entity;
+}
+
+/* push an entity to traversal stack */
+static void stack_push(struct media_graph *graph,
+                      struct media_entity *entity)
+{
+       if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
+               WARN_ON(1);
+               return;
+       }
+       graph->top++;
+       graph->stack[graph->top].link = entity->links.next;
+       graph->stack[graph->top].entity = entity;
+}
+
+static struct media_entity *stack_pop(struct media_graph *graph)
+{
+       struct media_entity *entity;
+
+       entity = graph->stack[graph->top].entity;
+       graph->top--;
+
+       return entity;
+}
+
+#define link_top(en)   ((en)->stack[(en)->top].link)
+#define stack_top(en)  ((en)->stack[(en)->top].entity)
+
+/**
+ * media_graph_walk_init - Allocate resources for graph walk
+ * @graph: Media graph structure that will be used to walk the graph
+ * @mdev: Media device
+ *
+ * Reserve resources for graph walk in media device's current
+ * state. The memory must be released using
+ * media_graph_walk_free().
+ *
+ * Returns error on failure, zero on success.
+ */
+__must_check int media_graph_walk_init(
+       struct media_graph *graph, struct media_device *mdev)
+{
+       return media_entity_enum_init(&graph->ent_enum, mdev);
+}
+EXPORT_SYMBOL_GPL(media_graph_walk_init);
+
+/**
+ * media_graph_walk_cleanup - Release resources related to graph walking
+ * @graph: Media graph structure that was used to walk the graph
+ */
+void media_graph_walk_cleanup(struct media_graph *graph)
+{
+       media_entity_enum_cleanup(&graph->ent_enum);
+}
+EXPORT_SYMBOL_GPL(media_graph_walk_cleanup);
+
+void media_graph_walk_start(struct media_graph *graph,
+                           struct media_entity *entity)
+{
+       media_entity_enum_zero(&graph->ent_enum);
+       media_entity_enum_set(&graph->ent_enum, entity);
+
+       graph->top = 0;
+       graph->stack[graph->top].entity = NULL;
+       stack_push(graph, entity);
+       dev_dbg(entity->graph_obj.mdev->dev,
+               "begin graph walk at '%s'\n", entity->name);
+}
+EXPORT_SYMBOL_GPL(media_graph_walk_start);
+
+static void media_graph_walk_iter(struct media_graph *graph)
+{
+       struct media_entity *entity = stack_top(graph);
+       struct media_link *link;
+       struct media_entity *next;
+
+       link = list_entry(link_top(graph), typeof(*link), list);
+
+       /* The link is not enabled so we do not follow. */
+       if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
+               link_top(graph) = link_top(graph)->next;
+               dev_dbg(entity->graph_obj.mdev->dev,
+                       "walk: skipping disabled link '%s':%u -> '%s':%u\n",
+                       link->source->entity->name, link->source->index,
+                       link->sink->entity->name, link->sink->index);
+               return;
+       }
+
+       /* Get the entity in the other end of the link . */
+       next = media_entity_other(entity, link);
+
+       /* Has the entity already been visited? */
+       if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
+               link_top(graph) = link_top(graph)->next;
+               dev_dbg(entity->graph_obj.mdev->dev,
+                       "walk: skipping entity '%s' (already seen)\n",
+                       next->name);
+               return;
+       }
+
+       /* Push the new entity to stack and start over. */
+       link_top(graph) = link_top(graph)->next;
+       stack_push(graph, next);
+       dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n",
+               next->name);
+}
+
+struct media_entity *media_graph_walk_next(struct media_graph *graph)
+{
+       struct media_entity *entity;
+
+       if (stack_top(graph) == NULL)
+               return NULL;
+
+       /*
+        * Depth first search. Push entity to stack and continue from
+        * top of the stack until no more entities on the level can be
+        * found.
+        */
+       while (link_top(graph) != &stack_top(graph)->links)
+               media_graph_walk_iter(graph);
+
+       entity = stack_pop(graph);
+       dev_dbg(entity->graph_obj.mdev->dev,
+               "walk: returning entity '%s'\n", entity->name);
+
+       return entity;
+}
+EXPORT_SYMBOL_GPL(media_graph_walk_next);
+
+int media_entity_get_fwnode_pad(struct media_entity *entity,
+                               struct fwnode_handle *fwnode,
+                               unsigned long direction_flags)
+{
+       struct fwnode_endpoint endpoint;
+       unsigned int i;
+       int ret;
+
+       if (!entity->ops || !entity->ops->get_fwnode_pad) {
+               for (i = 0; i < entity->num_pads; i++) {
+                       if (entity->pads[i].flags & direction_flags)
+                               return i;
+               }
+
+               return -ENXIO;
+       }
+
+       ret = fwnode_graph_parse_endpoint(fwnode, &endpoint);
+       if (ret)
+               return ret;
+
+       ret = entity->ops->get_fwnode_pad(&endpoint);
+       if (ret < 0)
+               return ret;
+
+       if (ret >= entity->num_pads)
+               return -ENXIO;
+
+       if (!(entity->pads[ret].flags & direction_flags))
+               return -ENXIO;
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad);
+
+/* -----------------------------------------------------------------------------
+ * Pipeline management
+ */
+
+__must_check int __media_pipeline_start(struct media_entity *entity,
+                                       struct media_pipeline *pipe)
+{
+       struct media_device *mdev = entity->graph_obj.mdev;
+       struct media_graph *graph = &pipe->graph;
+       struct media_entity *entity_err = entity;
+       struct media_link *link;
+       int ret;
+
+       if (!pipe->streaming_count++) {
+               ret = media_graph_walk_init(&pipe->graph, mdev);
+               if (ret)
+                       goto error_graph_walk_start;
+       }
+
+       media_graph_walk_start(&pipe->graph, entity);
+
+       while ((entity = media_graph_walk_next(graph))) {
+               DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
+               DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
+
+               entity->stream_count++;
+
+               if (entity->pipe && entity->pipe != pipe) {
+                       pr_err("Pipe active for %s. Can't start for %s\n",
+                               entity->name,
+                               entity_err->name);
+                       ret = -EBUSY;
+                       goto error;
+               }
+
+               entity->pipe = pipe;
+
+               /* Already streaming --- no need to check. */
+               if (entity->stream_count > 1)
+                       continue;
+
+               if (!entity->ops || !entity->ops->link_validate)
+                       continue;
+
+               bitmap_zero(active, entity->num_pads);
+               bitmap_fill(has_no_links, entity->num_pads);
+
+               list_for_each_entry(link, &entity->links, list) {
+                       struct media_pad *pad = link->sink->entity == entity
+                                               ? link->sink : link->source;
+
+                       /* Mark that a pad is connected by a link. */
+                       bitmap_clear(has_no_links, pad->index, 1);
+
+                       /*
+                        * Pads that either do not need to connect or
+                        * are connected through an enabled link are
+                        * fine.
+                        */
+                       if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) ||
+                           link->flags & MEDIA_LNK_FL_ENABLED)
+                               bitmap_set(active, pad->index, 1);
+
+                       /*
+                        * Link validation will only take place for
+                        * sink ends of the link that are enabled.
+                        */
+                       if (link->sink != pad ||
+                           !(link->flags & MEDIA_LNK_FL_ENABLED))
+                               continue;
+
+                       ret = entity->ops->link_validate(link);
+                       if (ret < 0 && ret != -ENOIOCTLCMD) {
+                               dev_dbg(entity->graph_obj.mdev->dev,
+                                       "link validation failed for '%s':%u -> '%s':%u, error %d\n",
+                                       link->source->entity->name,
+                                       link->source->index,
+                                       entity->name, link->sink->index, ret);
+                               goto error;
+                       }
+               }
+
+               /* Either no links or validated links are fine. */
+               bitmap_or(active, active, has_no_links, entity->num_pads);
+
+               if (!bitmap_full(active, entity->num_pads)) {
+                       ret = -ENOLINK;
+                       dev_dbg(entity->graph_obj.mdev->dev,
+                               "'%s':%u must be connected by an enabled link\n",
+                               entity->name,
+                               (unsigned)find_first_zero_bit(
+                                       active, entity->num_pads));
+                       goto error;
+               }
+       }
+
+       return 0;
+
+error:
+       /*
+        * Link validation on graph failed. We revert what we did and
+        * return the error.
+        */
+       media_graph_walk_start(graph, entity_err);
+
+       while ((entity_err = media_graph_walk_next(graph))) {
+               /* Sanity check for negative stream_count */
+               if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) {
+                       entity_err->stream_count--;
+                       if (entity_err->stream_count == 0)
+                               entity_err->pipe = NULL;
+               }
+
+               /*
+                * We haven't increased stream_count further than this
+                * so we quit here.
+                */
+               if (entity_err == entity)
+                       break;
+       }
+
+error_graph_walk_start:
+       if (!--pipe->streaming_count)
+               media_graph_walk_cleanup(graph);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(__media_pipeline_start);
+
+__must_check int media_pipeline_start(struct media_entity *entity,
+                                     struct media_pipeline *pipe)
+{
+       struct media_device *mdev = entity->graph_obj.mdev;
+       int ret;
+
+       mutex_lock(&mdev->graph_mutex);
+       ret = __media_pipeline_start(entity, pipe);
+       mutex_unlock(&mdev->graph_mutex);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(media_pipeline_start);
+
+void __media_pipeline_stop(struct media_entity *entity)
+{
+       struct media_graph *graph = &entity->pipe->graph;
+       struct media_pipeline *pipe = entity->pipe;
+
+       /*
+        * If the following check fails, the driver has performed an
+        * unbalanced call to media_pipeline_stop()
+        */
+       if (WARN_ON(!pipe))
+               return;
+
+       media_graph_walk_start(graph, entity);
+
+       while ((entity = media_graph_walk_next(graph))) {
+               /* Sanity check for negative stream_count */
+               if (!WARN_ON_ONCE(entity->stream_count <= 0)) {
+                       entity->stream_count--;
+                       if (entity->stream_count == 0)
+                               entity->pipe = NULL;
+               }
+       }
+
+       if (!--pipe->streaming_count)
+               media_graph_walk_cleanup(graph);
+
+}
+EXPORT_SYMBOL_GPL(__media_pipeline_stop);
+
+void media_pipeline_stop(struct media_entity *entity)
+{
+       struct media_device *mdev = entity->graph_obj.mdev;
+
+       mutex_lock(&mdev->graph_mutex);
+       __media_pipeline_stop(entity);
+       mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_pipeline_stop);
+
+/* -----------------------------------------------------------------------------
+ * Links management
+ */
+
+static struct media_link *media_add_link(struct list_head *head)
+{
+       struct media_link *link;
+
+       link = kzalloc(sizeof(*link), GFP_KERNEL);
+       if (link == NULL)
+               return NULL;
+
+       list_add_tail(&link->list, head);
+
+       return link;
+}
+
+static void __media_entity_remove_link(struct media_entity *entity,
+                                      struct media_link *link)
+{
+       struct media_link *rlink, *tmp;
+       struct media_entity *remote;
+
+       if (link->source->entity == entity)
+               remote = link->sink->entity;
+       else
+               remote = link->source->entity;
+
+       list_for_each_entry_safe(rlink, tmp, &remote->links, list) {
+               if (rlink != link->reverse)
+                       continue;
+
+               if (link->source->entity == entity)
+                       remote->num_backlinks--;
+
+               /* Remove the remote link */
+               list_del(&rlink->list);
+               media_gobj_destroy(&rlink->graph_obj);
+               kfree(rlink);
+
+               if (--remote->num_links == 0)
+                       break;
+       }
+       list_del(&link->list);
+       media_gobj_destroy(&link->graph_obj);
+       kfree(link);
+}
+
+int media_get_pad_index(struct media_entity *entity, bool is_sink,
+                       enum media_pad_signal_type sig_type)
+{
+       int i;
+       bool pad_is_sink;
+
+       if (!entity)
+               return -EINVAL;
+
+       for (i = 0; i < entity->num_pads; i++) {
+               if (entity->pads[i].flags == MEDIA_PAD_FL_SINK)
+                       pad_is_sink = true;
+               else if (entity->pads[i].flags == MEDIA_PAD_FL_SOURCE)
+                       pad_is_sink = false;
+               else
+                       continue;       /* This is an error! */
+
+               if (pad_is_sink != is_sink)
+                       continue;
+               if (entity->pads[i].sig_type == sig_type)
+                       return i;
+       }
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(media_get_pad_index);
+
+int
+media_create_pad_link(struct media_entity *source, u16 source_pad,
+                        struct media_entity *sink, u16 sink_pad, u32 flags)
+{
+       struct media_link *link;
+       struct media_link *backlink;
+
+       BUG_ON(source == NULL || sink == NULL);
+       BUG_ON(source_pad >= source->num_pads);
+       BUG_ON(sink_pad >= sink->num_pads);
+
+       link = media_add_link(&source->links);
+       if (link == NULL)
+               return -ENOMEM;
+
+       link->source = &source->pads[source_pad];
+       link->sink = &sink->pads[sink_pad];
+       link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK;
+
+       /* Initialize graph object embedded at the new link */
+       media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
+                       &link->graph_obj);
+
+       /* Create the backlink. Backlinks are used to help graph traversal and
+        * are not reported to userspace.
+        */
+       backlink = media_add_link(&sink->links);
+       if (backlink == NULL) {
+               __media_entity_remove_link(source, link);
+               return -ENOMEM;
+       }
+
+       backlink->source = &source->pads[source_pad];
+       backlink->sink = &sink->pads[sink_pad];
+       backlink->flags = flags;
+       backlink->is_backlink = true;
+
+       /* Initialize graph object embedded at the new link */
+       media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK,
+                       &backlink->graph_obj);
+
+       link->reverse = backlink;
+       backlink->reverse = link;
+
+       sink->num_backlinks++;
+       sink->num_links++;
+       source->num_links++;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(media_create_pad_link);
+
+int media_create_pad_links(const struct media_device *mdev,
+                          const u32 source_function,
+                          struct media_entity *source,
+                          const u16 source_pad,
+                          const u32 sink_function,
+                          struct media_entity *sink,
+                          const u16 sink_pad,
+                          u32 flags,
+                          const bool allow_both_undefined)
+{
+       struct media_entity *entity;
+       unsigned function;
+       int ret;
+
+       /* Trivial case: 1:1 relation */
+       if (source && sink)
+               return media_create_pad_link(source, source_pad,
+                                            sink, sink_pad, flags);
+
+       /* Worse case scenario: n:n relation */
+       if (!source && !sink) {
+               if (!allow_both_undefined)
+                       return 0;
+               media_device_for_each_entity(source, mdev) {
+                       if (source->function != source_function)
+                               continue;
+                       media_device_for_each_entity(sink, mdev) {
+                               if (sink->function != sink_function)
+                                       continue;
+                               ret = media_create_pad_link(source, source_pad,
+                                                           sink, sink_pad,
+                                                           flags);
+                               if (ret)
+                                       return ret;
+                               flags &= ~(MEDIA_LNK_FL_ENABLED |
+                                          MEDIA_LNK_FL_IMMUTABLE);
+                       }
+               }
+               return 0;
+       }
+
+       /* Handle 1:n and n:1 cases */
+       if (source)
+               function = sink_function;
+       else
+               function = source_function;
+
+       media_device_for_each_entity(entity, mdev) {
+               if (entity->function != function)
+                       continue;
+
+               if (source)
+                       ret = media_create_pad_link(source, source_pad,
+                                                   entity, sink_pad, flags);
+               else
+                       ret = media_create_pad_link(entity, source_pad,
+                                                   sink, sink_pad, flags);
+               if (ret)
+                       return ret;
+               flags &= ~(MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(media_create_pad_links);
+
+void __media_entity_remove_links(struct media_entity *entity)
+{
+       struct media_link *link, *tmp;
+
+       list_for_each_entry_safe(link, tmp, &entity->links, list)
+               __media_entity_remove_link(entity, link);
+
+       entity->num_links = 0;
+       entity->num_backlinks = 0;
+}
+EXPORT_SYMBOL_GPL(__media_entity_remove_links);
+
+void media_entity_remove_links(struct media_entity *entity)
+{
+       struct media_device *mdev = entity->graph_obj.mdev;
+
+       /* Do nothing if the entity is not registered. */
+       if (mdev == NULL)
+               return;
+
+       mutex_lock(&mdev->graph_mutex);
+       __media_entity_remove_links(entity);
+       mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_entity_remove_links);
+
+static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
+{
+       int ret;
+
+       /* Notify both entities. */
+       ret = media_entity_call(link->source->entity, link_setup,
+                               link->source, link->sink, flags);
+       if (ret < 0 && ret != -ENOIOCTLCMD)
+               return ret;
+
+       ret = media_entity_call(link->sink->entity, link_setup,
+                               link->sink, link->source, flags);
+       if (ret < 0 && ret != -ENOIOCTLCMD) {
+               media_entity_call(link->source->entity, link_setup,
+                                 link->source, link->sink, link->flags);
+               return ret;
+       }
+
+       link->flags = flags;
+       link->reverse->flags = link->flags;
+
+       return 0;
+}
+
+int __media_entity_setup_link(struct media_link *link, u32 flags)
+{
+       const u32 mask = MEDIA_LNK_FL_ENABLED;
+       struct media_device *mdev;
+       struct media_entity *source, *sink;
+       int ret = -EBUSY;
+
+       if (link == NULL)
+               return -EINVAL;
+
+       /* The non-modifiable link flags must not be modified. */
+       if ((link->flags & ~mask) != (flags & ~mask))
+               return -EINVAL;
+
+       if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
+               return link->flags == flags ? 0 : -EINVAL;
+
+       if (link->flags == flags)
+               return 0;
+
+       source = link->source->entity;
+       sink = link->sink->entity;
+
+       if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
+           (source->stream_count || sink->stream_count))
+               return -EBUSY;
+
+       mdev = source->graph_obj.mdev;
+
+       if (mdev->ops && mdev->ops->link_notify) {
+               ret = mdev->ops->link_notify(link, flags,
+                                            MEDIA_DEV_NOTIFY_PRE_LINK_CH);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ret = __media_entity_setup_link_notify(link, flags);
+
+       if (mdev->ops && mdev->ops->link_notify)
+               mdev->ops->link_notify(link, flags,
+                                      MEDIA_DEV_NOTIFY_POST_LINK_CH);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(__media_entity_setup_link);
+
+int media_entity_setup_link(struct media_link *link, u32 flags)
+{
+       int ret;
+
+       mutex_lock(&link->graph_obj.mdev->graph_mutex);
+       ret = __media_entity_setup_link(link, flags);
+       mutex_unlock(&link->graph_obj.mdev->graph_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(media_entity_setup_link);
+
+struct media_link *
+media_entity_find_link(struct media_pad *source, struct media_pad *sink)
+{
+       struct media_link *link;
+
+       list_for_each_entry(link, &source->entity->links, list) {
+               if (link->source->entity == source->entity &&
+                   link->source->index == source->index &&
+                   link->sink->entity == sink->entity &&
+                   link->sink->index == sink->index)
+                       return link;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(media_entity_find_link);
+
+struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
+{
+       struct media_link *link;
+
+       list_for_each_entry(link, &pad->entity->links, list) {
+               if (!(link->flags & MEDIA_LNK_FL_ENABLED))
+                       continue;
+
+               if (link->source == pad)
+                       return link->sink;
+
+               if (link->sink == pad)
+                       return link->source;
+       }
+
+       return NULL;
+
+}
+EXPORT_SYMBOL_GPL(media_entity_remote_pad);
+
+static void media_interface_init(struct media_device *mdev,
+                                struct media_interface *intf,
+                                u32 gobj_type,
+                                u32 intf_type, u32 flags)
+{
+       intf->type = intf_type;
+       intf->flags = flags;
+       INIT_LIST_HEAD(&intf->links);
+
+       media_gobj_create(mdev, gobj_type, &intf->graph_obj);
+}
+
+/* Functions related to the media interface via device nodes */
+
+struct media_intf_devnode *media_devnode_create(struct media_device *mdev,
+                                               u32 type, u32 flags,
+                                               u32 major, u32 minor)
+{
+       struct media_intf_devnode *devnode;
+
+       devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
+       if (!devnode)
+               return NULL;
+
+       devnode->major = major;
+       devnode->minor = minor;
+
+       media_interface_init(mdev, &devnode->intf, MEDIA_GRAPH_INTF_DEVNODE,
+                            type, flags);
+
+       return devnode;
+}
+EXPORT_SYMBOL_GPL(media_devnode_create);
+
+void media_devnode_remove(struct media_intf_devnode *devnode)
+{
+       media_remove_intf_links(&devnode->intf);
+       media_gobj_destroy(&devnode->intf.graph_obj);
+       kfree(devnode);
+}
+EXPORT_SYMBOL_GPL(media_devnode_remove);
+
+struct media_link *media_create_intf_link(struct media_entity *entity,
+                                           struct media_interface *intf,
+                                           u32 flags)
+{
+       struct media_link *link;
+
+       link = media_add_link(&intf->links);
+       if (link == NULL)
+               return NULL;
+
+       link->intf = intf;
+       link->entity = entity;
+       link->flags = flags | MEDIA_LNK_FL_INTERFACE_LINK;
+
+       /* Initialize graph object embedded at the new link */
+       media_gobj_create(intf->graph_obj.mdev, MEDIA_GRAPH_LINK,
+                       &link->graph_obj);
+
+       return link;
+}
+EXPORT_SYMBOL_GPL(media_create_intf_link);
+
+void __media_remove_intf_link(struct media_link *link)
+{
+       list_del(&link->list);
+       media_gobj_destroy(&link->graph_obj);
+       kfree(link);
+}
+EXPORT_SYMBOL_GPL(__media_remove_intf_link);
+
+void media_remove_intf_link(struct media_link *link)
+{
+       struct media_device *mdev = link->graph_obj.mdev;
+
+       /* Do nothing if the intf is not registered. */
+       if (mdev == NULL)
+               return;
+
+       mutex_lock(&mdev->graph_mutex);
+       __media_remove_intf_link(link);
+       mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_remove_intf_link);
+
+void __media_remove_intf_links(struct media_interface *intf)
+{
+       struct media_link *link, *tmp;
+
+       list_for_each_entry_safe(link, tmp, &intf->links, list)
+               __media_remove_intf_link(link);
+
+}
+EXPORT_SYMBOL_GPL(__media_remove_intf_links);
+
+void media_remove_intf_links(struct media_interface *intf)
+{
+       struct media_device *mdev = intf->graph_obj.mdev;
+
+       /* Do nothing if the intf is not registered. */
+       if (mdev == NULL)
+               return;
+
+       mutex_lock(&mdev->graph_mutex);
+       __media_remove_intf_links(intf);
+       mutex_unlock(&mdev->graph_mutex);
+}
+EXPORT_SYMBOL_GPL(media_remove_intf_links);
diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c
new file mode 100644 (file)
index 0000000..e3fca43
--- /dev/null
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Media device request objects
+ *
+ * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ * Copyright (C) 2018 Intel Corporation
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * Author: Hans Verkuil <hans.verkuil@cisco.com>
+ * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
+ */
+
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
+#include <linux/refcount.h>
+
+#include <media/media-device.h>
+#include <media/media-request.h>
+
+static const char * const request_state[] = {
+       [MEDIA_REQUEST_STATE_IDLE]       = "idle",
+       [MEDIA_REQUEST_STATE_VALIDATING] = "validating",
+       [MEDIA_REQUEST_STATE_QUEUED]     = "queued",
+       [MEDIA_REQUEST_STATE_COMPLETE]   = "complete",
+       [MEDIA_REQUEST_STATE_CLEANING]   = "cleaning",
+       [MEDIA_REQUEST_STATE_UPDATING]   = "updating",
+};
+
+static const char *
+media_request_state_str(enum media_request_state state)
+{
+       BUILD_BUG_ON(ARRAY_SIZE(request_state) != NR_OF_MEDIA_REQUEST_STATE);
+
+       if (WARN_ON(state >= ARRAY_SIZE(request_state)))
+               return "invalid";
+       return request_state[state];
+}
+
+static void media_request_clean(struct media_request *req)
+{
+       struct media_request_object *obj, *obj_safe;
+
+       /* Just a sanity check. No other code path is allowed to change this. */
+       WARN_ON(req->state != MEDIA_REQUEST_STATE_CLEANING);
+       WARN_ON(req->updating_count);
+       WARN_ON(req->access_count);
+
+       list_for_each_entry_safe(obj, obj_safe, &req->objects, list) {
+               media_request_object_unbind(obj);
+               media_request_object_put(obj);
+       }
+
+       req->updating_count = 0;
+       req->access_count = 0;
+       WARN_ON(req->num_incomplete_objects);
+       req->num_incomplete_objects = 0;
+       wake_up_interruptible_all(&req->poll_wait);
+}
+
+static void media_request_release(struct kref *kref)
+{
+       struct media_request *req =
+               container_of(kref, struct media_request, kref);
+       struct media_device *mdev = req->mdev;
+
+       dev_dbg(mdev->dev, "request: release %s\n", req->debug_str);
+
+       /* No other users, no need for a spinlock */
+       req->state = MEDIA_REQUEST_STATE_CLEANING;
+
+       media_request_clean(req);
+
+       if (mdev->ops->req_free)
+               mdev->ops->req_free(req);
+       else
+               kfree(req);
+}
+
+void media_request_put(struct media_request *req)
+{
+       kref_put(&req->kref, media_request_release);
+}
+EXPORT_SYMBOL_GPL(media_request_put);
+
+static int media_request_close(struct inode *inode, struct file *filp)
+{
+       struct media_request *req = filp->private_data;
+
+       media_request_put(req);
+       return 0;
+}
+
+static __poll_t media_request_poll(struct file *filp,
+                                  struct poll_table_struct *wait)
+{
+       struct media_request *req = filp->private_data;
+       unsigned long flags;
+       __poll_t ret = 0;
+
+       if (!(poll_requested_events(wait) & EPOLLPRI))
+               return 0;
+
+       poll_wait(filp, &req->poll_wait, wait);
+       spin_lock_irqsave(&req->lock, flags);
+       if (req->state == MEDIA_REQUEST_STATE_COMPLETE) {
+               ret = EPOLLPRI;
+               goto unlock;
+       }
+       if (req->state != MEDIA_REQUEST_STATE_QUEUED) {
+               ret = EPOLLERR;
+               goto unlock;
+       }
+
+unlock:
+       spin_unlock_irqrestore(&req->lock, flags);
+       return ret;
+}
+
+static long media_request_ioctl_queue(struct media_request *req)
+{
+       struct media_device *mdev = req->mdev;
+       enum media_request_state state;
+       unsigned long flags;
+       int ret;
+
+       dev_dbg(mdev->dev, "request: queue %s\n", req->debug_str);
+
+       /*
+        * Ensure the request that is validated will be the one that gets queued
+        * next by serialising the queueing process. This mutex is also used
+        * to serialize with canceling a vb2 queue and with setting values such
+        * as controls in a request.
+        */
+       mutex_lock(&mdev->req_queue_mutex);
+
+       media_request_get(req);
+
+       spin_lock_irqsave(&req->lock, flags);
+       if (req->state == MEDIA_REQUEST_STATE_IDLE)
+               req->state = MEDIA_REQUEST_STATE_VALIDATING;
+       state = req->state;
+       spin_unlock_irqrestore(&req->lock, flags);
+       if (state != MEDIA_REQUEST_STATE_VALIDATING) {
+               dev_dbg(mdev->dev,
+                       "request: unable to queue %s, request in state %s\n",
+                       req->debug_str, media_request_state_str(state));
+               media_request_put(req);
+               mutex_unlock(&mdev->req_queue_mutex);
+               return -EBUSY;
+       }
+
+       ret = mdev->ops->req_validate(req);
+
+       /*
+        * If the req_validate was successful, then we mark the state as QUEUED
+        * and call req_queue. The reason we set the state first is that this
+        * allows req_queue to unbind or complete the queued objects in case
+        * they are immediately 'consumed'. State changes from QUEUED to another
+        * state can only happen if either the driver changes the state or if
+        * the user cancels the vb2 queue. The driver can only change the state
+        * after each object is queued through the req_queue op (and note that
+        * that op cannot fail), so setting the state to QUEUED up front is
+        * safe.
+        *
+        * The other reason for changing the state is if the vb2 queue is
+        * canceled, and that uses the req_queue_mutex which is still locked
+        * while req_queue is called, so that's safe as well.
+        */
+       spin_lock_irqsave(&req->lock, flags);
+       req->state = ret ? MEDIA_REQUEST_STATE_IDLE
+                        : MEDIA_REQUEST_STATE_QUEUED;
+       spin_unlock_irqrestore(&req->lock, flags);
+
+       if (!ret)
+               mdev->ops->req_queue(req);
+
+       mutex_unlock(&mdev->req_queue_mutex);
+
+       if (ret) {
+               dev_dbg(mdev->dev, "request: can't queue %s (%d)\n",
+                       req->debug_str, ret);
+               media_request_put(req);
+       }
+
+       return ret;
+}
+
+static long media_request_ioctl_reinit(struct media_request *req)
+{
+       struct media_device *mdev = req->mdev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&req->lock, flags);
+       if (req->state != MEDIA_REQUEST_STATE_IDLE &&
+           req->state != MEDIA_REQUEST_STATE_COMPLETE) {
+               dev_dbg(mdev->dev,
+                       "request: %s not in idle or complete state, cannot reinit\n",
+                       req->debug_str);
+               spin_unlock_irqrestore(&req->lock, flags);
+               return -EBUSY;
+       }
+       if (req->access_count) {
+               dev_dbg(mdev->dev,
+                       "request: %s is being accessed, cannot reinit\n",
+                       req->debug_str);
+               spin_unlock_irqrestore(&req->lock, flags);
+               return -EBUSY;
+       }
+       req->state = MEDIA_REQUEST_STATE_CLEANING;
+       spin_unlock_irqrestore(&req->lock, flags);
+
+       media_request_clean(req);
+
+       spin_lock_irqsave(&req->lock, flags);
+       req->state = MEDIA_REQUEST_STATE_IDLE;
+       spin_unlock_irqrestore(&req->lock, flags);
+
+       return 0;
+}
+
+static long media_request_ioctl(struct file *filp, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct media_request *req = filp->private_data;
+
+       switch (cmd) {
+       case MEDIA_REQUEST_IOC_QUEUE:
+               return media_request_ioctl_queue(req);
+       case MEDIA_REQUEST_IOC_REINIT:
+               return media_request_ioctl_reinit(req);
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+static const struct file_operations request_fops = {
+       .owner = THIS_MODULE,
+       .poll = media_request_poll,
+       .unlocked_ioctl = media_request_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = media_request_ioctl,
+#endif /* CONFIG_COMPAT */
+       .release = media_request_close,
+};
+
+struct media_request *
+media_request_get_by_fd(struct media_device *mdev, int request_fd)
+{
+       struct fd f;
+       struct media_request *req;
+
+       if (!mdev || !mdev->ops ||
+           !mdev->ops->req_validate || !mdev->ops->req_queue)
+               return ERR_PTR(-EBADR);
+
+       f = fdget(request_fd);
+       if (!f.file)
+               goto err_no_req_fd;
+
+       if (f.file->f_op != &request_fops)
+               goto err_fput;
+       req = f.file->private_data;
+       if (req->mdev != mdev)
+               goto err_fput;
+
+       /*
+        * Note: as long as someone has an open filehandle of the request,
+        * the request can never be released. The fdget() above ensures that
+        * even if userspace closes the request filehandle, the release()
+        * fop won't be called, so the media_request_get() always succeeds
+        * and there is no race condition where the request was released
+        * before media_request_get() is called.
+        */
+       media_request_get(req);
+       fdput(f);
+
+       return req;
+
+err_fput:
+       fdput(f);
+
+err_no_req_fd:
+       dev_dbg(mdev->dev, "cannot find request_fd %d\n", request_fd);
+       return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL_GPL(media_request_get_by_fd);
+
+int media_request_alloc(struct media_device *mdev, int *alloc_fd)
+{
+       struct media_request *req;
+       struct file *filp;
+       int fd;
+       int ret;
+
+       /* Either both are NULL or both are non-NULL */
+       if (WARN_ON(!mdev->ops->req_alloc ^ !mdev->ops->req_free))
+               return -ENOMEM;
+
+       fd = get_unused_fd_flags(O_CLOEXEC);
+       if (fd < 0)
+               return fd;
+
+       filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC);
+       if (IS_ERR(filp)) {
+               ret = PTR_ERR(filp);
+               goto err_put_fd;
+       }
+
+       if (mdev->ops->req_alloc)
+               req = mdev->ops->req_alloc(mdev);
+       else
+               req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (!req) {
+               ret = -ENOMEM;
+               goto err_fput;
+       }
+
+       filp->private_data = req;
+       req->mdev = mdev;
+       req->state = MEDIA_REQUEST_STATE_IDLE;
+       req->num_incomplete_objects = 0;
+       kref_init(&req->kref);
+       INIT_LIST_HEAD(&req->objects);
+       spin_lock_init(&req->lock);
+       init_waitqueue_head(&req->poll_wait);
+       req->updating_count = 0;
+       req->access_count = 0;
+
+       *alloc_fd = fd;
+
+       snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d",
+                atomic_inc_return(&mdev->request_id), fd);
+       dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str);
+
+       fd_install(fd, filp);
+
+       return 0;
+
+err_fput:
+       fput(filp);
+
+err_put_fd:
+       put_unused_fd(fd);
+
+       return ret;
+}
+
+static void media_request_object_release(struct kref *kref)
+{
+       struct media_request_object *obj =
+               container_of(kref, struct media_request_object, kref);
+       struct media_request *req = obj->req;
+
+       if (WARN_ON(req))
+               media_request_object_unbind(obj);
+       obj->ops->release(obj);
+}
+
+struct media_request_object *
+media_request_object_find(struct media_request *req,
+                         const struct media_request_object_ops *ops,
+                         void *priv)
+{
+       struct media_request_object *obj;
+       struct media_request_object *found = NULL;
+       unsigned long flags;
+
+       if (WARN_ON(!ops || !priv))
+               return NULL;
+
+       spin_lock_irqsave(&req->lock, flags);
+       list_for_each_entry(obj, &req->objects, list) {
+               if (obj->ops == ops && obj->priv == priv) {
+                       media_request_object_get(obj);
+                       found = obj;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&req->lock, flags);
+       return found;
+}
+EXPORT_SYMBOL_GPL(media_request_object_find);
+
+void media_request_object_put(struct media_request_object *obj)
+{
+       kref_put(&obj->kref, media_request_object_release);
+}
+EXPORT_SYMBOL_GPL(media_request_object_put);
+
+void media_request_object_init(struct media_request_object *obj)
+{
+       obj->ops = NULL;
+       obj->req = NULL;
+       obj->priv = NULL;
+       obj->completed = false;
+       INIT_LIST_HEAD(&obj->list);
+       kref_init(&obj->kref);
+}
+EXPORT_SYMBOL_GPL(media_request_object_init);
+
+int media_request_object_bind(struct media_request *req,
+                             const struct media_request_object_ops *ops,
+                             void *priv, bool is_buffer,
+                             struct media_request_object *obj)
+{
+       unsigned long flags;
+       int ret = -EBUSY;
+
+       if (WARN_ON(!ops->release))
+               return -EBADR;
+
+       spin_lock_irqsave(&req->lock, flags);
+
+       if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
+               goto unlock;
+
+       obj->req = req;
+       obj->ops = ops;
+       obj->priv = priv;
+
+       if (is_buffer)
+               list_add_tail(&obj->list, &req->objects);
+       else
+               list_add(&obj->list, &req->objects);
+       req->num_incomplete_objects++;
+       ret = 0;
+
+unlock:
+       spin_unlock_irqrestore(&req->lock, flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(media_request_object_bind);
+
+void media_request_object_unbind(struct media_request_object *obj)
+{
+       struct media_request *req = obj->req;
+       unsigned long flags;
+       bool completed = false;
+
+       if (WARN_ON(!req))
+               return;
+
+       spin_lock_irqsave(&req->lock, flags);
+       list_del(&obj->list);
+       obj->req = NULL;
+
+       if (req->state == MEDIA_REQUEST_STATE_COMPLETE)
+               goto unlock;
+
+       if (WARN_ON(req->state == MEDIA_REQUEST_STATE_VALIDATING))
+               goto unlock;
+
+       if (req->state == MEDIA_REQUEST_STATE_CLEANING) {
+               if (!obj->completed)
+                       req->num_incomplete_objects--;
+               goto unlock;
+       }
+
+       if (WARN_ON(!req->num_incomplete_objects))
+               goto unlock;
+
+       req->num_incomplete_objects--;
+       if (req->state == MEDIA_REQUEST_STATE_QUEUED &&
+           !req->num_incomplete_objects) {
+               req->state = MEDIA_REQUEST_STATE_COMPLETE;
+               completed = true;
+               wake_up_interruptible_all(&req->poll_wait);
+       }
+
+unlock:
+       spin_unlock_irqrestore(&req->lock, flags);
+       if (obj->ops->unbind)
+               obj->ops->unbind(obj);
+       if (completed)
+               media_request_put(req);
+}
+EXPORT_SYMBOL_GPL(media_request_object_unbind);
+
+void media_request_object_complete(struct media_request_object *obj)
+{
+       struct media_request *req = obj->req;
+       unsigned long flags;
+       bool completed = false;
+
+       spin_lock_irqsave(&req->lock, flags);
+       if (obj->completed)
+               goto unlock;
+       obj->completed = true;
+       if (WARN_ON(!req->num_incomplete_objects) ||
+           WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
+               goto unlock;
+
+       if (!--req->num_incomplete_objects) {
+               req->state = MEDIA_REQUEST_STATE_COMPLETE;
+               wake_up_interruptible_all(&req->poll_wait);
+               completed = true;
+       }
+unlock:
+       spin_unlock_irqrestore(&req->lock, flags);
+       if (completed)
+               media_request_put(req);
+}
+EXPORT_SYMBOL_GPL(media_request_object_complete);
diff --git a/drivers/media/media-dev-allocator.c b/drivers/media/media-dev-allocator.c
deleted file mode 100644 (file)
index ae17887..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-// 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);
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
deleted file mode 100644 (file)
index 6893843..0000000
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
- * Media device
- *
- * Copyright (C) 2010 Nokia Corporation
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *          Sakari Ailus <sakari.ailus@iki.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/compat.h>
-#include <linux/export.h>
-#include <linux/idr.h>
-#include <linux/ioctl.h>
-#include <linux/media.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/usb.h>
-#include <linux/version.h>
-
-#include <media/media-device.h>
-#include <media/media-devnode.h>
-#include <media/media-entity.h>
-#include <media/media-request.h>
-
-#ifdef CONFIG_MEDIA_CONTROLLER
-
-/*
- * Legacy defines from linux/media.h. This is the only place we need this
- * so we just define it here. The media.h header doesn't expose it to the
- * kernel to prevent it from being used by drivers, but here (and only here!)
- * we need it to handle the legacy behavior.
- */
-#define MEDIA_ENT_SUBTYPE_MASK                 0x0000ffff
-#define MEDIA_ENT_T_DEVNODE_UNKNOWN            (MEDIA_ENT_F_OLD_BASE | \
-                                                MEDIA_ENT_SUBTYPE_MASK)
-
-/* -----------------------------------------------------------------------------
- * Userspace API
- */
-
-static inline void __user *media_get_uptr(__u64 arg)
-{
-       return (void __user *)(uintptr_t)arg;
-}
-
-static int media_device_open(struct file *filp)
-{
-       return 0;
-}
-
-static int media_device_close(struct file *filp)
-{
-       return 0;
-}
-
-static long media_device_get_info(struct media_device *dev, void *arg)
-{
-       struct media_device_info *info = arg;
-
-       memset(info, 0, sizeof(*info));
-
-       if (dev->driver_name[0])
-               strscpy(info->driver, dev->driver_name, sizeof(info->driver));
-       else
-               strscpy(info->driver, dev->dev->driver->name,
-                       sizeof(info->driver));
-
-       strscpy(info->model, dev->model, sizeof(info->model));
-       strscpy(info->serial, dev->serial, sizeof(info->serial));
-       strscpy(info->bus_info, dev->bus_info, sizeof(info->bus_info));
-
-       info->media_version = LINUX_VERSION_CODE;
-       info->driver_version = info->media_version;
-       info->hw_revision = dev->hw_revision;
-
-       return 0;
-}
-
-static struct media_entity *find_entity(struct media_device *mdev, u32 id)
-{
-       struct media_entity *entity;
-       int next = id & MEDIA_ENT_ID_FLAG_NEXT;
-
-       id &= ~MEDIA_ENT_ID_FLAG_NEXT;
-
-       media_device_for_each_entity(entity, mdev) {
-               if (((media_entity_id(entity) == id) && !next) ||
-                   ((media_entity_id(entity) > id) && next)) {
-                       return entity;
-               }
-       }
-
-       return NULL;
-}
-
-static long media_device_enum_entities(struct media_device *mdev, void *arg)
-{
-       struct media_entity_desc *entd = arg;
-       struct media_entity *ent;
-
-       ent = find_entity(mdev, entd->id);
-       if (ent == NULL)
-               return -EINVAL;
-
-       memset(entd, 0, sizeof(*entd));
-
-       entd->id = media_entity_id(ent);
-       if (ent->name)
-               strscpy(entd->name, ent->name, sizeof(entd->name));
-       entd->type = ent->function;
-       entd->revision = 0;             /* Unused */
-       entd->flags = ent->flags;
-       entd->group_id = 0;             /* Unused */
-       entd->pads = ent->num_pads;
-       entd->links = ent->num_links - ent->num_backlinks;
-
-       /*
-        * Workaround for a bug at media-ctl <= v1.10 that makes it to
-        * do the wrong thing if the entity function doesn't belong to
-        * either MEDIA_ENT_F_OLD_BASE or MEDIA_ENT_F_OLD_SUBDEV_BASE
-        * Ranges.
-        *
-        * Non-subdevices are expected to be at the MEDIA_ENT_F_OLD_BASE,
-        * or, otherwise, will be silently ignored by media-ctl when
-        * printing the graphviz diagram. So, map them into the devnode
-        * old range.
-        */
-       if (ent->function < MEDIA_ENT_F_OLD_BASE ||
-           ent->function > MEDIA_ENT_F_TUNER) {
-               if (is_media_entity_v4l2_subdev(ent))
-                       entd->type = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
-               else if (ent->function != MEDIA_ENT_F_IO_V4L)
-                       entd->type = MEDIA_ENT_T_DEVNODE_UNKNOWN;
-       }
-
-       memcpy(&entd->raw, &ent->info, sizeof(ent->info));
-
-       return 0;
-}
-
-static void media_device_kpad_to_upad(const struct media_pad *kpad,
-                                     struct media_pad_desc *upad)
-{
-       upad->entity = media_entity_id(kpad->entity);
-       upad->index = kpad->index;
-       upad->flags = kpad->flags;
-}
-
-static long media_device_enum_links(struct media_device *mdev, void *arg)
-{
-       struct media_links_enum *links = arg;
-       struct media_entity *entity;
-
-       entity = find_entity(mdev, links->entity);
-       if (entity == NULL)
-               return -EINVAL;
-
-       if (links->pads) {
-               unsigned int p;
-
-               for (p = 0; p < entity->num_pads; p++) {
-                       struct media_pad_desc pad;
-
-                       memset(&pad, 0, sizeof(pad));
-                       media_device_kpad_to_upad(&entity->pads[p], &pad);
-                       if (copy_to_user(&links->pads[p], &pad, sizeof(pad)))
-                               return -EFAULT;
-               }
-       }
-
-       if (links->links) {
-               struct media_link *link;
-               struct media_link_desc __user *ulink_desc = links->links;
-
-               list_for_each_entry(link, &entity->links, list) {
-                       struct media_link_desc klink_desc;
-
-                       /* Ignore backlinks. */
-                       if (link->source->entity != entity)
-                               continue;
-                       memset(&klink_desc, 0, sizeof(klink_desc));
-                       media_device_kpad_to_upad(link->source,
-                                                 &klink_desc.source);
-                       media_device_kpad_to_upad(link->sink,
-                                                 &klink_desc.sink);
-                       klink_desc.flags = link->flags;
-                       if (copy_to_user(ulink_desc, &klink_desc,
-                                        sizeof(*ulink_desc)))
-                               return -EFAULT;
-                       ulink_desc++;
-               }
-       }
-       memset(links->reserved, 0, sizeof(links->reserved));
-
-       return 0;
-}
-
-static long media_device_setup_link(struct media_device *mdev, void *arg)
-{
-       struct media_link_desc *linkd = arg;
-       struct media_link *link = NULL;
-       struct media_entity *source;
-       struct media_entity *sink;
-
-       /* Find the source and sink entities and link.
-        */
-       source = find_entity(mdev, linkd->source.entity);
-       sink = find_entity(mdev, linkd->sink.entity);
-
-       if (source == NULL || sink == NULL)
-               return -EINVAL;
-
-       if (linkd->source.index >= source->num_pads ||
-           linkd->sink.index >= sink->num_pads)
-               return -EINVAL;
-
-       link = media_entity_find_link(&source->pads[linkd->source.index],
-                                     &sink->pads[linkd->sink.index]);
-       if (link == NULL)
-               return -EINVAL;
-
-       memset(linkd->reserved, 0, sizeof(linkd->reserved));
-
-       /* Setup the link on both entities. */
-       return __media_entity_setup_link(link, linkd->flags);
-}
-
-static long media_device_get_topology(struct media_device *mdev, void *arg)
-{
-       struct media_v2_topology *topo = arg;
-       struct media_entity *entity;
-       struct media_interface *intf;
-       struct media_pad *pad;
-       struct media_link *link;
-       struct media_v2_entity kentity, __user *uentity;
-       struct media_v2_interface kintf, __user *uintf;
-       struct media_v2_pad kpad, __user *upad;
-       struct media_v2_link klink, __user *ulink;
-       unsigned int i;
-       int ret = 0;
-
-       topo->topology_version = mdev->topology_version;
-
-       /* Get entities and number of entities */
-       i = 0;
-       uentity = media_get_uptr(topo->ptr_entities);
-       media_device_for_each_entity(entity, mdev) {
-               i++;
-               if (ret || !uentity)
-                       continue;
-
-               if (i > topo->num_entities) {
-                       ret = -ENOSPC;
-                       continue;
-               }
-
-               /* Copy fields to userspace struct if not error */
-               memset(&kentity, 0, sizeof(kentity));
-               kentity.id = entity->graph_obj.id;
-               kentity.function = entity->function;
-               kentity.flags = entity->flags;
-               strscpy(kentity.name, entity->name,
-                       sizeof(kentity.name));
-
-               if (copy_to_user(uentity, &kentity, sizeof(kentity)))
-                       ret = -EFAULT;
-               uentity++;
-       }
-       topo->num_entities = i;
-       topo->reserved1 = 0;
-
-       /* Get interfaces and number of interfaces */
-       i = 0;
-       uintf = media_get_uptr(topo->ptr_interfaces);
-       media_device_for_each_intf(intf, mdev) {
-               i++;
-               if (ret || !uintf)
-                       continue;
-
-               if (i > topo->num_interfaces) {
-                       ret = -ENOSPC;
-                       continue;
-               }
-
-               memset(&kintf, 0, sizeof(kintf));
-
-               /* Copy intf fields to userspace struct */
-               kintf.id = intf->graph_obj.id;
-               kintf.intf_type = intf->type;
-               kintf.flags = intf->flags;
-
-               if (media_type(&intf->graph_obj) == MEDIA_GRAPH_INTF_DEVNODE) {
-                       struct media_intf_devnode *devnode;
-
-                       devnode = intf_to_devnode(intf);
-
-                       kintf.devnode.major = devnode->major;
-                       kintf.devnode.minor = devnode->minor;
-               }
-
-               if (copy_to_user(uintf, &kintf, sizeof(kintf)))
-                       ret = -EFAULT;
-               uintf++;
-       }
-       topo->num_interfaces = i;
-       topo->reserved2 = 0;
-
-       /* Get pads and number of pads */
-       i = 0;
-       upad = media_get_uptr(topo->ptr_pads);
-       media_device_for_each_pad(pad, mdev) {
-               i++;
-               if (ret || !upad)
-                       continue;
-
-               if (i > topo->num_pads) {
-                       ret = -ENOSPC;
-                       continue;
-               }
-
-               memset(&kpad, 0, sizeof(kpad));
-
-               /* Copy pad fields to userspace struct */
-               kpad.id = pad->graph_obj.id;
-               kpad.entity_id = pad->entity->graph_obj.id;
-               kpad.flags = pad->flags;
-               kpad.index = pad->index;
-
-               if (copy_to_user(upad, &kpad, sizeof(kpad)))
-                       ret = -EFAULT;
-               upad++;
-       }
-       topo->num_pads = i;
-       topo->reserved3 = 0;
-
-       /* Get links and number of links */
-       i = 0;
-       ulink = media_get_uptr(topo->ptr_links);
-       media_device_for_each_link(link, mdev) {
-               if (link->is_backlink)
-                       continue;
-
-               i++;
-
-               if (ret || !ulink)
-                       continue;
-
-               if (i > topo->num_links) {
-                       ret = -ENOSPC;
-                       continue;
-               }
-
-               memset(&klink, 0, sizeof(klink));
-
-               /* Copy link fields to userspace struct */
-               klink.id = link->graph_obj.id;
-               klink.source_id = link->gobj0->id;
-               klink.sink_id = link->gobj1->id;
-               klink.flags = link->flags;
-
-               if (copy_to_user(ulink, &klink, sizeof(klink)))
-                       ret = -EFAULT;
-               ulink++;
-       }
-       topo->num_links = i;
-       topo->reserved4 = 0;
-
-       return ret;
-}
-
-static long media_device_request_alloc(struct media_device *mdev,
-                                      int *alloc_fd)
-{
-#ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API
-       if (!mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue)
-               return -ENOTTY;
-
-       return media_request_alloc(mdev, alloc_fd);
-#else
-       return -ENOTTY;
-#endif
-}
-
-static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd)
-{
-       if ((_IOC_DIR(cmd) & _IOC_WRITE) &&
-           copy_from_user(karg, uarg, _IOC_SIZE(cmd)))
-               return -EFAULT;
-
-       return 0;
-}
-
-static long copy_arg_to_user(void __user *uarg, void *karg, unsigned int cmd)
-{
-       if ((_IOC_DIR(cmd) & _IOC_READ) &&
-           copy_to_user(uarg, karg, _IOC_SIZE(cmd)))
-               return -EFAULT;
-
-       return 0;
-}
-
-/* Do acquire the graph mutex */
-#define MEDIA_IOC_FL_GRAPH_MUTEX       BIT(0)
-
-#define MEDIA_IOC_ARG(__cmd, func, fl, from_user, to_user)             \
-       [_IOC_NR(MEDIA_IOC_##__cmd)] = {                                \
-               .cmd = MEDIA_IOC_##__cmd,                               \
-               .fn = (long (*)(struct media_device *, void *))func,    \
-               .flags = fl,                                            \
-               .arg_from_user = from_user,                             \
-               .arg_to_user = to_user,                                 \
-       }
-
-#define MEDIA_IOC(__cmd, func, fl)                                     \
-       MEDIA_IOC_ARG(__cmd, func, fl, copy_arg_from_user, copy_arg_to_user)
-
-/* the table is indexed by _IOC_NR(cmd) */
-struct media_ioctl_info {
-       unsigned int cmd;
-       unsigned short flags;
-       long (*fn)(struct media_device *dev, void *arg);
-       long (*arg_from_user)(void *karg, void __user *uarg, unsigned int cmd);
-       long (*arg_to_user)(void __user *uarg, void *karg, unsigned int cmd);
-};
-
-static const struct media_ioctl_info ioctl_info[] = {
-       MEDIA_IOC(DEVICE_INFO, media_device_get_info, MEDIA_IOC_FL_GRAPH_MUTEX),
-       MEDIA_IOC(ENUM_ENTITIES, media_device_enum_entities, MEDIA_IOC_FL_GRAPH_MUTEX),
-       MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX),
-       MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_FL_GRAPH_MUTEX),
-       MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX),
-       MEDIA_IOC(REQUEST_ALLOC, media_device_request_alloc, 0),
-};
-
-static long media_device_ioctl(struct file *filp, unsigned int cmd,
-                              unsigned long __arg)
-{
-       struct media_devnode *devnode = media_devnode_data(filp);
-       struct media_device *dev = devnode->media_dev;
-       const struct media_ioctl_info *info;
-       void __user *arg = (void __user *)__arg;
-       char __karg[256], *karg = __karg;
-       long ret;
-
-       if (_IOC_NR(cmd) >= ARRAY_SIZE(ioctl_info)
-           || ioctl_info[_IOC_NR(cmd)].cmd != cmd)
-               return -ENOIOCTLCMD;
-
-       info = &ioctl_info[_IOC_NR(cmd)];
-
-       if (_IOC_SIZE(info->cmd) > sizeof(__karg)) {
-               karg = kmalloc(_IOC_SIZE(info->cmd), GFP_KERNEL);
-               if (!karg)
-                       return -ENOMEM;
-       }
-
-       if (info->arg_from_user) {
-               ret = info->arg_from_user(karg, arg, cmd);
-               if (ret)
-                       goto out_free;
-       }
-
-       if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX)
-               mutex_lock(&dev->graph_mutex);
-
-       ret = info->fn(dev, karg);
-
-       if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX)
-               mutex_unlock(&dev->graph_mutex);
-
-       if (!ret && info->arg_to_user)
-               ret = info->arg_to_user(arg, karg, cmd);
-
-out_free:
-       if (karg != __karg)
-               kfree(karg);
-
-       return ret;
-}
-
-#ifdef CONFIG_COMPAT
-
-struct media_links_enum32 {
-       __u32 entity;
-       compat_uptr_t pads; /* struct media_pad_desc * */
-       compat_uptr_t links; /* struct media_link_desc * */
-       __u32 reserved[4];
-};
-
-static long media_device_enum_links32(struct media_device *mdev,
-                                     struct media_links_enum32 __user *ulinks)
-{
-       struct media_links_enum links;
-       compat_uptr_t pads_ptr, links_ptr;
-       int ret;
-
-       memset(&links, 0, sizeof(links));
-
-       if (get_user(links.entity, &ulinks->entity)
-           || get_user(pads_ptr, &ulinks->pads)
-           || get_user(links_ptr, &ulinks->links))
-               return -EFAULT;
-
-       links.pads = compat_ptr(pads_ptr);
-       links.links = compat_ptr(links_ptr);
-
-       ret = media_device_enum_links(mdev, &links);
-       if (ret)
-               return ret;
-
-       memset(ulinks->reserved, 0, sizeof(ulinks->reserved));
-
-       return 0;
-}
-
-#define MEDIA_IOC_ENUM_LINKS32         _IOWR('|', 0x02, struct media_links_enum32)
-
-static long media_device_compat_ioctl(struct file *filp, unsigned int cmd,
-                                     unsigned long arg)
-{
-       struct media_devnode *devnode = media_devnode_data(filp);
-       struct media_device *dev = devnode->media_dev;
-       long ret;
-
-       switch (cmd) {
-       case MEDIA_IOC_ENUM_LINKS32:
-               mutex_lock(&dev->graph_mutex);
-               ret = media_device_enum_links32(dev,
-                               (struct media_links_enum32 __user *)arg);
-               mutex_unlock(&dev->graph_mutex);
-               break;
-
-       default:
-               return media_device_ioctl(filp, cmd, arg);
-       }
-
-       return ret;
-}
-#endif /* CONFIG_COMPAT */
-
-static const struct media_file_operations media_device_fops = {
-       .owner = THIS_MODULE,
-       .open = media_device_open,
-       .ioctl = media_device_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = media_device_compat_ioctl,
-#endif /* CONFIG_COMPAT */
-       .release = media_device_close,
-};
-
-/* -----------------------------------------------------------------------------
- * sysfs
- */
-
-static ssize_t show_model(struct device *cd,
-                         struct device_attribute *attr, char *buf)
-{
-       struct media_devnode *devnode = to_media_devnode(cd);
-       struct media_device *mdev = devnode->media_dev;
-
-       return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model);
-}
-
-static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-
-/* -----------------------------------------------------------------------------
- * Registration/unregistration
- */
-
-static void media_device_release(struct media_devnode *devnode)
-{
-       dev_dbg(devnode->parent, "Media device released\n");
-}
-
-/**
- * media_device_register_entity - Register an entity with a media device
- * @mdev:      The media device
- * @entity:    The entity
- */
-int __must_check media_device_register_entity(struct media_device *mdev,
-                                             struct media_entity *entity)
-{
-       struct media_entity_notify *notify, *next;
-       unsigned int i;
-       int ret;
-
-       if (entity->function == MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN ||
-           entity->function == MEDIA_ENT_F_UNKNOWN)
-               dev_warn(mdev->dev,
-                        "Entity type for entity %s was not initialized!\n",
-                        entity->name);
-
-       /* Warn if we apparently re-register an entity */
-       WARN_ON(entity->graph_obj.mdev != NULL);
-       entity->graph_obj.mdev = mdev;
-       INIT_LIST_HEAD(&entity->links);
-       entity->num_links = 0;
-       entity->num_backlinks = 0;
-
-       ret = ida_alloc_min(&mdev->entity_internal_idx, 1, GFP_KERNEL);
-       if (ret < 0)
-               return ret;
-       entity->internal_idx = ret;
-
-       mutex_lock(&mdev->graph_mutex);
-       mdev->entity_internal_idx_max =
-               max(mdev->entity_internal_idx_max, entity->internal_idx);
-
-       /* Initialize media_gobj embedded at the entity */
-       media_gobj_create(mdev, MEDIA_GRAPH_ENTITY, &entity->graph_obj);
-
-       /* Initialize objects at the pads */
-       for (i = 0; i < entity->num_pads; i++)
-               media_gobj_create(mdev, MEDIA_GRAPH_PAD,
-                              &entity->pads[i].graph_obj);
-
-       /* invoke entity_notify callbacks */
-       list_for_each_entry_safe(notify, next, &mdev->entity_notify, list)
-               notify->notify(entity, notify->notify_data);
-
-       if (mdev->entity_internal_idx_max
-           >= mdev->pm_count_walk.ent_enum.idx_max) {
-               struct media_graph new = { .top = 0 };
-
-               /*
-                * Initialise the new graph walk before cleaning up
-                * the old one in order not to spoil the graph walk
-                * object of the media device if graph walk init fails.
-                */
-               ret = media_graph_walk_init(&new, mdev);
-               if (ret) {
-                       mutex_unlock(&mdev->graph_mutex);
-                       return ret;
-               }
-               media_graph_walk_cleanup(&mdev->pm_count_walk);
-               mdev->pm_count_walk = new;
-       }
-       mutex_unlock(&mdev->graph_mutex);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(media_device_register_entity);
-
-static void __media_device_unregister_entity(struct media_entity *entity)
-{
-       struct media_device *mdev = entity->graph_obj.mdev;
-       struct media_link *link, *tmp;
-       struct media_interface *intf;
-       unsigned int i;
-
-       ida_free(&mdev->entity_internal_idx, entity->internal_idx);
-
-       /* Remove all interface links pointing to this entity */
-       list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) {
-               list_for_each_entry_safe(link, tmp, &intf->links, list) {
-                       if (link->entity == entity)
-                               __media_remove_intf_link(link);
-               }
-       }
-
-       /* Remove all data links that belong to this entity */
-       __media_entity_remove_links(entity);
-
-       /* Remove all pads that belong to this entity */
-       for (i = 0; i < entity->num_pads; i++)
-               media_gobj_destroy(&entity->pads[i].graph_obj);
-
-       /* Remove the entity */
-       media_gobj_destroy(&entity->graph_obj);
-
-       /* invoke entity_notify callbacks to handle entity removal?? */
-
-       entity->graph_obj.mdev = NULL;
-}
-
-void media_device_unregister_entity(struct media_entity *entity)
-{
-       struct media_device *mdev = entity->graph_obj.mdev;
-
-       if (mdev == NULL)
-               return;
-
-       mutex_lock(&mdev->graph_mutex);
-       __media_device_unregister_entity(entity);
-       mutex_unlock(&mdev->graph_mutex);
-}
-EXPORT_SYMBOL_GPL(media_device_unregister_entity);
-
-/**
- * media_device_init() - initialize a media device
- * @mdev:      The media device
- *
- * The caller is responsible for initializing the media device before
- * registration. The following fields must be set:
- *
- * - dev must point to the parent device
- * - model must be filled with the device model name
- */
-void media_device_init(struct media_device *mdev)
-{
-       INIT_LIST_HEAD(&mdev->entities);
-       INIT_LIST_HEAD(&mdev->interfaces);
-       INIT_LIST_HEAD(&mdev->pads);
-       INIT_LIST_HEAD(&mdev->links);
-       INIT_LIST_HEAD(&mdev->entity_notify);
-
-       mutex_init(&mdev->req_queue_mutex);
-       mutex_init(&mdev->graph_mutex);
-       ida_init(&mdev->entity_internal_idx);
-
-       atomic_set(&mdev->request_id, 0);
-
-       dev_dbg(mdev->dev, "Media device initialized\n");
-}
-EXPORT_SYMBOL_GPL(media_device_init);
-
-void media_device_cleanup(struct media_device *mdev)
-{
-       ida_destroy(&mdev->entity_internal_idx);
-       mdev->entity_internal_idx_max = 0;
-       media_graph_walk_cleanup(&mdev->pm_count_walk);
-       mutex_destroy(&mdev->graph_mutex);
-       mutex_destroy(&mdev->req_queue_mutex);
-}
-EXPORT_SYMBOL_GPL(media_device_cleanup);
-
-int __must_check __media_device_register(struct media_device *mdev,
-                                        struct module *owner)
-{
-       struct media_devnode *devnode;
-       int ret;
-
-       devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
-       if (!devnode)
-               return -ENOMEM;
-
-       /* Register the device node. */
-       mdev->devnode = devnode;
-       devnode->fops = &media_device_fops;
-       devnode->parent = mdev->dev;
-       devnode->release = media_device_release;
-
-       /* Set version 0 to indicate user-space that the graph is static */
-       mdev->topology_version = 0;
-
-       ret = media_devnode_register(mdev, devnode, owner);
-       if (ret < 0) {
-               /* devnode free is handled in media_devnode_*() */
-               mdev->devnode = NULL;
-               return ret;
-       }
-
-       ret = device_create_file(&devnode->dev, &dev_attr_model);
-       if (ret < 0) {
-               /* devnode free is handled in media_devnode_*() */
-               mdev->devnode = NULL;
-               media_devnode_unregister_prepare(devnode);
-               media_devnode_unregister(devnode);
-               return ret;
-       }
-
-       dev_dbg(mdev->dev, "Media device registered\n");
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(__media_device_register);
-
-int __must_check media_device_register_entity_notify(struct media_device *mdev,
-                                       struct media_entity_notify *nptr)
-{
-       mutex_lock(&mdev->graph_mutex);
-       list_add_tail(&nptr->list, &mdev->entity_notify);
-       mutex_unlock(&mdev->graph_mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(media_device_register_entity_notify);
-
-/*
- * Note: Should be called with mdev->lock held.
- */
-static void __media_device_unregister_entity_notify(struct media_device *mdev,
-                                       struct media_entity_notify *nptr)
-{
-       list_del(&nptr->list);
-}
-
-void media_device_unregister_entity_notify(struct media_device *mdev,
-                                       struct media_entity_notify *nptr)
-{
-       mutex_lock(&mdev->graph_mutex);
-       __media_device_unregister_entity_notify(mdev, nptr);
-       mutex_unlock(&mdev->graph_mutex);
-}
-EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify);
-
-void media_device_unregister(struct media_device *mdev)
-{
-       struct media_entity *entity;
-       struct media_entity *next;
-       struct media_interface *intf, *tmp_intf;
-       struct media_entity_notify *notify, *nextp;
-
-       if (mdev == NULL)
-               return;
-
-       mutex_lock(&mdev->graph_mutex);
-
-       /* Check if mdev was ever registered at all */
-       if (!media_devnode_is_registered(mdev->devnode)) {
-               mutex_unlock(&mdev->graph_mutex);
-               return;
-       }
-
-       /* Clear the devnode register bit to avoid races with media dev open */
-       media_devnode_unregister_prepare(mdev->devnode);
-
-       /* Remove all entities from the media device */
-       list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list)
-               __media_device_unregister_entity(entity);
-
-       /* Remove all entity_notify callbacks from the media device */
-       list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list)
-               __media_device_unregister_entity_notify(mdev, notify);
-
-       /* Remove all interfaces from the media device */
-       list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces,
-                                graph_obj.list) {
-               /*
-                * Unlink the interface, but don't free it here; the
-                * module which created it is responsible for freeing
-                * it
-                */
-               __media_remove_intf_links(intf);
-               media_gobj_destroy(&intf->graph_obj);
-       }
-
-       mutex_unlock(&mdev->graph_mutex);
-
-       dev_dbg(mdev->dev, "Media device unregistered\n");
-
-       device_remove_file(&mdev->devnode->dev, &dev_attr_model);
-       media_devnode_unregister(mdev->devnode);
-       /* devnode free is handled in media_devnode_*() */
-       mdev->devnode = NULL;
-}
-EXPORT_SYMBOL_GPL(media_device_unregister);
-
-#if IS_ENABLED(CONFIG_PCI)
-void media_device_pci_init(struct media_device *mdev,
-                          struct pci_dev *pci_dev,
-                          const char *name)
-{
-       mdev->dev = &pci_dev->dev;
-
-       if (name)
-               strscpy(mdev->model, name, sizeof(mdev->model));
-       else
-               strscpy(mdev->model, pci_name(pci_dev), sizeof(mdev->model));
-
-       sprintf(mdev->bus_info, "PCI:%s", pci_name(pci_dev));
-
-       mdev->hw_revision = (pci_dev->subsystem_vendor << 16)
-                           | pci_dev->subsystem_device;
-
-       media_device_init(mdev);
-}
-EXPORT_SYMBOL_GPL(media_device_pci_init);
-#endif
-
-#if IS_ENABLED(CONFIG_USB)
-void __media_device_usb_init(struct media_device *mdev,
-                            struct usb_device *udev,
-                            const char *board_name,
-                            const char *driver_name)
-{
-       mdev->dev = &udev->dev;
-
-       if (driver_name)
-               strscpy(mdev->driver_name, driver_name,
-                       sizeof(mdev->driver_name));
-
-       if (board_name)
-               strscpy(mdev->model, board_name, sizeof(mdev->model));
-       else if (udev->product)
-               strscpy(mdev->model, udev->product, sizeof(mdev->model));
-       else
-               strscpy(mdev->model, "unknown model", sizeof(mdev->model));
-       if (udev->serial)
-               strscpy(mdev->serial, udev->serial, sizeof(mdev->serial));
-       usb_make_path(udev, mdev->bus_info, sizeof(mdev->bus_info));
-       mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
-
-       media_device_init(mdev);
-}
-EXPORT_SYMBOL_GPL(__media_device_usb_init);
-#endif
-
-
-#endif /* CONFIG_MEDIA_CONTROLLER */
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
deleted file mode 100644 (file)
index d5aa30e..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Media device node
- *
- * Copyright (C) 2010 Nokia Corporation
- *
- * Based on drivers/media/video/v4l2_dev.c code authored by
- *     Mauro Carvalho Chehab <mchehab@kernel.org> (version 2)
- *     Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *          Sakari Ailus <sakari.ailus@iki.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * --
- *
- * Generic media device node infrastructure to register and unregister
- * character devices using a dynamic major number and proper reference
- * counting.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/uaccess.h>
-
-#include <media/media-devnode.h>
-#include <media/media-device.h>
-
-#define MEDIA_NUM_DEVICES      256
-#define MEDIA_NAME             "media"
-
-static dev_t media_dev_t;
-
-/*
- *     Active devices
- */
-static DEFINE_MUTEX(media_devnode_lock);
-static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES);
-
-/* Called when the last user of the media device exits. */
-static void media_devnode_release(struct device *cd)
-{
-       struct media_devnode *devnode = to_media_devnode(cd);
-
-       mutex_lock(&media_devnode_lock);
-       /* Mark device node number as free */
-       clear_bit(devnode->minor, media_devnode_nums);
-       mutex_unlock(&media_devnode_lock);
-
-       /* Release media_devnode and perform other cleanups as needed. */
-       if (devnode->release)
-               devnode->release(devnode);
-
-       kfree(devnode);
-       pr_debug("%s: Media Devnode Deallocated\n", __func__);
-}
-
-static struct bus_type media_bus_type = {
-       .name = MEDIA_NAME,
-};
-
-static ssize_t media_read(struct file *filp, char __user *buf,
-               size_t sz, loff_t *off)
-{
-       struct media_devnode *devnode = media_devnode_data(filp);
-
-       if (!devnode->fops->read)
-               return -EINVAL;
-       if (!media_devnode_is_registered(devnode))
-               return -EIO;
-       return devnode->fops->read(filp, buf, sz, off);
-}
-
-static ssize_t media_write(struct file *filp, const char __user *buf,
-               size_t sz, loff_t *off)
-{
-       struct media_devnode *devnode = media_devnode_data(filp);
-
-       if (!devnode->fops->write)
-               return -EINVAL;
-       if (!media_devnode_is_registered(devnode))
-               return -EIO;
-       return devnode->fops->write(filp, buf, sz, off);
-}
-
-static __poll_t media_poll(struct file *filp,
-                              struct poll_table_struct *poll)
-{
-       struct media_devnode *devnode = media_devnode_data(filp);
-
-       if (!media_devnode_is_registered(devnode))
-               return EPOLLERR | EPOLLHUP;
-       if (!devnode->fops->poll)
-               return DEFAULT_POLLMASK;
-       return devnode->fops->poll(filp, poll);
-}
-
-static long
-__media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg,
-             long (*ioctl_func)(struct file *filp, unsigned int cmd,
-                                unsigned long arg))
-{
-       struct media_devnode *devnode = media_devnode_data(filp);
-
-       if (!ioctl_func)
-               return -ENOTTY;
-
-       if (!media_devnode_is_registered(devnode))
-               return -EIO;
-
-       return ioctl_func(filp, cmd, arg);
-}
-
-static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
-       struct media_devnode *devnode = media_devnode_data(filp);
-
-       return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl);
-}
-
-#ifdef CONFIG_COMPAT
-
-static long media_compat_ioctl(struct file *filp, unsigned int cmd,
-                              unsigned long arg)
-{
-       struct media_devnode *devnode = media_devnode_data(filp);
-
-       return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl);
-}
-
-#endif /* CONFIG_COMPAT */
-
-/* Override for the open function */
-static int media_open(struct inode *inode, struct file *filp)
-{
-       struct media_devnode *devnode;
-       int ret;
-
-       /* Check if the media device is available. This needs to be done with
-        * the media_devnode_lock held to prevent an open/unregister race:
-        * without the lock, the device could be unregistered and freed between
-        * the media_devnode_is_registered() and get_device() calls, leading to
-        * a crash.
-        */
-       mutex_lock(&media_devnode_lock);
-       devnode = container_of(inode->i_cdev, struct media_devnode, cdev);
-       /* return ENXIO if the media device has been removed
-          already or if it is not registered anymore. */
-       if (!media_devnode_is_registered(devnode)) {
-               mutex_unlock(&media_devnode_lock);
-               return -ENXIO;
-       }
-       /* and increase the device refcount */
-       get_device(&devnode->dev);
-       mutex_unlock(&media_devnode_lock);
-
-       filp->private_data = devnode;
-
-       if (devnode->fops->open) {
-               ret = devnode->fops->open(filp);
-               if (ret) {
-                       put_device(&devnode->dev);
-                       filp->private_data = NULL;
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-/* Override for the release function */
-static int media_release(struct inode *inode, struct file *filp)
-{
-       struct media_devnode *devnode = media_devnode_data(filp);
-
-       if (devnode->fops->release)
-               devnode->fops->release(filp);
-
-       filp->private_data = NULL;
-
-       /* decrease the refcount unconditionally since the release()
-          return value is ignored. */
-       put_device(&devnode->dev);
-
-       pr_debug("%s: Media Release\n", __func__);
-       return 0;
-}
-
-static const struct file_operations media_devnode_fops = {
-       .owner = THIS_MODULE,
-       .read = media_read,
-       .write = media_write,
-       .open = media_open,
-       .unlocked_ioctl = media_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = media_compat_ioctl,
-#endif /* CONFIG_COMPAT */
-       .release = media_release,
-       .poll = media_poll,
-       .llseek = no_llseek,
-};
-
-int __must_check media_devnode_register(struct media_device *mdev,
-                                       struct media_devnode *devnode,
-                                       struct module *owner)
-{
-       int minor;
-       int ret;
-
-       /* Part 1: Find a free minor number */
-       mutex_lock(&media_devnode_lock);
-       minor = find_next_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES, 0);
-       if (minor == MEDIA_NUM_DEVICES) {
-               mutex_unlock(&media_devnode_lock);
-               pr_err("could not get a free minor\n");
-               kfree(devnode);
-               return -ENFILE;
-       }
-
-       set_bit(minor, media_devnode_nums);
-       mutex_unlock(&media_devnode_lock);
-
-       devnode->minor = minor;
-       devnode->media_dev = mdev;
-
-       /* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */
-       devnode->dev.bus = &media_bus_type;
-       devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor);
-       devnode->dev.release = media_devnode_release;
-       if (devnode->parent)
-               devnode->dev.parent = devnode->parent;
-       dev_set_name(&devnode->dev, "media%d", devnode->minor);
-       device_initialize(&devnode->dev);
-
-       /* Part 2: Initialize the character device */
-       cdev_init(&devnode->cdev, &media_devnode_fops);
-       devnode->cdev.owner = owner;
-       kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor);
-
-       /* Part 3: Add the media and char device */
-       ret = cdev_device_add(&devnode->cdev, &devnode->dev);
-       if (ret < 0) {
-               pr_err("%s: cdev_device_add failed\n", __func__);
-               goto cdev_add_error;
-       }
-
-       /* Part 4: Activate this minor. The char device can now be used. */
-       set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
-
-       return 0;
-
-cdev_add_error:
-       mutex_lock(&media_devnode_lock);
-       clear_bit(devnode->minor, media_devnode_nums);
-       devnode->media_dev = NULL;
-       mutex_unlock(&media_devnode_lock);
-
-       put_device(&devnode->dev);
-       return ret;
-}
-
-void media_devnode_unregister_prepare(struct media_devnode *devnode)
-{
-       /* Check if devnode was ever registered at all */
-       if (!media_devnode_is_registered(devnode))
-               return;
-
-       mutex_lock(&media_devnode_lock);
-       clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags);
-       mutex_unlock(&media_devnode_lock);
-}
-
-void media_devnode_unregister(struct media_devnode *devnode)
-{
-       mutex_lock(&media_devnode_lock);
-       /* Delete the cdev on this minor as well */
-       cdev_device_del(&devnode->cdev, &devnode->dev);
-       devnode->media_dev = NULL;
-       mutex_unlock(&media_devnode_lock);
-
-       put_device(&devnode->dev);
-}
-
-/*
- *     Initialise media for linux
- */
-static int __init media_devnode_init(void)
-{
-       int ret;
-
-       pr_info("Linux media interface: v0.10\n");
-       ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES,
-                                 MEDIA_NAME);
-       if (ret < 0) {
-               pr_warn("unable to allocate major\n");
-               return ret;
-       }
-
-       ret = bus_register(&media_bus_type);
-       if (ret < 0) {
-               unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
-               pr_warn("bus_register failed\n");
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static void __exit media_devnode_exit(void)
-{
-       bus_unregister(&media_bus_type);
-       unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES);
-}
-
-subsys_initcall(media_devnode_init);
-module_exit(media_devnode_exit)
-
-MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
-MODULE_DESCRIPTION("Device node registration for media drivers");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
deleted file mode 100644 (file)
index a998a2e..0000000
+++ /dev/null
@@ -1,1036 +0,0 @@
-/*
- * Media entity
- *
- * Copyright (C) 2010 Nokia Corporation
- *
- * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *          Sakari Ailus <sakari.ailus@iki.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
-
-#include <linux/bitmap.h>
-#include <linux/property.h>
-#include <linux/slab.h>
-#include <media/media-entity.h>
-#include <media/media-device.h>
-
-static inline const char *gobj_type(enum media_gobj_type type)
-{
-       switch (type) {
-       case MEDIA_GRAPH_ENTITY:
-               return "entity";
-       case MEDIA_GRAPH_PAD:
-               return "pad";
-       case MEDIA_GRAPH_LINK:
-               return "link";
-       case MEDIA_GRAPH_INTF_DEVNODE:
-               return "intf-devnode";
-       default:
-               return "unknown";
-       }
-}
-
-static inline const char *intf_type(struct media_interface *intf)
-{
-       switch (intf->type) {
-       case MEDIA_INTF_T_DVB_FE:
-               return "dvb-frontend";
-       case MEDIA_INTF_T_DVB_DEMUX:
-               return "dvb-demux";
-       case MEDIA_INTF_T_DVB_DVR:
-               return "dvb-dvr";
-       case MEDIA_INTF_T_DVB_CA:
-               return  "dvb-ca";
-       case MEDIA_INTF_T_DVB_NET:
-               return "dvb-net";
-       case MEDIA_INTF_T_V4L_VIDEO:
-               return "v4l-video";
-       case MEDIA_INTF_T_V4L_VBI:
-               return "v4l-vbi";
-       case MEDIA_INTF_T_V4L_RADIO:
-               return "v4l-radio";
-       case MEDIA_INTF_T_V4L_SUBDEV:
-               return "v4l-subdev";
-       case MEDIA_INTF_T_V4L_SWRADIO:
-               return "v4l-swradio";
-       case MEDIA_INTF_T_V4L_TOUCH:
-               return "v4l-touch";
-       default:
-               return "unknown-intf";
-       }
-};
-
-__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
-                                         int idx_max)
-{
-       idx_max = ALIGN(idx_max, BITS_PER_LONG);
-       ent_enum->bmap = kcalloc(idx_max / BITS_PER_LONG, sizeof(long),
-                                GFP_KERNEL);
-       if (!ent_enum->bmap)
-               return -ENOMEM;
-
-       bitmap_zero(ent_enum->bmap, idx_max);
-       ent_enum->idx_max = idx_max;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(__media_entity_enum_init);
-
-void media_entity_enum_cleanup(struct media_entity_enum *ent_enum)
-{
-       kfree(ent_enum->bmap);
-}
-EXPORT_SYMBOL_GPL(media_entity_enum_cleanup);
-
-/**
- *  dev_dbg_obj - Prints in debug mode a change on some object
- *
- * @event_name:        Name of the event to report. Could be __func__
- * @gobj:      Pointer to the object
- *
- * Enabled only if DEBUG or CONFIG_DYNAMIC_DEBUG. Otherwise, it
- * won't produce any code.
- */
-static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
-{
-#if defined(DEBUG) || defined (CONFIG_DYNAMIC_DEBUG)
-       switch (media_type(gobj)) {
-       case MEDIA_GRAPH_ENTITY:
-               dev_dbg(gobj->mdev->dev,
-                       "%s id %u: entity '%s'\n",
-                       event_name, media_id(gobj),
-                       gobj_to_entity(gobj)->name);
-               break;
-       case MEDIA_GRAPH_LINK:
-       {
-               struct media_link *link = gobj_to_link(gobj);
-
-               dev_dbg(gobj->mdev->dev,
-                       "%s id %u: %s link id %u ==> id %u\n",
-                       event_name, media_id(gobj),
-                       media_type(link->gobj0) == MEDIA_GRAPH_PAD ?
-                               "data" : "interface",
-                       media_id(link->gobj0),
-                       media_id(link->gobj1));
-               break;
-       }
-       case MEDIA_GRAPH_PAD:
-       {
-               struct media_pad *pad = gobj_to_pad(gobj);
-
-               dev_dbg(gobj->mdev->dev,
-                       "%s id %u: %s%spad '%s':%d\n",
-                       event_name, media_id(gobj),
-                       pad->flags & MEDIA_PAD_FL_SINK   ? "sink " : "",
-                       pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "",
-                       pad->entity->name, pad->index);
-               break;
-       }
-       case MEDIA_GRAPH_INTF_DEVNODE:
-       {
-               struct media_interface *intf = gobj_to_intf(gobj);
-               struct media_intf_devnode *devnode = intf_to_devnode(intf);
-
-               dev_dbg(gobj->mdev->dev,
-                       "%s id %u: intf_devnode %s - major: %d, minor: %d\n",
-                       event_name, media_id(gobj),
-                       intf_type(intf),
-                       devnode->major, devnode->minor);
-               break;
-       }
-       }
-#endif
-}
-
-void media_gobj_create(struct media_device *mdev,
-                          enum media_gobj_type type,
-                          struct media_gobj *gobj)
-{
-       BUG_ON(!mdev);
-
-       gobj->mdev = mdev;
-
-       /* Create a per-type unique object ID */
-       gobj->id = media_gobj_gen_id(type, ++mdev->id);
-
-       switch (type) {
-       case MEDIA_GRAPH_ENTITY:
-               list_add_tail(&gobj->list, &mdev->entities);
-               break;
-       case MEDIA_GRAPH_PAD:
-               list_add_tail(&gobj->list, &mdev->pads);
-               break;
-       case MEDIA_GRAPH_LINK:
-               list_add_tail(&gobj->list, &mdev->links);
-               break;
-       case MEDIA_GRAPH_INTF_DEVNODE:
-               list_add_tail(&gobj->list, &mdev->interfaces);
-               break;
-       }
-
-       mdev->topology_version++;
-
-       dev_dbg_obj(__func__, gobj);
-}
-
-void media_gobj_destroy(struct media_gobj *gobj)
-{
-       /* Do nothing if the object is not linked. */
-       if (gobj->mdev == NULL)
-               return;
-
-       dev_dbg_obj(__func__, gobj);
-
-       gobj->mdev->topology_version++;
-
-       /* Remove the object from mdev list */
-       list_del(&gobj->list);
-
-       gobj->mdev = NULL;
-}
-
-/*
- * TODO: Get rid of this.
- */
-#define MEDIA_ENTITY_MAX_PADS          512
-
-int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
-                          struct media_pad *pads)
-{
-       struct media_device *mdev = entity->graph_obj.mdev;
-       unsigned int i;
-
-       if (num_pads >= MEDIA_ENTITY_MAX_PADS)
-               return -E2BIG;
-
-       entity->num_pads = num_pads;
-       entity->pads = pads;
-
-       if (mdev)
-               mutex_lock(&mdev->graph_mutex);
-
-       for (i = 0; i < num_pads; i++) {
-               pads[i].entity = entity;
-               pads[i].index = i;
-               if (mdev)
-                       media_gobj_create(mdev, MEDIA_GRAPH_PAD,
-                                       &entity->pads[i].graph_obj);
-       }
-
-       if (mdev)
-               mutex_unlock(&mdev->graph_mutex);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(media_entity_pads_init);
-
-/* -----------------------------------------------------------------------------
- * Graph traversal
- */
-
-static struct media_entity *
-media_entity_other(struct media_entity *entity, struct media_link *link)
-{
-       if (link->source->entity == entity)
-               return link->sink->entity;
-       else
-               return link->source->entity;
-}
-
-/* push an entity to traversal stack */
-static void stack_push(struct media_graph *graph,
-                      struct media_entity *entity)
-{
-       if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) {
-               WARN_ON(1);
-               return;
-       }
-       graph->top++;
-       graph->stack[graph->top].link = entity->links.next;
-       graph->stack[graph->top].entity = entity;
-}
-
-static struct media_entity *stack_pop(struct media_graph *graph)
-{
-       struct media_entity *entity;
-
-       entity = graph->stack[graph->top].entity;
-       graph->top--;
-
-       return entity;
-}
-
-#define link_top(en)   ((en)->stack[(en)->top].link)
-#define stack_top(en)  ((en)->stack[(en)->top].entity)
-
-/**
- * media_graph_walk_init - Allocate resources for graph walk
- * @graph: Media graph structure that will be used to walk the graph
- * @mdev: Media device
- *
- * Reserve resources for graph walk in media device's current
- * state. The memory must be released using
- * media_graph_walk_free().
- *
- * Returns error on failure, zero on success.
- */
-__must_check int media_graph_walk_init(
-       struct media_graph *graph, struct media_device *mdev)
-{
-       return media_entity_enum_init(&graph->ent_enum, mdev);
-}
-EXPORT_SYMBOL_GPL(media_graph_walk_init);
-
-/**
- * media_graph_walk_cleanup - Release resources related to graph walking
- * @graph: Media graph structure that was used to walk the graph
- */
-void media_graph_walk_cleanup(struct media_graph *graph)
-{
-       media_entity_enum_cleanup(&graph->ent_enum);
-}
-EXPORT_SYMBOL_GPL(media_graph_walk_cleanup);
-
-void media_graph_walk_start(struct media_graph *graph,
-                           struct media_entity *entity)
-{
-       media_entity_enum_zero(&graph->ent_enum);
-       media_entity_enum_set(&graph->ent_enum, entity);
-
-       graph->top = 0;
-       graph->stack[graph->top].entity = NULL;
-       stack_push(graph, entity);
-       dev_dbg(entity->graph_obj.mdev->dev,
-               "begin graph walk at '%s'\n", entity->name);
-}
-EXPORT_SYMBOL_GPL(media_graph_walk_start);
-
-static void media_graph_walk_iter(struct media_graph *graph)
-{
-       struct media_entity *entity = stack_top(graph);
-       struct media_link *link;
-       struct media_entity *next;
-
-       link = list_entry(link_top(graph), typeof(*link), list);
-
-       /* The link is not enabled so we do not follow. */
-       if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
-               link_top(graph) = link_top(graph)->next;
-               dev_dbg(entity->graph_obj.mdev->dev,
-                       "walk: skipping disabled link '%s':%u -> '%s':%u\n",
-                       link->source->entity->name, link->source->index,
-                       link->sink->entity->name, link->sink->index);
-               return;
-       }
-
-       /* Get the entity in the other end of the link . */
-       next = media_entity_other(entity, link);
-
-       /* Has the entity already been visited? */
-       if (media_entity_enum_test_and_set(&graph->ent_enum, next)) {
-               link_top(graph) = link_top(graph)->next;
-               dev_dbg(entity->graph_obj.mdev->dev,
-                       "walk: skipping entity '%s' (already seen)\n",
-                       next->name);
-               return;
-       }
-
-       /* Push the new entity to stack and start over. */
-       link_top(graph) = link_top(graph)->next;
-       stack_push(graph, next);
-       dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n",
-               next->name);
-}
-
-struct media_entity *media_graph_walk_next(struct media_graph *graph)
-{
-       struct media_entity *entity;
-
-       if (stack_top(graph) == NULL)
-               return NULL;
-
-       /*
-        * Depth first search. Push entity to stack and continue from
-        * top of the stack until no more entities on the level can be
-        * found.
-        */
-       while (link_top(graph) != &stack_top(graph)->links)
-               media_graph_walk_iter(graph);
-
-       entity = stack_pop(graph);
-       dev_dbg(entity->graph_obj.mdev->dev,
-               "walk: returning entity '%s'\n", entity->name);
-
-       return entity;
-}
-EXPORT_SYMBOL_GPL(media_graph_walk_next);
-
-int media_entity_get_fwnode_pad(struct media_entity *entity,
-                               struct fwnode_handle *fwnode,
-                               unsigned long direction_flags)
-{
-       struct fwnode_endpoint endpoint;
-       unsigned int i;
-       int ret;
-
-       if (!entity->ops || !entity->ops->get_fwnode_pad) {
-               for (i = 0; i < entity->num_pads; i++) {
-                       if (entity->pads[i].flags & direction_flags)
-                               return i;
-               }
-
-               return -ENXIO;
-       }
-
-       ret = fwnode_graph_parse_endpoint(fwnode, &endpoint);
-       if (ret)
-               return ret;
-
-       ret = entity->ops->get_fwnode_pad(&endpoint);
-       if (ret < 0)
-               return ret;
-
-       if (ret >= entity->num_pads)
-               return -ENXIO;
-
-       if (!(entity->pads[ret].flags & direction_flags))
-               return -ENXIO;
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad);
-
-/* -----------------------------------------------------------------------------
- * Pipeline management
- */
-
-__must_check int __media_pipeline_start(struct media_entity *entity,
-                                       struct media_pipeline *pipe)
-{
-       struct media_device *mdev = entity->graph_obj.mdev;
-       struct media_graph *graph = &pipe->graph;
-       struct media_entity *entity_err = entity;
-       struct media_link *link;
-       int ret;
-
-       if (!pipe->streaming_count++) {
-               ret = media_graph_walk_init(&pipe->graph, mdev);
-               if (ret)
-                       goto error_graph_walk_start;
-       }
-
-       media_graph_walk_start(&pipe->graph, entity);
-
-       while ((entity = media_graph_walk_next(graph))) {
-               DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS);
-               DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS);
-
-               entity->stream_count++;
-
-               if (entity->pipe && entity->pipe != pipe) {
-                       pr_err("Pipe active for %s. Can't start for %s\n",
-                               entity->name,
-                               entity_err->name);
-                       ret = -EBUSY;
-                       goto error;
-               }
-
-               entity->pipe = pipe;
-
-               /* Already streaming --- no need to check. */
-               if (entity->stream_count > 1)
-                       continue;
-
-               if (!entity->ops || !entity->ops->link_validate)
-                       continue;
-
-               bitmap_zero(active, entity->num_pads);
-               bitmap_fill(has_no_links, entity->num_pads);
-
-               list_for_each_entry(link, &entity->links, list) {
-                       struct media_pad *pad = link->sink->entity == entity
-                                               ? link->sink : link->source;
-
-                       /* Mark that a pad is connected by a link. */
-                       bitmap_clear(has_no_links, pad->index, 1);
-
-                       /*
-                        * Pads that either do not need to connect or
-                        * are connected through an enabled link are
-                        * fine.
-                        */
-                       if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) ||
-                           link->flags & MEDIA_LNK_FL_ENABLED)
-                               bitmap_set(active, pad->index, 1);
-
-                       /*
-                        * Link validation will only take place for
-                        * sink ends of the link that are enabled.
-                        */
-                       if (link->sink != pad ||
-                           !(link->flags & MEDIA_LNK_FL_ENABLED))
-                               continue;
-
-                       ret = entity->ops->link_validate(link);
-                       if (ret < 0 && ret != -ENOIOCTLCMD) {
-                               dev_dbg(entity->graph_obj.mdev->dev,
-                                       "link validation failed for '%s':%u -> '%s':%u, error %d\n",
-                                       link->source->entity->name,
-                                       link->source->index,
-                                       entity->name, link->sink->index, ret);
-                               goto error;
-                       }
-               }
-
-               /* Either no links or validated links are fine. */
-               bitmap_or(active, active, has_no_links, entity->num_pads);
-
-               if (!bitmap_full(active, entity->num_pads)) {
-                       ret = -ENOLINK;
-                       dev_dbg(entity->graph_obj.mdev->dev,
-                               "'%s':%u must be connected by an enabled link\n",
-                               entity->name,
-                               (unsigned)find_first_zero_bit(
-                                       active, entity->num_pads));
-                       goto error;
-               }
-       }
-
-       return 0;
-
-error:
-       /*
-        * Link validation on graph failed. We revert what we did and
-        * return the error.
-        */
-       media_graph_walk_start(graph, entity_err);
-
-       while ((entity_err = media_graph_walk_next(graph))) {
-               /* Sanity check for negative stream_count */
-               if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) {
-                       entity_err->stream_count--;
-                       if (entity_err->stream_count == 0)
-                               entity_err->pipe = NULL;
-               }
-
-               /*
-                * We haven't increased stream_count further than this
-                * so we quit here.
-                */
-               if (entity_err == entity)
-                       break;
-       }
-
-error_graph_walk_start:
-       if (!--pipe->streaming_count)
-               media_graph_walk_cleanup(graph);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(__media_pipeline_start);
-
-__must_check int media_pipeline_start(struct media_entity *entity,
-                                     struct media_pipeline *pipe)
-{
-       struct media_device *mdev = entity->graph_obj.mdev;
-       int ret;
-
-       mutex_lock(&mdev->graph_mutex);
-       ret = __media_pipeline_start(entity, pipe);
-       mutex_unlock(&mdev->graph_mutex);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(media_pipeline_start);
-
-void __media_pipeline_stop(struct media_entity *entity)
-{
-       struct media_graph *graph = &entity->pipe->graph;
-       struct media_pipeline *pipe = entity->pipe;
-
-       /*
-        * If the following check fails, the driver has performed an
-        * unbalanced call to media_pipeline_stop()
-        */
-       if (WARN_ON(!pipe))
-               return;
-
-       media_graph_walk_start(graph, entity);
-
-       while ((entity = media_graph_walk_next(graph))) {
-               /* Sanity check for negative stream_count */
-               if (!WARN_ON_ONCE(entity->stream_count <= 0)) {
-                       entity->stream_count--;
-                       if (entity->stream_count == 0)
-                               entity->pipe = NULL;
-               }
-       }
-
-       if (!--pipe->streaming_count)
-               media_graph_walk_cleanup(graph);
-
-}
-EXPORT_SYMBOL_GPL(__media_pipeline_stop);
-
-void media_pipeline_stop(struct media_entity *entity)
-{
-       struct media_device *mdev = entity->graph_obj.mdev;
-
-       mutex_lock(&mdev->graph_mutex);
-       __media_pipeline_stop(entity);
-       mutex_unlock(&mdev->graph_mutex);
-}
-EXPORT_SYMBOL_GPL(media_pipeline_stop);
-
-/* -----------------------------------------------------------------------------
- * Links management
- */
-
-static struct media_link *media_add_link(struct list_head *head)
-{
-       struct media_link *link;
-
-       link = kzalloc(sizeof(*link), GFP_KERNEL);
-       if (link == NULL)
-               return NULL;
-
-       list_add_tail(&link->list, head);
-
-       return link;
-}
-
-static void __media_entity_remove_link(struct media_entity *entity,
-                                      struct media_link *link)
-{
-       struct media_link *rlink, *tmp;
-       struct media_entity *remote;
-
-       if (link->source->entity == entity)
-               remote = link->sink->entity;
-       else
-               remote = link->source->entity;
-
-       list_for_each_entry_safe(rlink, tmp, &remote->links, list) {
-               if (rlink != link->reverse)
-                       continue;
-
-               if (link->source->entity == entity)
-                       remote->num_backlinks--;
-
-               /* Remove the remote link */
-               list_del(&rlink->list);
-               media_gobj_destroy(&rlink->graph_obj);
-               kfree(rlink);
-
-               if (--remote->num_links == 0)
-                       break;
-       }
-       list_del(&link->list);
-       media_gobj_destroy(&link->graph_obj);
-       kfree(link);
-}
-
-int media_get_pad_index(struct media_entity *entity, bool is_sink,
-                       enum media_pad_signal_type sig_type)
-{
-       int i;
-       bool pad_is_sink;
-
-       if (!entity)
-               return -EINVAL;
-
-       for (i = 0; i < entity->num_pads; i++) {
-               if (entity->pads[i].flags == MEDIA_PAD_FL_SINK)
-                       pad_is_sink = true;
-               else if (entity->pads[i].flags == MEDIA_PAD_FL_SOURCE)
-                       pad_is_sink = false;
-               else
-                       continue;       /* This is an error! */
-
-               if (pad_is_sink != is_sink)
-                       continue;
-               if (entity->pads[i].sig_type == sig_type)
-                       return i;
-       }
-       return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(media_get_pad_index);
-
-int
-media_create_pad_link(struct media_entity *source, u16 source_pad,
-                        struct media_entity *sink, u16 sink_pad, u32 flags)
-{
-       struct media_link *link;
-       struct media_link *backlink;
-
-       BUG_ON(source == NULL || sink == NULL);
-       BUG_ON(source_pad >= source->num_pads);
-       BUG_ON(sink_pad >= sink->num_pads);
-
-       link = media_add_link(&source->links);
-       if (link == NULL)
-               return -ENOMEM;
-
-       link->source = &source->pads[source_pad];
-       link->sink = &sink->pads[sink_pad];
-       link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK;
-
-       /* Initialize graph object embedded at the new link */
-       media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK,
-                       &link->graph_obj);
-
-       /* Create the backlink. Backlinks are used to help graph traversal and
-        * are not reported to userspace.
-        */
-       backlink = media_add_link(&sink->links);
-       if (backlink == NULL) {
-               __media_entity_remove_link(source, link);
-               return -ENOMEM;
-       }
-
-       backlink->source = &source->pads[source_pad];
-       backlink->sink = &sink->pads[sink_pad];
-       backlink->flags = flags;
-       backlink->is_backlink = true;
-
-       /* Initialize graph object embedded at the new link */
-       media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK,
-                       &backlink->graph_obj);
-
-       link->reverse = backlink;
-       backlink->reverse = link;
-
-       sink->num_backlinks++;
-       sink->num_links++;
-       source->num_links++;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(media_create_pad_link);
-
-int media_create_pad_links(const struct media_device *mdev,
-                          const u32 source_function,
-                          struct media_entity *source,
-                          const u16 source_pad,
-                          const u32 sink_function,
-                          struct media_entity *sink,
-                          const u16 sink_pad,
-                          u32 flags,
-                          const bool allow_both_undefined)
-{
-       struct media_entity *entity;
-       unsigned function;
-       int ret;
-
-       /* Trivial case: 1:1 relation */
-       if (source && sink)
-               return media_create_pad_link(source, source_pad,
-                                            sink, sink_pad, flags);
-
-       /* Worse case scenario: n:n relation */
-       if (!source && !sink) {
-               if (!allow_both_undefined)
-                       return 0;
-               media_device_for_each_entity(source, mdev) {
-                       if (source->function != source_function)
-                               continue;
-                       media_device_for_each_entity(sink, mdev) {
-                               if (sink->function != sink_function)
-                                       continue;
-                               ret = media_create_pad_link(source, source_pad,
-                                                           sink, sink_pad,
-                                                           flags);
-                               if (ret)
-                                       return ret;
-                               flags &= ~(MEDIA_LNK_FL_ENABLED |
-                                          MEDIA_LNK_FL_IMMUTABLE);
-                       }
-               }
-               return 0;
-       }
-
-       /* Handle 1:n and n:1 cases */
-       if (source)
-               function = sink_function;
-       else
-               function = source_function;
-
-       media_device_for_each_entity(entity, mdev) {
-               if (entity->function != function)
-                       continue;
-
-               if (source)
-                       ret = media_create_pad_link(source, source_pad,
-                                                   entity, sink_pad, flags);
-               else
-                       ret = media_create_pad_link(entity, source_pad,
-                                                   sink, sink_pad, flags);
-               if (ret)
-                       return ret;
-               flags &= ~(MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(media_create_pad_links);
-
-void __media_entity_remove_links(struct media_entity *entity)
-{
-       struct media_link *link, *tmp;
-
-       list_for_each_entry_safe(link, tmp, &entity->links, list)
-               __media_entity_remove_link(entity, link);
-
-       entity->num_links = 0;
-       entity->num_backlinks = 0;
-}
-EXPORT_SYMBOL_GPL(__media_entity_remove_links);
-
-void media_entity_remove_links(struct media_entity *entity)
-{
-       struct media_device *mdev = entity->graph_obj.mdev;
-
-       /* Do nothing if the entity is not registered. */
-       if (mdev == NULL)
-               return;
-
-       mutex_lock(&mdev->graph_mutex);
-       __media_entity_remove_links(entity);
-       mutex_unlock(&mdev->graph_mutex);
-}
-EXPORT_SYMBOL_GPL(media_entity_remove_links);
-
-static int __media_entity_setup_link_notify(struct media_link *link, u32 flags)
-{
-       int ret;
-
-       /* Notify both entities. */
-       ret = media_entity_call(link->source->entity, link_setup,
-                               link->source, link->sink, flags);
-       if (ret < 0 && ret != -ENOIOCTLCMD)
-               return ret;
-
-       ret = media_entity_call(link->sink->entity, link_setup,
-                               link->sink, link->source, flags);
-       if (ret < 0 && ret != -ENOIOCTLCMD) {
-               media_entity_call(link->source->entity, link_setup,
-                                 link->source, link->sink, link->flags);
-               return ret;
-       }
-
-       link->flags = flags;
-       link->reverse->flags = link->flags;
-
-       return 0;
-}
-
-int __media_entity_setup_link(struct media_link *link, u32 flags)
-{
-       const u32 mask = MEDIA_LNK_FL_ENABLED;
-       struct media_device *mdev;
-       struct media_entity *source, *sink;
-       int ret = -EBUSY;
-
-       if (link == NULL)
-               return -EINVAL;
-
-       /* The non-modifiable link flags must not be modified. */
-       if ((link->flags & ~mask) != (flags & ~mask))
-               return -EINVAL;
-
-       if (link->flags & MEDIA_LNK_FL_IMMUTABLE)
-               return link->flags == flags ? 0 : -EINVAL;
-
-       if (link->flags == flags)
-               return 0;
-
-       source = link->source->entity;
-       sink = link->sink->entity;
-
-       if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) &&
-           (source->stream_count || sink->stream_count))
-               return -EBUSY;
-
-       mdev = source->graph_obj.mdev;
-
-       if (mdev->ops && mdev->ops->link_notify) {
-               ret = mdev->ops->link_notify(link, flags,
-                                            MEDIA_DEV_NOTIFY_PRE_LINK_CH);
-               if (ret < 0)
-                       return ret;
-       }
-
-       ret = __media_entity_setup_link_notify(link, flags);
-
-       if (mdev->ops && mdev->ops->link_notify)
-               mdev->ops->link_notify(link, flags,
-                                      MEDIA_DEV_NOTIFY_POST_LINK_CH);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(__media_entity_setup_link);
-
-int media_entity_setup_link(struct media_link *link, u32 flags)
-{
-       int ret;
-
-       mutex_lock(&link->graph_obj.mdev->graph_mutex);
-       ret = __media_entity_setup_link(link, flags);
-       mutex_unlock(&link->graph_obj.mdev->graph_mutex);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(media_entity_setup_link);
-
-struct media_link *
-media_entity_find_link(struct media_pad *source, struct media_pad *sink)
-{
-       struct media_link *link;
-
-       list_for_each_entry(link, &source->entity->links, list) {
-               if (link->source->entity == source->entity &&
-                   link->source->index == source->index &&
-                   link->sink->entity == sink->entity &&
-                   link->sink->index == sink->index)
-                       return link;
-       }
-
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(media_entity_find_link);
-
-struct media_pad *media_entity_remote_pad(const struct media_pad *pad)
-{
-       struct media_link *link;
-
-       list_for_each_entry(link, &pad->entity->links, list) {
-               if (!(link->flags & MEDIA_LNK_FL_ENABLED))
-                       continue;
-
-               if (link->source == pad)
-                       return link->sink;
-
-               if (link->sink == pad)
-                       return link->source;
-       }
-
-       return NULL;
-
-}
-EXPORT_SYMBOL_GPL(media_entity_remote_pad);
-
-static void media_interface_init(struct media_device *mdev,
-                                struct media_interface *intf,
-                                u32 gobj_type,
-                                u32 intf_type, u32 flags)
-{
-       intf->type = intf_type;
-       intf->flags = flags;
-       INIT_LIST_HEAD(&intf->links);
-
-       media_gobj_create(mdev, gobj_type, &intf->graph_obj);
-}
-
-/* Functions related to the media interface via device nodes */
-
-struct media_intf_devnode *media_devnode_create(struct media_device *mdev,
-                                               u32 type, u32 flags,
-                                               u32 major, u32 minor)
-{
-       struct media_intf_devnode *devnode;
-
-       devnode = kzalloc(sizeof(*devnode), GFP_KERNEL);
-       if (!devnode)
-               return NULL;
-
-       devnode->major = major;
-       devnode->minor = minor;
-
-       media_interface_init(mdev, &devnode->intf, MEDIA_GRAPH_INTF_DEVNODE,
-                            type, flags);
-
-       return devnode;
-}
-EXPORT_SYMBOL_GPL(media_devnode_create);
-
-void media_devnode_remove(struct media_intf_devnode *devnode)
-{
-       media_remove_intf_links(&devnode->intf);
-       media_gobj_destroy(&devnode->intf.graph_obj);
-       kfree(devnode);
-}
-EXPORT_SYMBOL_GPL(media_devnode_remove);
-
-struct media_link *media_create_intf_link(struct media_entity *entity,
-                                           struct media_interface *intf,
-                                           u32 flags)
-{
-       struct media_link *link;
-
-       link = media_add_link(&intf->links);
-       if (link == NULL)
-               return NULL;
-
-       link->intf = intf;
-       link->entity = entity;
-       link->flags = flags | MEDIA_LNK_FL_INTERFACE_LINK;
-
-       /* Initialize graph object embedded at the new link */
-       media_gobj_create(intf->graph_obj.mdev, MEDIA_GRAPH_LINK,
-                       &link->graph_obj);
-
-       return link;
-}
-EXPORT_SYMBOL_GPL(media_create_intf_link);
-
-void __media_remove_intf_link(struct media_link *link)
-{
-       list_del(&link->list);
-       media_gobj_destroy(&link->graph_obj);
-       kfree(link);
-}
-EXPORT_SYMBOL_GPL(__media_remove_intf_link);
-
-void media_remove_intf_link(struct media_link *link)
-{
-       struct media_device *mdev = link->graph_obj.mdev;
-
-       /* Do nothing if the intf is not registered. */
-       if (mdev == NULL)
-               return;
-
-       mutex_lock(&mdev->graph_mutex);
-       __media_remove_intf_link(link);
-       mutex_unlock(&mdev->graph_mutex);
-}
-EXPORT_SYMBOL_GPL(media_remove_intf_link);
-
-void __media_remove_intf_links(struct media_interface *intf)
-{
-       struct media_link *link, *tmp;
-
-       list_for_each_entry_safe(link, tmp, &intf->links, list)
-               __media_remove_intf_link(link);
-
-}
-EXPORT_SYMBOL_GPL(__media_remove_intf_links);
-
-void media_remove_intf_links(struct media_interface *intf)
-{
-       struct media_device *mdev = intf->graph_obj.mdev;
-
-       /* Do nothing if the intf is not registered. */
-       if (mdev == NULL)
-               return;
-
-       mutex_lock(&mdev->graph_mutex);
-       __media_remove_intf_links(intf);
-       mutex_unlock(&mdev->graph_mutex);
-}
-EXPORT_SYMBOL_GPL(media_remove_intf_links);
diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c
deleted file mode 100644 (file)
index e3fca43..0000000
+++ /dev/null
@@ -1,503 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Media device request objects
- *
- * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- * Copyright (C) 2018 Intel Corporation
- * Copyright (C) 2018 Google, Inc.
- *
- * Author: Hans Verkuil <hans.verkuil@cisco.com>
- * Author: Sakari Ailus <sakari.ailus@linux.intel.com>
- */
-
-#include <linux/anon_inodes.h>
-#include <linux/file.h>
-#include <linux/refcount.h>
-
-#include <media/media-device.h>
-#include <media/media-request.h>
-
-static const char * const request_state[] = {
-       [MEDIA_REQUEST_STATE_IDLE]       = "idle",
-       [MEDIA_REQUEST_STATE_VALIDATING] = "validating",
-       [MEDIA_REQUEST_STATE_QUEUED]     = "queued",
-       [MEDIA_REQUEST_STATE_COMPLETE]   = "complete",
-       [MEDIA_REQUEST_STATE_CLEANING]   = "cleaning",
-       [MEDIA_REQUEST_STATE_UPDATING]   = "updating",
-};
-
-static const char *
-media_request_state_str(enum media_request_state state)
-{
-       BUILD_BUG_ON(ARRAY_SIZE(request_state) != NR_OF_MEDIA_REQUEST_STATE);
-
-       if (WARN_ON(state >= ARRAY_SIZE(request_state)))
-               return "invalid";
-       return request_state[state];
-}
-
-static void media_request_clean(struct media_request *req)
-{
-       struct media_request_object *obj, *obj_safe;
-
-       /* Just a sanity check. No other code path is allowed to change this. */
-       WARN_ON(req->state != MEDIA_REQUEST_STATE_CLEANING);
-       WARN_ON(req->updating_count);
-       WARN_ON(req->access_count);
-
-       list_for_each_entry_safe(obj, obj_safe, &req->objects, list) {
-               media_request_object_unbind(obj);
-               media_request_object_put(obj);
-       }
-
-       req->updating_count = 0;
-       req->access_count = 0;
-       WARN_ON(req->num_incomplete_objects);
-       req->num_incomplete_objects = 0;
-       wake_up_interruptible_all(&req->poll_wait);
-}
-
-static void media_request_release(struct kref *kref)
-{
-       struct media_request *req =
-               container_of(kref, struct media_request, kref);
-       struct media_device *mdev = req->mdev;
-
-       dev_dbg(mdev->dev, "request: release %s\n", req->debug_str);
-
-       /* No other users, no need for a spinlock */
-       req->state = MEDIA_REQUEST_STATE_CLEANING;
-
-       media_request_clean(req);
-
-       if (mdev->ops->req_free)
-               mdev->ops->req_free(req);
-       else
-               kfree(req);
-}
-
-void media_request_put(struct media_request *req)
-{
-       kref_put(&req->kref, media_request_release);
-}
-EXPORT_SYMBOL_GPL(media_request_put);
-
-static int media_request_close(struct inode *inode, struct file *filp)
-{
-       struct media_request *req = filp->private_data;
-
-       media_request_put(req);
-       return 0;
-}
-
-static __poll_t media_request_poll(struct file *filp,
-                                  struct poll_table_struct *wait)
-{
-       struct media_request *req = filp->private_data;
-       unsigned long flags;
-       __poll_t ret = 0;
-
-       if (!(poll_requested_events(wait) & EPOLLPRI))
-               return 0;
-
-       poll_wait(filp, &req->poll_wait, wait);
-       spin_lock_irqsave(&req->lock, flags);
-       if (req->state == MEDIA_REQUEST_STATE_COMPLETE) {
-               ret = EPOLLPRI;
-               goto unlock;
-       }
-       if (req->state != MEDIA_REQUEST_STATE_QUEUED) {
-               ret = EPOLLERR;
-               goto unlock;
-       }
-
-unlock:
-       spin_unlock_irqrestore(&req->lock, flags);
-       return ret;
-}
-
-static long media_request_ioctl_queue(struct media_request *req)
-{
-       struct media_device *mdev = req->mdev;
-       enum media_request_state state;
-       unsigned long flags;
-       int ret;
-
-       dev_dbg(mdev->dev, "request: queue %s\n", req->debug_str);
-
-       /*
-        * Ensure the request that is validated will be the one that gets queued
-        * next by serialising the queueing process. This mutex is also used
-        * to serialize with canceling a vb2 queue and with setting values such
-        * as controls in a request.
-        */
-       mutex_lock(&mdev->req_queue_mutex);
-
-       media_request_get(req);
-
-       spin_lock_irqsave(&req->lock, flags);
-       if (req->state == MEDIA_REQUEST_STATE_IDLE)
-               req->state = MEDIA_REQUEST_STATE_VALIDATING;
-       state = req->state;
-       spin_unlock_irqrestore(&req->lock, flags);
-       if (state != MEDIA_REQUEST_STATE_VALIDATING) {
-               dev_dbg(mdev->dev,
-                       "request: unable to queue %s, request in state %s\n",
-                       req->debug_str, media_request_state_str(state));
-               media_request_put(req);
-               mutex_unlock(&mdev->req_queue_mutex);
-               return -EBUSY;
-       }
-
-       ret = mdev->ops->req_validate(req);
-
-       /*
-        * If the req_validate was successful, then we mark the state as QUEUED
-        * and call req_queue. The reason we set the state first is that this
-        * allows req_queue to unbind or complete the queued objects in case
-        * they are immediately 'consumed'. State changes from QUEUED to another
-        * state can only happen if either the driver changes the state or if
-        * the user cancels the vb2 queue. The driver can only change the state
-        * after each object is queued through the req_queue op (and note that
-        * that op cannot fail), so setting the state to QUEUED up front is
-        * safe.
-        *
-        * The other reason for changing the state is if the vb2 queue is
-        * canceled, and that uses the req_queue_mutex which is still locked
-        * while req_queue is called, so that's safe as well.
-        */
-       spin_lock_irqsave(&req->lock, flags);
-       req->state = ret ? MEDIA_REQUEST_STATE_IDLE
-                        : MEDIA_REQUEST_STATE_QUEUED;
-       spin_unlock_irqrestore(&req->lock, flags);
-
-       if (!ret)
-               mdev->ops->req_queue(req);
-
-       mutex_unlock(&mdev->req_queue_mutex);
-
-       if (ret) {
-               dev_dbg(mdev->dev, "request: can't queue %s (%d)\n",
-                       req->debug_str, ret);
-               media_request_put(req);
-       }
-
-       return ret;
-}
-
-static long media_request_ioctl_reinit(struct media_request *req)
-{
-       struct media_device *mdev = req->mdev;
-       unsigned long flags;
-
-       spin_lock_irqsave(&req->lock, flags);
-       if (req->state != MEDIA_REQUEST_STATE_IDLE &&
-           req->state != MEDIA_REQUEST_STATE_COMPLETE) {
-               dev_dbg(mdev->dev,
-                       "request: %s not in idle or complete state, cannot reinit\n",
-                       req->debug_str);
-               spin_unlock_irqrestore(&req->lock, flags);
-               return -EBUSY;
-       }
-       if (req->access_count) {
-               dev_dbg(mdev->dev,
-                       "request: %s is being accessed, cannot reinit\n",
-                       req->debug_str);
-               spin_unlock_irqrestore(&req->lock, flags);
-               return -EBUSY;
-       }
-       req->state = MEDIA_REQUEST_STATE_CLEANING;
-       spin_unlock_irqrestore(&req->lock, flags);
-
-       media_request_clean(req);
-
-       spin_lock_irqsave(&req->lock, flags);
-       req->state = MEDIA_REQUEST_STATE_IDLE;
-       spin_unlock_irqrestore(&req->lock, flags);
-
-       return 0;
-}
-
-static long media_request_ioctl(struct file *filp, unsigned int cmd,
-                               unsigned long arg)
-{
-       struct media_request *req = filp->private_data;
-
-       switch (cmd) {
-       case MEDIA_REQUEST_IOC_QUEUE:
-               return media_request_ioctl_queue(req);
-       case MEDIA_REQUEST_IOC_REINIT:
-               return media_request_ioctl_reinit(req);
-       default:
-               return -ENOIOCTLCMD;
-       }
-}
-
-static const struct file_operations request_fops = {
-       .owner = THIS_MODULE,
-       .poll = media_request_poll,
-       .unlocked_ioctl = media_request_ioctl,
-#ifdef CONFIG_COMPAT
-       .compat_ioctl = media_request_ioctl,
-#endif /* CONFIG_COMPAT */
-       .release = media_request_close,
-};
-
-struct media_request *
-media_request_get_by_fd(struct media_device *mdev, int request_fd)
-{
-       struct fd f;
-       struct media_request *req;
-
-       if (!mdev || !mdev->ops ||
-           !mdev->ops->req_validate || !mdev->ops->req_queue)
-               return ERR_PTR(-EBADR);
-
-       f = fdget(request_fd);
-       if (!f.file)
-               goto err_no_req_fd;
-
-       if (f.file->f_op != &request_fops)
-               goto err_fput;
-       req = f.file->private_data;
-       if (req->mdev != mdev)
-               goto err_fput;
-
-       /*
-        * Note: as long as someone has an open filehandle of the request,
-        * the request can never be released. The fdget() above ensures that
-        * even if userspace closes the request filehandle, the release()
-        * fop won't be called, so the media_request_get() always succeeds
-        * and there is no race condition where the request was released
-        * before media_request_get() is called.
-        */
-       media_request_get(req);
-       fdput(f);
-
-       return req;
-
-err_fput:
-       fdput(f);
-
-err_no_req_fd:
-       dev_dbg(mdev->dev, "cannot find request_fd %d\n", request_fd);
-       return ERR_PTR(-EINVAL);
-}
-EXPORT_SYMBOL_GPL(media_request_get_by_fd);
-
-int media_request_alloc(struct media_device *mdev, int *alloc_fd)
-{
-       struct media_request *req;
-       struct file *filp;
-       int fd;
-       int ret;
-
-       /* Either both are NULL or both are non-NULL */
-       if (WARN_ON(!mdev->ops->req_alloc ^ !mdev->ops->req_free))
-               return -ENOMEM;
-
-       fd = get_unused_fd_flags(O_CLOEXEC);
-       if (fd < 0)
-               return fd;
-
-       filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC);
-       if (IS_ERR(filp)) {
-               ret = PTR_ERR(filp);
-               goto err_put_fd;
-       }
-
-       if (mdev->ops->req_alloc)
-               req = mdev->ops->req_alloc(mdev);
-       else
-               req = kzalloc(sizeof(*req), GFP_KERNEL);
-       if (!req) {
-               ret = -ENOMEM;
-               goto err_fput;
-       }
-
-       filp->private_data = req;
-       req->mdev = mdev;
-       req->state = MEDIA_REQUEST_STATE_IDLE;
-       req->num_incomplete_objects = 0;
-       kref_init(&req->kref);
-       INIT_LIST_HEAD(&req->objects);
-       spin_lock_init(&req->lock);
-       init_waitqueue_head(&req->poll_wait);
-       req->updating_count = 0;
-       req->access_count = 0;
-
-       *alloc_fd = fd;
-
-       snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d",
-                atomic_inc_return(&mdev->request_id), fd);
-       dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str);
-
-       fd_install(fd, filp);
-
-       return 0;
-
-err_fput:
-       fput(filp);
-
-err_put_fd:
-       put_unused_fd(fd);
-
-       return ret;
-}
-
-static void media_request_object_release(struct kref *kref)
-{
-       struct media_request_object *obj =
-               container_of(kref, struct media_request_object, kref);
-       struct media_request *req = obj->req;
-
-       if (WARN_ON(req))
-               media_request_object_unbind(obj);
-       obj->ops->release(obj);
-}
-
-struct media_request_object *
-media_request_object_find(struct media_request *req,
-                         const struct media_request_object_ops *ops,
-                         void *priv)
-{
-       struct media_request_object *obj;
-       struct media_request_object *found = NULL;
-       unsigned long flags;
-
-       if (WARN_ON(!ops || !priv))
-               return NULL;
-
-       spin_lock_irqsave(&req->lock, flags);
-       list_for_each_entry(obj, &req->objects, list) {
-               if (obj->ops == ops && obj->priv == priv) {
-                       media_request_object_get(obj);
-                       found = obj;
-                       break;
-               }
-       }
-       spin_unlock_irqrestore(&req->lock, flags);
-       return found;
-}
-EXPORT_SYMBOL_GPL(media_request_object_find);
-
-void media_request_object_put(struct media_request_object *obj)
-{
-       kref_put(&obj->kref, media_request_object_release);
-}
-EXPORT_SYMBOL_GPL(media_request_object_put);
-
-void media_request_object_init(struct media_request_object *obj)
-{
-       obj->ops = NULL;
-       obj->req = NULL;
-       obj->priv = NULL;
-       obj->completed = false;
-       INIT_LIST_HEAD(&obj->list);
-       kref_init(&obj->kref);
-}
-EXPORT_SYMBOL_GPL(media_request_object_init);
-
-int media_request_object_bind(struct media_request *req,
-                             const struct media_request_object_ops *ops,
-                             void *priv, bool is_buffer,
-                             struct media_request_object *obj)
-{
-       unsigned long flags;
-       int ret = -EBUSY;
-
-       if (WARN_ON(!ops->release))
-               return -EBADR;
-
-       spin_lock_irqsave(&req->lock, flags);
-
-       if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING))
-               goto unlock;
-
-       obj->req = req;
-       obj->ops = ops;
-       obj->priv = priv;
-
-       if (is_buffer)
-               list_add_tail(&obj->list, &req->objects);
-       else
-               list_add(&obj->list, &req->objects);
-       req->num_incomplete_objects++;
-       ret = 0;
-
-unlock:
-       spin_unlock_irqrestore(&req->lock, flags);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(media_request_object_bind);
-
-void media_request_object_unbind(struct media_request_object *obj)
-{
-       struct media_request *req = obj->req;
-       unsigned long flags;
-       bool completed = false;
-
-       if (WARN_ON(!req))
-               return;
-
-       spin_lock_irqsave(&req->lock, flags);
-       list_del(&obj->list);
-       obj->req = NULL;
-
-       if (req->state == MEDIA_REQUEST_STATE_COMPLETE)
-               goto unlock;
-
-       if (WARN_ON(req->state == MEDIA_REQUEST_STATE_VALIDATING))
-               goto unlock;
-
-       if (req->state == MEDIA_REQUEST_STATE_CLEANING) {
-               if (!obj->completed)
-                       req->num_incomplete_objects--;
-               goto unlock;
-       }
-
-       if (WARN_ON(!req->num_incomplete_objects))
-               goto unlock;
-
-       req->num_incomplete_objects--;
-       if (req->state == MEDIA_REQUEST_STATE_QUEUED &&
-           !req->num_incomplete_objects) {
-               req->state = MEDIA_REQUEST_STATE_COMPLETE;
-               completed = true;
-               wake_up_interruptible_all(&req->poll_wait);
-       }
-
-unlock:
-       spin_unlock_irqrestore(&req->lock, flags);
-       if (obj->ops->unbind)
-               obj->ops->unbind(obj);
-       if (completed)
-               media_request_put(req);
-}
-EXPORT_SYMBOL_GPL(media_request_object_unbind);
-
-void media_request_object_complete(struct media_request_object *obj)
-{
-       struct media_request *req = obj->req;
-       unsigned long flags;
-       bool completed = false;
-
-       spin_lock_irqsave(&req->lock, flags);
-       if (obj->completed)
-               goto unlock;
-       obj->completed = true;
-       if (WARN_ON(!req->num_incomplete_objects) ||
-           WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED))
-               goto unlock;
-
-       if (!--req->num_incomplete_objects) {
-               req->state = MEDIA_REQUEST_STATE_COMPLETE;
-               wake_up_interruptible_all(&req->poll_wait);
-               completed = true;
-       }
-unlock:
-       spin_unlock_irqrestore(&req->lock, flags);
-       if (completed)
-               media_request_put(req);
-}
-EXPORT_SYMBOL_GPL(media_request_object_complete);