summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/media/media-device.h469
-rw-r--r--include/media/media-devnode.h54
-rw-r--r--include/media/media-entity.h904
-rw-r--r--include/media/tuner.h8
-rw-r--r--include/media/v4l2-dev.h1
-rw-r--r--include/uapi/linux/media.h228
6 files changed, 1581 insertions, 83 deletions
diff --git a/include/media/media-device.h b/include/media/media-device.h
index 6e6db78f1ee2..d3855898c3fc 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -30,6 +30,238 @@
#include <media/media-devnode.h>
#include <media/media-entity.h>
+/**
+ * DOC: Media Controller
+ *
+ * The media controller userspace API is documented in DocBook format in
+ * Documentation/DocBook/media/v4l/media-controller.xml. This document focus
+ * on the kernel-side implementation of the media framework.
+ *
+ * * Abstract media device model:
+ *
+ * Discovering a device internal topology, and configuring it at runtime, is one
+ * of the goals of the media framework. To achieve this, hardware devices are
+ * modelled as an oriented graph of building blocks called entities connected
+ * through pads.
+ *
+ * An entity is a basic media hardware building block. It can correspond to
+ * a large variety of logical blocks such as physical hardware devices
+ * (CMOS sensor for instance), logical hardware devices (a building block
+ * in a System-on-Chip image processing pipeline), DMA channels or physical
+ * connectors.
+ *
+ * A pad is a connection endpoint through which an entity can interact with
+ * other entities. Data (not restricted to video) produced by an entity
+ * flows from the entity's output to one or more entity inputs. Pads should
+ * not be confused with physical pins at chip boundaries.
+ *
+ * A link is a point-to-point oriented connection between two pads, either
+ * on the same entity or on different entities. Data flows from a source
+ * pad to a sink pad.
+ *
+ *
+ * * Media device:
+ *
+ * A media device is represented by a struct &media_device instance, defined in
+ * include/media/media-device.h. Allocation of the structure is handled by the
+ * media device driver, usually by embedding the &media_device instance in a
+ * larger driver-specific structure.
+ *
+ * Drivers register media device instances by calling
+ * __media_device_register() via the macro media_device_register()
+ * and unregistered by calling
+ * media_device_unregister().
+ *
+ * * Entities, pads and links:
+ *
+ * - Entities
+ *
+ * Entities are represented by a struct &media_entity instance, defined in
+ * include/media/media-entity.h. The structure is usually embedded into a
+ * higher-level structure, such as a v4l2_subdev or video_device instance,
+ * although drivers can allocate entities directly.
+ *
+ * Drivers initialize entity pads by calling
+ * media_entity_pads_init().
+ *
+ * Drivers register entities with a media device by calling
+ * media_device_register_entity()
+ * and unregistred by calling
+ * media_device_unregister_entity().
+ *
+ * - Interfaces
+ *
+ * Interfaces are represented by a struct &media_interface instance, defined in
+ * include/media/media-entity.h. Currently, only one type of interface is
+ * defined: a device node. Such interfaces are represented by a struct
+ * &media_intf_devnode.
+ *
+ * Drivers initialize and create device node interfaces by calling
+ * media_devnode_create()
+ * and remove them by calling:
+ * media_devnode_remove().
+ *
+ * - Pads
+ *
+ * Pads are represented by a struct &media_pad instance, defined in
+ * include/media/media-entity.h. Each entity stores its pads in a pads array
+ * managed by the entity driver. Drivers usually embed the array in a
+ * driver-specific structure.
+ *
+ * Pads are identified by their entity and their 0-based index in the pads
+ * array.
+ * Both information are stored in the &media_pad structure, making the
+ * &media_pad pointer the canonical way to store and pass link references.
+ *
+ * Pads have flags that describe the pad capabilities and state.
+ *
+ * %MEDIA_PAD_FL_SINK indicates that the pad supports sinking data.
+ * %MEDIA_PAD_FL_SOURCE indicates that the pad supports sourcing data.
+ *
+ * NOTE: One and only one of %MEDIA_PAD_FL_SINK and %MEDIA_PAD_FL_SOURCE must
+ * be set for each pad.
+ *
+ * - Links
+ *
+ * Links are represented by a struct &media_link instance, defined in
+ * include/media/media-entity.h. There are two types of links:
+ *
+ * 1. pad to pad links:
+ *
+ * Associate two entities via their PADs. Each entity has a list that points
+ * to all links originating at or targeting any of its pads.
+ * A given link is thus stored twice, once in the source entity and once in
+ * the target entity.
+ *
+ * Drivers create pad to pad links by calling:
+ * media_create_pad_link() and remove with media_entity_remove_links().
+ *
+ * 2. interface to entity links:
+ *
+ * Associate one interface to a Link.
+ *
+ * Drivers create interface to entity links by calling:
+ * media_create_intf_link() and remove with media_remove_intf_links().
+ *
+ * NOTE:
+ *
+ * Links can only be created after having both ends already created.
+ *
+ * Links have flags that describe the link capabilities and state. The
+ * valid values are described at media_create_pad_link() and
+ * media_create_intf_link().
+ *
+ * Graph traversal:
+ *
+ * The media framework provides APIs to iterate over entities in a graph.
+ *
+ * To iterate over all entities belonging to a media device, drivers can use
+ * the media_device_for_each_entity macro, defined in
+ * include/media/media-device.h.
+ *
+ * struct media_entity *entity;
+ *
+ * media_device_for_each_entity(entity, mdev) {
+ * // entity will point to each entity in turn
+ * ...
+ * }
+ *
+ * Drivers might also need to iterate over all entities in a graph that can be
+ * reached only through enabled links starting at a given entity. The media
+ * framework provides a depth-first graph traversal API for that purpose.
+ *
+ * Note that graphs with cycles (whether directed or undirected) are *NOT*
+ * supported by the graph traversal API. To prevent infinite loops, the graph
+ * traversal code limits the maximum depth to MEDIA_ENTITY_ENUM_MAX_DEPTH,
+ * currently defined as 16.
+ *
+ * Drivers initiate a graph traversal by calling
+ * media_entity_graph_walk_start()
+ *
+ * The graph structure, provided by the caller, is initialized to start graph
+ * traversal at the given entity.
+ *
+ * Drivers can then retrieve the next entity by calling
+ * media_entity_graph_walk_next()
+ *
+ * When the graph traversal is complete the function will return NULL.
+ *
+ * Graph traversal can be interrupted at any moment. No cleanup function call
+ * is required and the graph structure can be freed normally.
+ *
+ * Helper functions can be used to find a link between two given pads, or a pad
+ * connected to another pad through an enabled link
+ * media_entity_find_link() and media_entity_remote_pad()
+ *
+ * Use count and power handling:
+ *
+ * Due to the wide differences between drivers regarding power management
+ * needs, the media controller does not implement power management. However,
+ * the &media_entity structure includes a use_count field that media drivers
+ * can use to track the number of users of every entity for power management
+ * needs.
+ *
+ * The &media_entity.@use_count field is owned by media drivers and must not be
+ * touched by entity drivers. Access to the field must be protected by the
+ * &media_device.@graph_mutex lock.
+ *
+ * Links setup:
+ *
+ * Link properties can be modified at runtime by calling
+ * media_entity_setup_link()
+ *
+ * Pipelines and media streams:
+ *
+ * When starting streaming, drivers must notify all entities in the pipeline to
+ * prevent link states from being modified during streaming by calling
+ * media_entity_pipeline_start().
+ *
+ * The function will mark all entities connected to the given entity through
+ * enabled links, either directly or indirectly, as streaming.
+ *
+ * The &media_pipeline instance pointed to by the pipe argument will be stored
+ * in every entity in the pipeline. Drivers should embed the &media_pipeline
+ * structure in higher-level pipeline structures and can then access the
+ * pipeline through the &media_entity pipe field.
+ *
+ * Calls to media_entity_pipeline_start() can be nested. The pipeline pointer
+ * must be identical for all nested calls to the function.
+ *
+ * media_entity_pipeline_start() may return an error. In that case, it will
+ * clean up any of the changes it did by itself.
+ *
+ * When stopping the stream, drivers must notify the entities with
+ * media_entity_pipeline_stop().
+ *
+ * If multiple calls to media_entity_pipeline_start() have been made the same
+ * number of media_entity_pipeline_stop() calls are required to stop streaming.
+ * The &media_entity pipe field is reset to NULL on the last nested stop call.
+ *
+ * Link configuration will fail with -%EBUSY by default if either end of the
+ * link is a streaming entity. Links that can be modified while streaming must
+ * be marked with the %MEDIA_LNK_FL_DYNAMIC flag.
+ *
+ * If other operations need to be disallowed on streaming entities (such as
+ * changing entities configuration parameters) drivers can explicitly check the
+ * media_entity stream_count field to find out if an entity is streaming. This
+ * operation must be done with the media_device graph_mutex held.
+ *
+ * Link validation:
+ *
+ * Link validation is performed by media_entity_pipeline_start() for any
+ * entity which has sink pads in the pipeline. The
+ * &media_entity.@link_validate() callback is used for that purpose. In
+ * @link_validate() callback, entity driver should check that the properties of
+ * the source pad of the connected entity and its own sink pad match. It is up
+ * to the type of the entity (and in the end, the properties of the hardware)
+ * what matching actually means.
+ *
+ * Subsystems should facilitate link validation by providing subsystem specific
+ * helper functions to provide easy access for commonly needed information, and
+ * in the end provide a way to use driver-specific callbacks.
+ */
+
+struct ida;
struct device;
/**
@@ -41,8 +273,16 @@ struct device;
* @bus_info: Unique and stable device location identifier
* @hw_revision: Hardware device revision
* @driver_version: Device driver version
- * @entity_id: ID of the next entity to be registered
+ * @topology_version: Monotonic counter for storing the version of the graph
+ * topology. Should be incremented each time the topology changes.
+ * @id: Unique ID used on the last registered graph object
+ * @entity_internal_idx: Unique internal entity ID used by the graph traversal
+ * algorithms
+ * @entity_internal_idx_max: Allocated internal entity indices
* @entities: List of registered entities
+ * @interfaces: List of registered interfaces
+ * @pads: List of registered pads
+ * @links: List of registered links
* @lock: Entities list lock
* @graph_mutex: Entities graph operation lock
* @link_notify: Link state change notification callback
@@ -68,10 +308,18 @@ struct media_device {
u32 hw_revision;
u32 driver_version;
- u32 entity_id;
+ u32 topology_version;
+
+ u32 id;
+ struct ida entity_internal_idx;
+ int entity_internal_idx_max;
+
struct list_head entities;
+ struct list_head interfaces;
+ struct list_head pads;
+ struct list_head links;
- /* Protects the entities list */
+ /* Protects the graph objects creation/removal */
spinlock_t lock;
/* Serializes graph operations. */
struct mutex graph_mutex;
@@ -80,6 +328,8 @@ struct media_device {
unsigned int notification);
};
+#ifdef CONFIG_MEDIA_CONTROLLER
+
/* Supported link_notify @notification values. */
#define MEDIA_DEV_NOTIFY_PRE_LINK_CH 0
#define MEDIA_DEV_NOTIFY_POST_LINK_CH 1
@@ -87,17 +337,228 @@ struct media_device {
/* media_devnode to media_device */
#define to_media_device(node) container_of(node, struct media_device, devnode)
+/**
+ * media_entity_enum_init - Initialise an entity enumeration
+ *
+ * @ent_enum: Entity enumeration to be initialised
+ * @mdev: The related media device
+ *
+ * Returns zero on success or a negative error code.
+ */
+static inline __must_check int media_entity_enum_init(
+ struct media_entity_enum *ent_enum, struct media_device *mdev)
+{
+ return __media_entity_enum_init(ent_enum,
+ mdev->entity_internal_idx_max + 1);
+}
+
+/**
+ * media_device_init() - Initializes a media device element
+ *
+ * @mdev: pointer to struct &media_device
+ *
+ * This function initializes the media device prior to its registration.
+ * The media device initialization and registration is split in two functions
+ * to avoid race conditions and make the media device available to user-space
+ * before the media graph has been completed.
+ *
+ * So drivers need to first initialize the media device, register any entity
+ * within the media device, create pad to pad links and then finally register
+ * the media device by calling media_device_register() as a final step.
+ */
+void media_device_init(struct media_device *mdev);
+
+/**
+ * media_device_cleanup() - Cleanups a media device element
+ *
+ * @mdev: pointer to struct &media_device
+ *
+ * This function that will destroy the graph_mutex that is
+ * initialized in media_device_init().
+ */
+void media_device_cleanup(struct media_device *mdev);
+
+/**
+ * __media_device_register() - Registers a media device element
+ *
+ * @mdev: pointer to struct &media_device
+ * @owner: should be filled with %THIS_MODULE
+ *
+ * Users, should, instead, call the media_device_register() macro.
+ *
+ * The caller is responsible for initializing the media_device structure before
+ * registration. The following fields must be set:
+ *
+ * - dev must point to the parent device (usually a &pci_dev, &usb_interface or
+ * &platform_device instance).
+ *
+ * - model must be filled with the device model name as a NUL-terminated UTF-8
+ * string. The device/model revision must not be stored in this field.
+ *
+ * The following fields are optional:
+ *
+ * - serial is a unique serial number stored as a NUL-terminated ASCII string.
+ * The field is big enough to store a GUID in text form. If the hardware
+ * doesn't provide a unique serial number this field must be left empty.
+ *
+ * - bus_info represents the location of the device in the system as a
+ * NUL-terminated ASCII string. For PCI/PCIe devices bus_info must be set to
+ * "PCI:" (or "PCIe:") followed by the value of pci_name(). For USB devices,
+ * the usb_make_path() function must be used. This field is used by
+ * applications to distinguish between otherwise identical devices that don't
+ * provide a serial number.
+ *
+ * - hw_revision is the hardware device revision in a driver-specific format.
+ * When possible the revision should be formatted with the KERNEL_VERSION
+ * macro.
+ *
+ * - driver_version is formatted with the KERNEL_VERSION macro. The version
+ * minor must be incremented when new features are added to the userspace API
+ * without breaking binary compatibility. The version major must be
+ * incremented when binary compatibility is broken.
+ *
+ * Notes:
+ *
+ * Upon successful registration a character device named media[0-9]+ is created.
+ * The device major and minor numbers are dynamic. The model name is exported as
+ * a sysfs attribute.
+ *
+ * Unregistering a media device that hasn't been registered is *NOT* safe.
+ *
+ * Return: returns zero on success or a negative error code.
+ */
int __must_check __media_device_register(struct media_device *mdev,
struct module *owner);
#define media_device_register(mdev) __media_device_register(mdev, THIS_MODULE)
+
+/**
+ * __media_device_unregister() - Unegisters a media device element
+ *
+ * @mdev: pointer to struct &media_device
+ *
+ *
+ * It is safe to call this function on an unregistered (but initialised)
+ * media device.
+ */
void media_device_unregister(struct media_device *mdev);
+/**
+ * media_device_register_entity() - registers a media entity inside a
+ * previously registered media device.
+ *
+ * @mdev: pointer to struct &media_device
+ * @entity: pointer to struct &media_entity to be registered
+ *
+ * Entities are identified by a unique positive integer ID. The media
+ * controller framework will such ID automatically. IDs are not guaranteed
+ * to be contiguous, and the ID number can change on newer Kernel versions.
+ * So, neither the driver nor userspace should hardcode ID numbers to refer
+ * to the entities, but, instead, use the framework to find the ID, when
+ * needed.
+ *
+ * The media_entity name, type and flags fields should be initialized before
+ * calling media_device_register_entity(). Entities embedded in higher-level
+ * standard structures can have some of those fields set by the higher-level
+ * framework.
+ *
+ * If the device has pads, media_entity_pads_init() should be called before
+ * this function. Otherwise, the &media_entity.@pad and &media_entity.@num_pads
+ * should be zeroed before calling this function.
+ *
+ * Entities have flags that describe the entity capabilities and state:
+ *
+ * %MEDIA_ENT_FL_DEFAULT indicates the default entity for a given type.
+ * This can be used to report the default audio and video devices or the
+ * default camera sensor.
+ *
+ * NOTE: Drivers should set the entity function before calling this function.
+ * Please notice that the values %MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN and
+ * %MEDIA_ENT_F_UNKNOWN should not be used by the drivers.
+ */
int __must_check media_device_register_entity(struct media_device *mdev,
struct media_entity *entity);
+
+/*
+ * media_device_unregister_entity() - unregisters a media entity.
+ *
+ * @entity: pointer to struct &media_entity to be unregistered
+ *
+ * All links associated with the entity and all PADs are automatically
+ * unregistered from the media_device when this function is called.
+ *
+ * Unregistering an entity will not change the IDs of the other entities and
+ * the previoully used ID will never be reused for a newly registered entities.
+ *
+ * When a media device is unregistered, all its entities are unregistered
+ * automatically. No manual entities unregistration is then required.
+ *
+ * Note: the media_entity instance itself must be freed explicitly by
+ * the driver if required.
+ */
void media_device_unregister_entity(struct media_entity *entity);
+/**
+ * media_device_get_devres() - get media device as device resource
+ * creates if one doesn't exist
+ *
+ * @dev: pointer to struct &device.
+ *
+ * Sometimes, the media controller &media_device needs to be shared by more
+ * than one driver. This function adds support for that, by dynamically
+ * allocating the &media_device and allowing it to be obtained from the
+ * struct &device associated with the common device where all sub-device
+ * components belong. So, for example, on an USB device with multiple
+ * interfaces, each interface may be handled by a separate per-interface
+ * drivers. While each interface have its own &device, they all share a
+ * common &device associated with the hole USB device.
+ */
+struct media_device *media_device_get_devres(struct device *dev);
+
+/**
+ * media_device_find_devres() - find media device as device resource
+ *
+ * @dev: pointer to struct &device.
+ */
+struct media_device *media_device_find_devres(struct device *dev);
+
/* Iterate over all entities. */
#define media_device_for_each_entity(entity, mdev) \
- list_for_each_entry(entity, &(mdev)->entities, list)
+ list_for_each_entry(entity, &(mdev)->entities, graph_obj.list)
+
+/* Iterate over all interfaces. */
+#define media_device_for_each_intf(intf, mdev) \
+ list_for_each_entry(intf, &(mdev)->interfaces, graph_obj.list)
+
+/* Iterate over all pads. */
+#define media_device_for_each_pad(pad, mdev) \
+ list_for_each_entry(pad, &(mdev)->pads, graph_obj.list)
+/* Iterate over all links. */
+#define media_device_for_each_link(link, mdev) \
+ list_for_each_entry(link, &(mdev)->links, graph_obj.list)
+#else
+static inline int media_device_register(struct media_device *mdev)
+{
+ return 0;
+}
+static inline void media_device_unregister(struct media_device *mdev)
+{
+}
+static inline int media_device_register_entity(struct media_device *mdev,
+ struct media_entity *entity)
+{
+ return 0;
+}
+static inline void media_device_unregister_entity(struct media_entity *entity)
+{
+}
+static inline struct media_device *media_device_get_devres(struct device *dev)
+{
+ return NULL;
+}
+static inline struct media_device *media_device_find_devres(struct device *dev)
+{
+ return NULL;
+}
+#endif /* CONFIG_MEDIA_CONTROLLER */
#endif
diff --git a/include/media/media-devnode.h b/include/media/media-devnode.h
index 17ddae32060d..fe42f08e72bd 100644
--- a/include/media/media-devnode.h
+++ b/include/media/media-devnode.h
@@ -40,6 +40,20 @@
*/
#define MEDIA_FLAG_REGISTERED 0
+/**
+ * struct media_file_operations - Media device file operations
+ *
+ * @owner: should be filled with %THIS_MODULE
+ * @read: pointer to the function that implements read() syscall
+ * @write: pointer to the function that implements write() syscall
+ * @poll: pointer to the function that implements poll() syscall
+ * @ioctl: pointer to the function that implements ioctl() syscall
+ * @compat_ioctl: pointer to the function that will handle 32 bits userspace
+ * calls to the the ioctl() syscall on a Kernel compiled with 64 bits.
+ * @open: pointer to the function that implements open() syscall
+ * @release: pointer to the function that will release the resources allocated
+ * by the @open function.
+ */
struct media_file_operations {
struct module *owner;
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
@@ -53,7 +67,7 @@ struct media_file_operations {
/**
* struct media_devnode - Media device node
- * @fops: pointer to struct media_file_operations with media device ops
+ * @fops: pointer to struct &media_file_operations with media device ops
* @dev: struct device pointer for the media controller device
* @cdev: struct cdev pointer character device
* @parent: parent device
@@ -86,15 +100,53 @@ struct media_devnode {
/* dev to media_devnode */
#define to_media_devnode(cd) container_of(cd, struct media_devnode, dev)
+/**
+ * media_devnode_register - register a media device node
+ *
+ * @mdev: media device node structure we want to register
+ * @owner: should be filled with %THIS_MODULE
+ *
+ * The registration code assigns minor numbers and registers the new device node
+ * with the kernel. An error is returned if no free minor number can be found,
+ * or if the registration of the device node fails.
+ *
+ * Zero is returned on success.
+ *
+ * Note that if the media_devnode_register call fails, the release() callback of
+ * the media_devnode structure is *not* called, so the caller is responsible for
+ * freeing any data.
+ */
int __must_check media_devnode_register(struct media_devnode *mdev,
struct module *owner);
+
+/**
+ * media_devnode_unregister - unregister a media device node
+ * @mdev: the device node to unregister
+ *
+ * This unregisters the passed device. Future open calls will be met with
+ * errors.
+ *
+ * This function can safely be called if the device node has never been
+ * registered or has already been unregistered.
+ */
void media_devnode_unregister(struct media_devnode *mdev);
+/**
+ * media_devnode_data - returns a pointer to the &media_devnode
+ *
+ * @filp: pointer to struct &file
+ */
static inline struct media_devnode *media_devnode_data(struct file *filp)
{
return filp->private_data;
}
+/**
+ * media_devnode_is_registered - returns true if &media_devnode is registered;
+ * false otherwise.
+ *
+ * @mdev: pointer to struct &media_devnode.
+ */
static inline int media_devnode_is_registered(struct media_devnode *mdev)
{
return test_bit(MEDIA_FLAG_REGISTERED, &mdev->flags);
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 197f93799753..fe485d367985 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -23,25 +23,151 @@
#ifndef _MEDIA_ENTITY_H
#define _MEDIA_ENTITY_H
-#include <linux/bitops.h>
+#include <linux/bitmap.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/media.h>
+/* Enums used internally at the media controller to represent graphs */
+
+/**
+ * enum media_gobj_type - type of a graph object
+ *
+ * @MEDIA_GRAPH_ENTITY: Identify a media entity
+ * @MEDIA_GRAPH_PAD: Identify a media pad
+ * @MEDIA_GRAPH_LINK: Identify a media link
+ * @MEDIA_GRAPH_INTF_DEVNODE: Identify a media Kernel API interface via
+ * a device node
+ */
+enum media_gobj_type {
+ MEDIA_GRAPH_ENTITY,
+ MEDIA_GRAPH_PAD,
+ MEDIA_GRAPH_LINK,
+ MEDIA_GRAPH_INTF_DEVNODE,
+};
+
+#define MEDIA_BITS_PER_TYPE 8
+#define MEDIA_BITS_PER_ID (32 - MEDIA_BITS_PER_TYPE)
+#define MEDIA_ID_MASK GENMASK_ULL(MEDIA_BITS_PER_ID - 1, 0)
+
+/* Structs to represent the objects that belong to a media graph */
+
+/**
+ * struct media_gobj - Define a graph object.
+ *
+ * @mdev: Pointer to the struct media_device that owns the object
+ * @id: Non-zero object ID identifier. The ID should be unique
+ * inside a media_device, as it is composed by
+ * %MEDIA_BITS_PER_TYPE to store the type plus
+ * %MEDIA_BITS_PER_ID to store the ID
+ * @list: List entry stored in one of the per-type mdev object lists
+ *
+ * All objects on the media graph should have this struct embedded
+ */
+struct media_gobj {
+ struct media_device *mdev;
+ u32 id;
+ struct list_head list;
+};
+
+#define MEDIA_ENTITY_ENUM_MAX_DEPTH 16
+
+/**
+ * struct media_entity_enum - An enumeration of media entities.
+ *
+ * @bmap: Bit map in which each bit represents one entity at struct
+ * media_entity->internal_idx.
+ * @idx_max: Number of bits in bmap
+ */
+struct media_entity_enum {
+ unsigned long *bmap;
+ int idx_max;
+};
+
+/**
+ * struct media_entity_graph - Media graph traversal state
+ *
+ * @stack: Graph traversal stack; the stack contains information
+ * on the path the media entities to be walked and the
+ * links through which they were reached.
+ * @ent_enum: Visited entities
+ * @top: The top of the stack
+ */
+struct media_entity_graph {
+ struct {
+ struct media_entity *entity;
+ struct list_head *link;
+ } stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
+
+ struct media_entity_enum ent_enum;
+ int top;
+};
+
+/*
+ * struct media_pipeline - Media pipeline related information
+ *
+ * @streaming_count: Streaming start count - streaming stop count
+ * @graph: Media graph walk during pipeline start / stop
+ */
struct media_pipeline {
+ int streaming_count;
+ struct media_entity_graph graph;
};
+/**
+ * struct media_link - A link object part of a media graph.
+ *
+ * @graph_obj: Embedded structure containing the media object common data
+ * @list: Linked list associated with an entity or an interface that
+ * owns the link.
+ * @gobj0: Part of a union. Used to get the pointer for the first
+ * graph_object of the link.
+ * @source: Part of a union. Used only if the first object (gobj0) is
+ * a pad. In that case, it represents the source pad.
+ * @intf: Part of a union. Used only if the first object (gobj0) is
+ * an interface.
+ * @gobj1: Part of a union. Used to get the pointer for the second
+ * graph_object of the link.
+ * @source: Part of a union. Used only if the second object (gobj1) is
+ * a pad. In that case, it represents the sink pad.
+ * @entity: Part of a union. Used only if the second object (gobj1) is
+ * an entity.
+ * @reverse: Pointer to the link for the reverse direction of a pad to pad
+ * link.
+ * @flags: Link flags, as defined in uapi/media.h (MEDIA_LNK_FL_*)
+ * @is_backlink: Indicate if the link is a backlink.
+ */
struct media_link {
- struct media_pad *source; /* Source pad */
- struct media_pad *sink; /* Sink pad */
- struct media_link *reverse; /* Link in the reverse direction */
- unsigned long flags; /* Link flags (MEDIA_LNK_FL_*) */
+ struct media_gobj graph_obj;
+ struct list_head list;
+ union {
+ struct media_gobj *gobj0;
+ struct media_pad *source;
+ struct media_interface *intf;
+ };
+ union {
+ struct media_gobj *gobj1;
+ struct media_pad *sink;
+ struct media_entity *entity;
+ };
+ struct media_link *reverse;
+ unsigned long flags;
+ bool is_backlink;
};
+/**
+ * struct media_pad - A media pad graph object.
+ *
+ * @graph_obj: Embedded structure containing the media object common data
+ * @entity: Entity this pad belongs to
+ * @index: Pad index in the entity pads array, numbered from 0 to n
+ * @flags: Pad flags, as defined in uapi/media.h (MEDIA_PAD_FL_*)
+ */
struct media_pad {
- struct media_entity *entity; /* Entity this pad belongs to */
- u16 index; /* Pad index in the entity pads array */
- unsigned long flags; /* Pad flags (MEDIA_PAD_FL_*) */
+ struct media_gobj graph_obj; /* must be first field in struct */
+ struct media_entity *entity;
+ u16 index;
+ unsigned long flags;
};
/**
@@ -60,105 +186,763 @@ struct media_entity_operations {
int (*link_validate)(struct media_link *link);
};
+/**
+ * struct media_entity - A media entity graph object.
+ *
+ * @graph_obj: Embedded structure containing the media object common data.
+ * @name: Entity name.
+ * @function: Entity main function, as defined in uapi/media.h
+ * (MEDIA_ENT_F_*)
+ * @flags: Entity flags, as defined in uapi/media.h (MEDIA_ENT_FL_*)
+ * @num_pads: Number of sink and source pads.
+ * @num_links: Total number of links, forward and back, enabled and disabled.
+ * @num_backlinks: Number of backlinks
+ * @internal_idx: An unique internal entity specific number. The numbers are
+ * re-used if entities are unregistered or registered again.
+ * @pads: Pads array with the size defined by @num_pads.
+ * @links: List of data links.
+ * @ops: Entity operations.
+ * @stream_count: Stream count for the entity.
+ * @use_count: Use count for the entity.
+ * @pipe: Pipeline this entity belongs to.
+ * @info: Union with devnode information. Kept just for backward
+ * compatibility.
+ * @major: Devnode major number (zero if not applicable). Kept just
+ * for backward compatibility.
+ * @minor: Devnode minor number (zero if not applicable). Kept just
+ * for backward compatibility.
+ *
+ * NOTE: @stream_count and @use_count reference counts must never be
+ * negative, but are signed integers on purpose: a simple WARN_ON(<0) check
+ * can be used to detect reference count bugs that would make them negative.
+ */
struct media_entity {
- struct list_head list;
- struct media_device *parent; /* Media device this entity belongs to*/
- u32 id; /* Entity ID, unique in the parent media
- * device context */
- const char *name; /* Entity name */
- u32 type; /* Entity type (MEDIA_ENT_T_*) */
- u32 revision; /* Entity revision, driver specific */
- unsigned long flags; /* Entity flags (MEDIA_ENT_FL_*) */
- u32 group_id; /* Entity group ID */
-
- u16 num_pads; /* Number of sink and source pads */
- u16 num_links; /* Number of existing links, both
- * enabled and disabled */
- u16 num_backlinks; /* Number of backlinks */
- u16 max_links; /* Maximum number of links */
-
- struct media_pad *pads; /* Pads array (num_pads elements) */
- struct media_link *links; /* Links array (max_links elements)*/
-
- const struct media_entity_operations *ops; /* Entity operations */
+ struct media_gobj graph_obj; /* must be first field in struct */
+ const char *name;
+ u32 function;
+ unsigned long flags;
+
+ u16 num_pads;
+ u16 num_links;
+ u16 num_backlinks;
+ int internal_idx;
+
+ struct media_pad *pads;
+ struct list_head links;
+
+ const struct media_entity_operations *ops;
/* Reference counts must never be negative, but are signed integers on
* purpose: a simple WARN_ON(<0) check can be used to detect reference
* count bugs that would make them negative.
*/
- int stream_count; /* Stream count for the entity. */
- int use_count; /* Use count for the entity. */
+ int stream_count;
+ int use_count;
- struct media_pipeline *pipe; /* Pipeline this entity belongs to. */
+ struct media_pipeline *pipe;
union {
- /* Node specifications */
struct {
u32 major;
u32 minor;
} dev;
-
- /* Sub-device specifications */
- /* Nothing needed yet */
} info;
};
-static inline u32 media_entity_type(struct media_entity *entity)
+/**
+ * struct media_interface - A media interface graph object.
+ *
+ * @graph_obj: embedded graph object
+ * @links: List of links pointing to graph entities
+ * @type: Type of the interface as defined in the
+ * uapi/media/media.h header, e. g.
+ * MEDIA_INTF_T_*
+ * @flags: Interface flags as defined in uapi/media/media.h
+ */
+struct media_interface {
+ struct media_gobj graph_obj;
+ struct list_head links;
+ u32 type;
+ u32 flags;
+};
+
+/**
+ * struct media_intf_devnode - A media interface via a device node.
+ *
+ * @intf: embedded interface object
+ * @major: Major number of a device node
+ * @minor: Minor number of a device node
+ */
+struct media_intf_devnode {
+ struct media_interface intf;
+
+ /* Should match the fields at media_v2_intf_devnode */
+ u32 major;
+ u32 minor;
+};
+
+/**
+ * media_entity_id() - return the media entity graph object id
+ *
+ * @entity: pointer to entity
+ */
+static inline u32 media_entity_id(struct media_entity *entity)
{
- return entity->type & MEDIA_ENT_TYPE_MASK;
+ return entity->graph_obj.id;
}
-static inline u32 media_entity_subtype(struct media_entity *entity)
+/**
+ * media_type() - return the media object type
+ *
+ * @gobj: pointer to the media graph object
+ */
+static inline enum media_gobj_type media_type(struct media_gobj *gobj)
{
- return entity->type & MEDIA_ENT_SUBTYPE_MASK;
+ return gobj->id >> MEDIA_BITS_PER_ID;
}
-#define MEDIA_ENTITY_ENUM_MAX_DEPTH 16
-#define MEDIA_ENTITY_ENUM_MAX_ID 64
+/**
+ * media_id() - return the media object ID
+ *
+ * @gobj: pointer to the media graph object
+ */
+static inline u32 media_id(struct media_gobj *gobj)
+{
+ return gobj->id & MEDIA_ID_MASK;
+}
-/*
- * The number of pads can't be bigger than the number of entities,
- * as the worse-case scenario is to have one entity linked up to
- * MEDIA_ENTITY_ENUM_MAX_ID - 1 entities.
+/**
+ * media_gobj_gen_id() - encapsulates type and ID on at the object ID
+ *
+ * @type: object type as define at enum &media_gobj_type.
+ * @local_id: next ID, from struct &media_device.@id.
*/
-#define MEDIA_ENTITY_MAX_PADS (MEDIA_ENTITY_ENUM_MAX_ID - 1)
+static inline u32 media_gobj_gen_id(enum media_gobj_type type, u64 local_id)
+{
+ u32 id;
-struct media_entity_graph {
- struct {
- struct media_entity *entity;
- int link;
- } stack[MEDIA_ENTITY_ENUM_MAX_DEPTH];
+ id = type << MEDIA_BITS_PER_ID;
+ id |= local_id & MEDIA_ID_MASK;
- DECLARE_BITMAP(entities, MEDIA_ENTITY_ENUM_MAX_ID);
- int top;
-};
+ return id;
+}
+
+/**
+ * is_media_entity_v4l2_io() - identify if the entity main function
+ * is a V4L2 I/O
+ *
+ * @entity: pointer to entity
+ *
+ * Return: true if the entity main function is one of the V4L2 I/O types
+ * (video, VBI or SDR radio); false otherwise.
+ */
+static inline bool is_media_entity_v4l2_io(struct media_entity *entity)
+{
+ if (!entity)
+ return false;
+
+ switch (entity->function) {
+ case MEDIA_ENT_F_IO_V4L:
+ case MEDIA_ENT_F_IO_VBI:
+ case MEDIA_ENT_F_IO_SWRADIO:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * is_media_entity_v4l2_subdev - return true if the entity main function is
+ * associated with the V4L2 API subdev usage
+ *
+ * @entity: pointer to entity
+ *
+ * This is an ancillary function used by subdev-based V4L2 drivers.
+ * It checks if the entity function is one of functions used by a V4L2 subdev,
+ * e. g. camera-relatef functions, analog TV decoder, TV tuner, V4L2 DSPs.
+ */
+static inline bool is_media_entity_v4l2_subdev(struct media_entity *entity)
+{
+ if (!entity)
+ return false;
+
+ switch (entity->function) {
+ case MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN:
+ case MEDIA_ENT_F_CAM_SENSOR:
+ case MEDIA_ENT_F_FLASH:
+ case MEDIA_ENT_F_LENS:
+ case MEDIA_ENT_F_ATV_DECODER:
+ case MEDIA_ENT_F_TUNER:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/**
+ * __media_entity_enum_init - Initialise an entity enumeration
+ *
+ * @ent_enum: Entity enumeration to be initialised
+ * @idx_max: Maximum number of entities in the enumeration
+ *
+ * Return: Returns zero on success or a negative error code.
+ */
+__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum,
+ int idx_max);
+
+/**
+ * media_entity_enum_cleanup - Release resources of an entity enumeration
+ *
+ * @ent_enum: Entity enumeration to be released
+ */
+void media_entity_enum_cleanup(struct media_entity_enum *ent_enum);
+
+/**
+ * media_entity_enum_zero - Clear the entire enum
+ *
+ * @ent_enum: Entity enumeration to be cleared
+ */
+static inline void media_entity_enum_zero(struct media_entity_enum *ent_enum)
+{
+ bitmap_zero(ent_enum->bmap, ent_enum->idx_max);
+}
+
+/**
+ * media_entity_enum_set - Mark a single entity in the enum
+ *
+ * @ent_enum: Entity enumeration
+ * @entity: Entity to be marked
+ */
+static inline void media_entity_enum_set(struct media_entity_enum *ent_enum,
+ struct media_entity *entity)
+{
+ if (WARN_ON(entity->internal_idx >= ent_enum->idx_max))
+ return;
+
+ __set_bit(entity->internal_idx, ent_enum->bmap);
+}
+
+/**
+ * media_entity_enum_clear - Unmark a single entity in the enum
+ *
+ * @ent_enum: Entity enumeration
+ * @entity: Entity to be unmarked
+ */
+static inline void media_entity_enum_clear(struct media_entity_enum *ent_enum,
+ struct media_entity *entity)
+{
+ if (WARN_ON(entity->internal_idx >= ent_enum->idx_max))
+ return;
-int media_entity_init(struct media_entity *entity, u16 num_pads,
- struct media_pad *pads, u16 extra_links);
-void media_entity_cleanup(struct media_entity *entity);
+ __clear_bit(entity->internal_idx, ent_enum->bmap);
+}
+
+/**
+ * media_entity_enum_test - Test whether the entity is marked
+ *
+ * @ent_enum: Entity enumeration
+ * @entity: Entity to be tested
+ *
+ * Returns true if the entity was marked.
+ */
+static inline bool media_entity_enum_test(struct media_entity_enum *ent_enum,
+ struct media_entity *entity)
+{
+ if (WARN_ON(entity->internal_idx >= ent_enum->idx_max))
+ return true;
+
+ return test_bit(entity->internal_idx, ent_enum->bmap);
+}
+
+/**
+ * media_entity_enum_test - Test whether the entity is marked, and mark it
+ *
+ * @ent_enum: Entity enumeration
+ * @entity: Entity to be tested
+ *
+ * Returns true if the entity was marked, and mark it before doing so.
+ */
+static inline bool
+media_entity_enum_test_and_set(struct media_entity_enum *ent_enum,
+ struct media_entity *entity)
+{
+ if (WARN_ON(entity->internal_idx >= ent_enum->idx_max))
+ return true;
+
+ return __test_and_set_bit(entity->internal_idx, ent_enum->bmap);
+}
+
+/**
+ * media_entity_enum_empty - Test whether the entire enum is empty
+ *
+ * @ent_enum: Entity enumeration
+ *
+ * Returns true if the entity was marked.
+ */
+static inline bool media_entity_enum_empty(struct media_entity_enum *ent_enum)
+{
+ return bitmap_empty(ent_enum->bmap, ent_enum->idx_max);
+}
+
+/**
+ * media_entity_enum_intersects - Test whether two enums intersect
+ *
+ * @ent_enum1: First entity enumeration
+ * @ent_enum2: Second entity enumeration
+ *
+ * Returns true if entity enumerations e and f intersect, otherwise false.
+ */
+static inline bool media_entity_enum_intersects(
+ struct media_entity_enum *ent_enum1,
+ struct media_entity_enum *ent_enum2)
+{
+ WARN_ON(ent_enum1->idx_max != ent_enum2->idx_max);
+
+ return bitmap_intersects(ent_enum1->bmap, ent_enum2->bmap,
+ min(ent_enum1->idx_max, ent_enum2->idx_max));
+}
+
+#define gobj_to_entity(gobj) \
+ container_of(gobj, struct media_entity, graph_obj)
+
+#define gobj_to_pad(gobj) \
+ container_of(gobj, struct media_pad, graph_obj)
+
+#define gobj_to_link(gobj) \
+ container_of(gobj, struct media_link, graph_obj)
+
+#define gobj_to_link(gobj) \
+ container_of(gobj, struct media_link, graph_obj)
+
+#define gobj_to_pad(gobj) \
+ container_of(gobj, struct media_pad, graph_obj)
+
+#define gobj_to_intf(gobj) \
+ container_of(gobj, struct media_interface, graph_obj)
+
+#define intf_to_devnode(intf) \
+ container_of(intf, struct media_intf_devnode, intf)
+
+/**
+ * media_gobj_create - Initialize a graph object
+ *
+ * @mdev: Pointer to the media_device that contains the object
+ * @type: Type of the object
+ * @gobj: Pointer to the graph object
+ *
+ * This routine initializes the embedded struct media_gobj inside a
+ * media graph object. It is called automatically if media_*_create()
+ * calls are used. However, if the object (entity, link, pad, interface)
+ * is embedded on some other object, this function should be called before
+ * registering the object at the media controller.
+ */
+void media_gobj_create(struct media_device *mdev,
+ enum media_gobj_type type,
+ struct media_gobj *gobj);
+
+/**
+ * media_gobj_destroy - Stop using a graph object on a media device
+ *
+ * @gobj: Pointer to the graph object
+ *
+ * This should be called by all routines like media_device_unregister()
+ * that remove/destroy media graph objects.
+ */
+void media_gobj_destroy(struct media_gobj *gobj);
+
+/**
+ * media_entity_pads_init() - Initialize the entity pads
+ *
+ * @entity: entity where the pads belong
+ * @num_pads: total number of sink and source pads
+ * @pads: Array of @num_pads pads.
+ *
+ * The pads array is managed by the entity driver and passed to
+ * media_entity_pads_init() where its pointer will be stored in the entity
+ * structure.
+ *
+ * If no pads are needed, drivers could either directly fill
+ * &media_entity->@num_pads with 0 and &media_entity->@pads with NULL or call
+ * this function that will do the same.
+ *
+ * As the number of pads is known in advance, the pads array is not allocated
+ * dynamically but is managed by the entity driver. Most drivers will embed the
+ * pads array in a driver-specific structure, avoiding dynamic allocation.
+ *
+ * Drivers must set the direction of every pad in the pads array before calling
+ * media_entity_pads_init(). The function will initialize the other pads fields.
+ */
+int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
+ struct media_pad *pads);
+
+/**
+ * media_entity_cleanup() - free resources associated with an entity
+ *
+ * @entity: entity where the pads belong
+ *
+ * This function must be called during the cleanup phase after unregistering
+ * the entity (currently, it does nothing).
+ */
+static inline void media_entity_cleanup(struct media_entity *entity) {};
+
+/**
+ * media_create_pad_link() - creates a link between two entities.
+ *
+ * @source: pointer to &media_entity of the source pad.
+ * @source_pad: number of the source pad in the pads array
+ * @sink: pointer to &media_entity of the sink pad.
+ * @sink_pad: number of the sink pad in the pads array.
+ * @flags: Link flags, as defined in include/uapi/linux/media.h.
+ *
+ * Valid values for flags:
+ * A %MEDIA_LNK_FL_ENABLED flag indicates that the link is enabled and can be
+ * used to transfer media data. When two or more links target a sink pad,
+ * only one of them can be enabled at a time.
+ *
+ * A %MEDIA_LNK_FL_IMMUTABLE flag indicates that the link enabled state can't
+ * be modified at runtime. If %MEDIA_LNK_FL_IMMUTABLE is set, then
+ * %MEDIA_LNK_FL_ENABLED must also be set since an immutable link is
+ * always enabled.
+ *
+ * NOTE:
+ *
+ * Before calling this function, media_entity_pads_init() and
+ * media_device_register_entity() should be called previously for both ends.
+ */
+__must_check int media_create_pad_link(struct media_entity *source,
+ u16 source_pad, struct media_entity *sink,
+ u16 sink_pad, u32 flags);
+
+/**
+ * media_create_pad_links() - creates a link between two entities.
+ *
+ * @mdev: Pointer to the media_device that contains the object
+ * @source_function: Function of the source entities. Used only if @source is
+ * NULL.
+ * @source: pointer to &media_entity of the source pad. If NULL, it will use
+ * all entities that matches the @sink_function.
+ * @source_pad: number of the source pad in the pads array
+ * @sink_function: Function of the sink entities. Used only if @sink is NULL.
+ * @sink: pointer to &media_entity of the sink pad. If NULL, it will use
+ * all entities that matches the @sink_function.
+ * @sink_pad: number of the sink pad in the pads array.
+ * @flags: Link flags, as defined in include/uapi/linux/media.h.
+ * @allow_both_undefined: if true, then both @source and @sink can be NULL.
+ * In such case, it will create a crossbar between all entities that
+ * matches @source_function to all entities that matches @sink_function.
+ * If false, it will return 0 and won't create any link if both @source
+ * and @sink are NULL.
+ *
+ * Valid values for flags:
+ * A %MEDIA_LNK_FL_ENABLED flag indicates that the link is enabled and can be
+ * used to transfer media data. If multiple links are created and this
+ * flag is passed as an argument, only the first created link will have
+ * this flag.
+ *
+ * A %MEDIA_LNK_FL_IMMUTABLE flag indicates that the link enabled state can't
+ * be modified at runtime. If %MEDIA_LNK_FL_IMMUTABLE is set, then
+ * %MEDIA_LNK_FL_ENABLED must also be set since an immutable link is
+ * always enabled.
+ *
+ * It is common for some devices to have multiple source and/or sink entities
+ * of the same type that should be linked. While media_create_pad_link()
+ * creates link by link, this function is meant to allow 1:n, n:1 and even
+ * cross-bar (n:n) links.
+ *
+ * NOTE: Before calling this function, media_entity_pads_init() and
+ * media_device_register_entity() should be called previously for the entities
+ * to be linked.
+ */
+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);
-int media_entity_create_link(struct media_entity *source, u16 source_pad,
- struct media_entity *sink, u16 sink_pad, u32 flags);
void __media_entity_remove_links(struct media_entity *entity);
+
+/**
+ * media_entity_remove_links() - remove all links associated with an entity
+ *
+ * @entity: pointer to &media_entity
+ *
+ * Note: this is called automatically when an entity is unregistered via
+ * media_device_register_entity().
+ */
void media_entity_remove_links(struct media_entity *entity);
+/**
+ * __media_entity_setup_link - Configure a media link without locking
+ * @link: The link being configured
+ * @flags: Link configuration flags
+ *
+ * The bulk of link setup is handled by the two entities connected through the
+ * link. This function notifies both entities of the link configuration change.
+ *
+ * If the link is immutable or if the current and new configuration are
+ * identical, return immediately.
+ *
+ * The user is expected to hold link->source->parent->mutex. If not,
+ * media_entity_setup_link() should be used instead.
+ */
int __media_entity_setup_link(struct media_link *link, u32 flags);
+
+/**
+ * media_entity_setup_link() - changes the link flags properties in runtime
+ *
+ * @link: pointer to &media_link
+ * @flags: the requested new link flags
+ *
+ * The only configurable property is the %MEDIA_LNK_FL_ENABLED link flag
+ * flag to enable/disable a link. Links marked with the
+ * %MEDIA_LNK_FL_IMMUTABLE link flag can not be enabled or disabled.
+ *
+ * When a link is enabled or disabled, the media framework calls the
+ * link_setup operation for the two entities at the source and sink of the
+ * link, in that order. If the second link_setup call fails, another
+ * link_setup call is made on the first entity to restore the original link
+ * flags.
+ *
+ * Media device drivers can be notified of link setup operations by setting the
+ * media_device::link_notify pointer to a callback function. If provided, the
+ * notification callback will be called before enabling and after disabling
+ * links.
+ *
+ * Entity drivers must implement the link_setup operation if any of their links
+ * is non-immutable. The operation must either configure the hardware or store
+ * the configuration information to be applied later.
+ *
+ * Link configuration must not have any side effect on other links. If an
+ * enabled link at a sink pad prevents another link at the same pad from
+ * being enabled, the link_setup operation must return -EBUSY and can't
+ * implicitly disable the first enabled link.
+ *
+ * NOTE: the valid values of the flags for the link is the same as described
+ * on media_create_pad_link(), for pad to pad links or the same as described
+ * on media_create_intf_link(), for interface to entity links.
+ */
int media_entity_setup_link(struct media_link *link, u32 flags);
+
+/**
+ * media_entity_find_link - Find a link between two pads
+ * @source: Source pad
+ * @sink: Sink pad
+ *
+ * Return a pointer to the link between the two entities. If no such link
+ * exists, return NULL.
+ */
struct media_link *media_entity_find_link(struct media_pad *source,
struct media_pad *sink);
+
+/**
+ * media_entity_remote_pad - Find the pad at the remote end of a link
+ * @pad: Pad at the local end of the link
+ *
+ * Search for a remote pad connected to the given pad by iterating over all
+ * links originating or terminating at that pad until an enabled link is found.
+ *
+ * Return a pointer to the pad at the remote end of the first found enabled
+ * link, or NULL if no enabled link has been found.
+ */
struct media_pad *media_entity_remote_pad(struct media_pad *pad);
+/**
+ * media_entity_get - Get a reference to the parent module
+ *
+ * @entity: The entity
+ *
+ * Get a reference to the parent media device module.
+ *
+ * The function will return immediately if @entity is NULL.
+ *
+ * Return a pointer to the entity on success or NULL on failure.
+ */
struct media_entity *media_entity_get(struct media_entity *entity);
+
+__must_check int media_entity_graph_walk_init(
+ struct media_entity_graph *graph, struct media_device *mdev);
+
+/**
+ * media_entity_graph_walk_cleanup - Release resources used by graph walk.
+ *
+ * @graph: Media graph structure that will be used to walk the graph
+ */
+void media_entity_graph_walk_cleanup(struct media_entity_graph *graph);
+
+/**
+ * media_entity_put - Release the reference to the parent module
+ *
+ * @entity: The entity
+ *
+ * Release the reference count acquired by media_entity_get().
+ *
+ * The function will return immediately if @entity is NULL.
+ */
void media_entity_put(struct media_entity *entity);
+/**
+ * media_entity_graph_walk_start - Start walking the media graph at a given entity
+ * @graph: Media graph structure that will be used to walk the graph
+ * @entity: Starting entity
+ *
+ * Before using this function, media_entity_graph_walk_init() must be
+ * used to allocate resources used for walking the graph. This
+ * function initializes the graph traversal structure to walk the
+ * entities graph starting at the given entity. The traversal
+ * structure must not be modified by the caller during graph
+ * traversal. After the graph walk, the resources must be released
+ * using media_entity_graph_walk_cleanup().
+ */
void media_entity_graph_walk_start(struct media_entity_graph *graph,
- struct media_entity *entity);
+ struct media_entity *entity);
+
+/**
+ * media_entity_graph_walk_next - Get the next entity in the graph
+ * @graph: Media graph structure
+ *
+ * Perform a depth-first traversal of the given media entities graph.
+ *
+ * The graph structure must have been previously initialized with a call to
+ * media_entity_graph_walk_start().
+ *
+ * Return the next entity in the graph or NULL if the whole graph have been
+ * traversed.
+ */
struct media_entity *
media_entity_graph_walk_next(struct media_entity_graph *graph);
+
+/**
+ * media_entity_pipeline_start - Mark a pipeline as streaming
+ * @entity: Starting entity
+ * @pipe: Media pipeline to be assigned to all entities in the pipeline.
+ *
+ * Mark all entities connected to a given entity through enabled links, either
+ * directly or indirectly, as streaming. The given pipeline object is assigned to
+ * every entity in the pipeline and stored in the media_entity pipe field.
+ *
+ * Calls to this function can be nested, in which case the same number of
+ * media_entity_pipeline_stop() calls will be required to stop streaming. The
+ * pipeline pointer must be identical for all nested calls to
+ * media_entity_pipeline_start().
+ */
__must_check int media_entity_pipeline_start(struct media_entity *entity,
struct media_pipeline *pipe);
+
+/**
+ * media_entity_pipeline_stop - Mark a pipeline as not streaming
+ * @entity: Starting entity
+ *
+ * Mark all entities connected to a given entity through enabled links, either
+ * directly or indirectly, as not streaming. The media_entity pipe field is
+ * reset to NULL.
+ *
+ * If multiple calls to media_entity_pipeline_start() have been made, the same
+ * number of calls to this function are required to mark the pipeline as not
+ * streaming.
+ */
void media_entity_pipeline_stop(struct media_entity *entity);
+/**
+ * media_devnode_create() - creates and initializes a device node interface
+ *
+ * @mdev: pointer to struct &media_device
+ * @type: type of the interface, as given by MEDIA_INTF_T_* macros
+ * as defined in the uapi/media/media.h header.
+ * @flags: Interface flags as defined in uapi/media/media.h.
+ * @major: Device node major number.
+ * @minor: Device node minor number.
+ *
+ * Return: if succeeded, returns a pointer to the newly allocated
+ * &media_intf_devnode pointer.
+ */
+struct media_intf_devnode *
+__must_check media_devnode_create(struct media_device *mdev,
+ u32 type, u32 flags,
+ u32 major, u32 minor);
+/**
+ * media_devnode_remove() - removes a device node interface
+ *
+ * @devnode: pointer to &media_intf_devnode to be freed.
+ *
+ * When a device node interface is removed, all links to it are automatically
+ * removed.
+ */
+void media_devnode_remove(struct media_intf_devnode *devnode);
+struct media_link *
+
+/**
+ * media_create_intf_link() - creates a link between an entity and an interface
+ *
+ * @entity: pointer to %media_entity
+ * @intf: pointer to %media_interface
+ * @flags: Link flags, as defined in include/uapi/linux/media.h.
+ *
+ *
+ * Valid values for flags:
+ * The %MEDIA_LNK_FL_ENABLED flag indicates that the interface is connected to
+ * the entity hardware. That's the default value for interfaces. An
+ * interface may be disabled if the hardware is busy due to the usage
+ * of some other interface that it is currently controlling the hardware.
+ * A typical example is an hybrid TV device that handle only one type of
+ * stream on a given time. So, when the digital TV is streaming,
+ * the V4L2 interfaces won't be enabled, as such device is not able to
+ * also stream analog TV or radio.
+ *
+ * Note:
+ *
+ * Before calling this function, media_devnode_create() should be called for
+ * the interface and media_device_register_entity() should be called for the
+ * interface that will be part of the link.
+ */
+__must_check media_create_intf_link(struct media_entity *entity,
+ struct media_interface *intf,
+ u32 flags);
+/**
+ * __media_remove_intf_link() - remove a single interface link
+ *
+ * @link: pointer to &media_link.
+ *
+ * Note: this is an unlocked version of media_remove_intf_link()
+ */
+void __media_remove_intf_link(struct media_link *link);
+
+/**
+ * media_remove_intf_link() - remove a single interface link
+ *
+ * @link: pointer to &media_link.
+ *
+ * Note: prefer to use this one, instead of __media_remove_intf_link()
+ */
+void media_remove_intf_link(struct media_link *link);
+
+/**
+ * __media_remove_intf_links() - remove all links associated with an interface
+ *
+ * @intf: pointer to &media_interface
+ *
+ * Note: this is an unlocked version of media_remove_intf_links().
+ */
+void __media_remove_intf_links(struct media_interface *intf);
+
+/**
+ * media_remove_intf_links() - remove all links associated with an interface
+ *
+ * @intf: pointer to &media_interface
+ *
+ * Notes:
+ *
+ * this is called automatically when an entity is unregistered via
+ * media_device_register_entity() and by media_devnode_remove().
+ *
+ * Prefer to use this one, instead of __media_remove_intf_links().
+ */
+void media_remove_intf_links(struct media_interface *intf);
+
#define media_entity_call(entity, operation, args...) \
(((entity)->ops && (entity)->ops->operation) ? \
(entity)->ops->operation((entity) , ##args) : -ENOIOCTLCMD)
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 486b6a54363b..e5321fda5489 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -21,6 +21,14 @@
#include <linux/videodev2.h>
+/* Tuner PADs */
+/* FIXME: is this the right place for it? */
+enum tuner_pad_index {
+ TUNER_PAD_RF_INPUT,
+ TUNER_PAD_IF_OUTPUT,
+ TUNER_NUM_PADS
+};
+
#define ADDR_UNSET (255)
#define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index acbcd2f5fe7f..eeabf20e87a6 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -86,6 +86,7 @@ struct video_device
{
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
+ struct media_intf_devnode *intf_devnode;
#endif
/* device ops */
const struct v4l2_file_operations *fops;
diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index 4e816be3de39..1e3c8cb43bd7 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -23,6 +23,9 @@
#ifndef __LINUX_MEDIA_H
#define __LINUX_MEDIA_H
+#ifndef __KERNEL__
+#include <stdint.h>
+#endif
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/version.h>
@@ -42,33 +45,107 @@ struct media_device_info {
#define MEDIA_ENT_ID_FLAG_NEXT (1 << 31)
+/*
+ * Initial value to be used when a new entity is created
+ * Drivers should change it to something useful
+ */
+#define MEDIA_ENT_F_UNKNOWN 0x00000000
+
+/*
+ * Base number ranges for entity functions
+ *
+ * NOTE: those ranges and entity function number are phased just to
+ * make it easier to maintain this file. Userspace should not rely on
+ * the ranges to identify a group of function types, as newer
+ * functions can be added with any name within the full u32 range.
+ */
+#define MEDIA_ENT_F_BASE 0x00000000
+#define MEDIA_ENT_F_OLD_BASE 0x00010000
+#define MEDIA_ENT_F_OLD_SUBDEV_BASE 0x00020000
+
+/*
+ * DVB entities
+ */
+#define MEDIA_ENT_F_DTV_DEMOD (MEDIA_ENT_F_BASE + 1)
+#define MEDIA_ENT_F_TS_DEMUX (MEDIA_ENT_F_BASE + 2)
+#define MEDIA_ENT_F_DTV_CA (MEDIA_ENT_F_BASE + 3)
+#define MEDIA_ENT_F_DTV_NET_DECAP (MEDIA_ENT_F_BASE + 4)
+
+/*
+ * Connectors
+ */
+/* It is a responsibility of the entity drivers to add connectors and links */
+#define MEDIA_ENT_F_CONN_RF (MEDIA_ENT_F_BASE + 21)
+#define MEDIA_ENT_F_CONN_SVIDEO (MEDIA_ENT_F_BASE + 22)
+#define MEDIA_ENT_F_CONN_COMPOSITE (MEDIA_ENT_F_BASE + 23)
+/* For internal test signal generators and other debug connectors */
+#define MEDIA_ENT_F_CONN_TEST (MEDIA_ENT_F_BASE + 24)
+
+/*
+ * I/O entities
+ */
+#define MEDIA_ENT_F_IO_DTV (MEDIA_ENT_F_BASE + 31)
+#define MEDIA_ENT_F_IO_VBI (MEDIA_ENT_F_BASE + 32)
+#define MEDIA_ENT_F_IO_SWRADIO (MEDIA_ENT_F_BASE + 33)
+
+/*
+ * Don't touch on those. The ranges MEDIA_ENT_F_OLD_BASE and
+ * MEDIA_ENT_F_OLD_SUBDEV_BASE are kept to keep backward compatibility
+ * with the legacy v1 API.The number range is out of range by purpose:
+ * several previously reserved numbers got excluded from this range.
+ *
+ * Subdevs are initialized with MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN,
+ * in order to preserve backward compatibility.
+ * Drivers must change to the proper subdev type before
+ * registering the entity.
+ */
+
+#define MEDIA_ENT_F_IO_V4L (MEDIA_ENT_F_OLD_BASE + 1)
+
+#define MEDIA_ENT_F_CAM_SENSOR (MEDIA_ENT_F_OLD_SUBDEV_BASE + 1)
+#define MEDIA_ENT_F_FLASH (MEDIA_ENT_F_OLD_SUBDEV_BASE + 2)
+#define MEDIA_ENT_F_LENS (MEDIA_ENT_F_OLD_SUBDEV_BASE + 3)
+#define MEDIA_ENT_F_ATV_DECODER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 4)
+/*
+ * It is a responsibility of the entity drivers to add connectors and links
+ * for the tuner entities.
+ */
+#define MEDIA_ENT_F_TUNER (MEDIA_ENT_F_OLD_SUBDEV_BASE + 5)
+
+#define MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN MEDIA_ENT_F_OLD_SUBDEV_BASE
+
+#ifndef __KERNEL__
+
+/*
+ * Legacy symbols used to avoid userspace compilation breakages
+ *
+ * Those symbols map the entity function into types and should be
+ * used only on legacy programs for legacy hardware. Don't rely
+ * on those for MEDIA_IOC_G_TOPOLOGY.
+ */
#define MEDIA_ENT_TYPE_SHIFT 16
#define MEDIA_ENT_TYPE_MASK 0x00ff0000
#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff
-#define MEDIA_ENT_T_DEVNODE (1 << MEDIA_ENT_TYPE_SHIFT)
-#define MEDIA_ENT_T_DEVNODE_V4L (MEDIA_ENT_T_DEVNODE + 1)
+#define MEDIA_ENT_T_DEVNODE MEDIA_ENT_F_OLD_BASE
+#define MEDIA_ENT_T_DEVNODE_V4L MEDIA_ENT_F_IO_V4L
#define MEDIA_ENT_T_DEVNODE_FB (MEDIA_ENT_T_DEVNODE + 2)
#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3)
-#define MEDIA_ENT_T_DEVNODE_DVB_FE (MEDIA_ENT_T_DEVNODE + 4)
-#define MEDIA_ENT_T_DEVNODE_DVB_DEMUX (MEDIA_ENT_T_DEVNODE + 5)
-#define MEDIA_ENT_T_DEVNODE_DVB_DVR (MEDIA_ENT_T_DEVNODE + 6)
-#define MEDIA_ENT_T_DEVNODE_DVB_CA (MEDIA_ENT_T_DEVNODE + 7)
-#define MEDIA_ENT_T_DEVNODE_DVB_NET (MEDIA_ENT_T_DEVNODE + 8)
-
-/* Legacy symbol. Use it to avoid userspace compilation breakages */
-#define MEDIA_ENT_T_DEVNODE_DVB MEDIA_ENT_T_DEVNODE_DVB_FE
-
-#define MEDIA_ENT_T_V4L2_SUBDEV (2 << MEDIA_ENT_TYPE_SHIFT)
-#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR (MEDIA_ENT_T_V4L2_SUBDEV + 1)
-#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH (MEDIA_ENT_T_V4L2_SUBDEV + 2)
-#define MEDIA_ENT_T_V4L2_SUBDEV_LENS (MEDIA_ENT_T_V4L2_SUBDEV + 3)
-/* A converter of analogue video to its digital representation. */
-#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER (MEDIA_ENT_T_V4L2_SUBDEV + 4)
+#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4)
-#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER (MEDIA_ENT_T_V4L2_SUBDEV + 5)
+#define MEDIA_ENT_T_UNKNOWN MEDIA_ENT_F_UNKNOWN
+#define MEDIA_ENT_T_V4L2_VIDEO MEDIA_ENT_F_IO_V4L
+#define MEDIA_ENT_T_V4L2_SUBDEV MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN
+#define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR MEDIA_ENT_F_CAM_SENSOR
+#define MEDIA_ENT_T_V4L2_SUBDEV_FLASH MEDIA_ENT_F_FLASH
+#define MEDIA_ENT_T_V4L2_SUBDEV_LENS MEDIA_ENT_F_LENS
+#define MEDIA_ENT_T_V4L2_SUBDEV_DECODER MEDIA_ENT_F_ATV_DECODER
+#define MEDIA_ENT_T_V4L2_SUBDEV_TUNER MEDIA_ENT_F_TUNER
+#endif
+/* Entity flags */
#define MEDIA_ENT_FL_DEFAULT (1 << 0)
+#define MEDIA_ENT_FL_CONNECTOR (1 << 1)
struct media_entity_desc {
__u32 id;
@@ -151,6 +228,10 @@ struct media_pad_desc {
#define MEDIA_LNK_FL_IMMUTABLE (1 << 1)
#define MEDIA_LNK_FL_DYNAMIC (1 << 2)
+#define MEDIA_LNK_FL_LINK_TYPE (0xf << 28)
+# define MEDIA_LNK_FL_DATA_LINK (0 << 28)
+# define MEDIA_LNK_FL_INTERFACE_LINK (1 << 28)
+
struct media_link_desc {
struct media_pad_desc source;
struct media_pad_desc sink;
@@ -167,9 +248,120 @@ struct media_links_enum {
__u32 reserved[4];
};
+/* Interface type ranges */
+
+#define MEDIA_INTF_T_DVB_BASE 0x00000100
+#define MEDIA_INTF_T_V4L_BASE 0x00000200
+
+/* Interface types */
+
+#define MEDIA_INTF_T_DVB_FE (MEDIA_INTF_T_DVB_BASE)
+#define MEDIA_INTF_T_DVB_DEMUX (MEDIA_INTF_T_DVB_BASE + 1)
+#define MEDIA_INTF_T_DVB_DVR (MEDIA_INTF_T_DVB_BASE + 2)
+#define MEDIA_INTF_T_DVB_CA (MEDIA_INTF_T_DVB_BASE + 3)
+#define MEDIA_INTF_T_DVB_NET (MEDIA_INTF_T_DVB_BASE + 4)
+
+#define MEDIA_INTF_T_V4L_VIDEO (MEDIA_INTF_T_V4L_BASE)
+#define MEDIA_INTF_T_V4L_VBI (MEDIA_INTF_T_V4L_BASE + 1)
+#define MEDIA_INTF_T_V4L_RADIO (MEDIA_INTF_T_V4L_BASE + 2)
+#define MEDIA_INTF_T_V4L_SUBDEV (MEDIA_INTF_T_V4L_BASE + 3)
+#define MEDIA_INTF_T_V4L_SWRADIO (MEDIA_INTF_T_V4L_BASE + 4)
+
+/*
+ * MC next gen API definitions
+ *
+ * NOTE: The declarations below are close to the MC RFC for the Media
+ * Controller, the next generation. Yet, there are a few adjustments
+ * to do, as we want to be able to have a functional API before
+ * the MC properties change. Those will be properly marked below.
+ * Please also notice that I removed "num_pads", "num_links",
+ * from the proposal, as a proper userspace application will likely
+ * use lists for pads/links, just as we intend to do in Kernelspace.
+ * The API definition should be freed from fields that are bound to
+ * some specific data structure.
+ *
+ * FIXME: Currently, I opted to name the new types as "media_v2", as this
+ * won't cause any conflict with the Kernelspace namespace, nor with
+ * the previous kAPI media_*_desc namespace. This can be changed
+ * later, before the adding this API upstream.
+ */
+
+#if 0 /* Let's postpone it to Kernel 4.6 */
+struct media_v2_entity {
+ __u32 id;
+ char name[64]; /* FIXME: move to a property? (RFC says so) */
+ __u32 function; /* Main function of the entity */
+ __u16 reserved[12];
+};
+
+/* Should match the specific fields at media_intf_devnode */
+struct media_v2_intf_devnode {
+ __u32 major;
+ __u32 minor;
+};
+
+struct media_v2_interface {
+ __u32 id;
+ __u32 intf_type;
+ __u32 flags;
+ __u32 reserved[9];
+
+ union {
+ struct media_v2_intf_devnode devnode;
+ __u32 raw[16];
+ };
+};
+
+struct media_v2_pad {
+ __u32 id;
+ __u32 entity_id;
+ __u32 flags;
+ __u16 reserved[9];
+};
+
+struct media_v2_link {
+ __u32 id;
+ __u32 source_id;
+ __u32 sink_id;
+ __u32 flags;
+ __u32 reserved[5];
+};
+
+struct media_v2_topology {
+ __u64 topology_version;
+
+ __u32 num_entities;
+ __u32 reserved1;
+ __u64 ptr_entities;
+
+ __u32 num_interfaces;
+ __u32 reserved2;
+ __u64 ptr_interfaces;
+
+ __u32 num_pads;
+ __u32 reserved3;
+ __u64 ptr_pads;
+
+ __u32 num_links;
+ __u32 reserved4;
+ __u64 ptr_links;
+};
+
+static inline void __user *media_get_uptr(__u64 arg)
+{
+ return (void __user *)(uintptr_t)arg;
+}
+#endif
+
+/* ioctls */
+
#define MEDIA_IOC_DEVICE_INFO _IOWR('|', 0x00, struct media_device_info)
#define MEDIA_IOC_ENUM_ENTITIES _IOWR('|', 0x01, struct media_entity_desc)
#define MEDIA_IOC_ENUM_LINKS _IOWR('|', 0x02, struct media_links_enum)
#define MEDIA_IOC_SETUP_LINK _IOWR('|', 0x03, struct media_link_desc)
+#if 0 /* Let's postpone it to Kernel 4.6 */
+#define MEDIA_IOC_G_TOPOLOGY _IOWR('|', 0x04, struct media_v2_topology)
+#endif
+
#endif /* __LINUX_MEDIA_H */