Struct media_entity Explained Deeply
Free Linux Kernel Development Course — Field-by-field reference for struct media_device and struct media_entity on current kernels
Now that you understand the entity/pad/link abstraction conceptually, it’s time to open up the two core data structures that back it: struct media_device and struct media_entity. This lecture in our free linux kernel development course walks through every field that actually matters to a driver author, explains where they come from, and shows an original driver populating them correctly.
What You Will Learn
- Every practically-relevant field of
struct media_device - Every practically-relevant field of
struct media_entity, including the currentMEDIA_ENTITY_TYPE_*andMEDIA_ENT_F_*constants - How
topology_versionis used by user space to detect graph changes - How to correctly initialize both structures in an original bridge driver
Prerequisites
Read the previous lecture on entities, pads, and links first — this lecture assumes you already know what those three words mean conceptually.
struct media_device: The Top Of The Hierarchy
Every media graph is rooted at one struct media_device instance, defined in include/media/media-device.h. It is normally embedded inside the bridge driver’s private structure and is what ultimately backs the /dev/mediaX node.
struct media_device {
struct device *dev;
struct media_devnode *devnode;
char model[32];
char driver_name[32];
char serial[40];
u32 hw_revision;
u64 topology_version;
struct list_head entities;
struct list_head interfaces;
struct list_head pads;
struct list_head links;
struct list_head entity_notify;
struct mutex graph_mutex;
const struct media_device_ops *ops;
};
Field-by-field, here is what a driver author actually needs to care about:
dev— the parent device for this media device, usually a&platform_device->dev,&pci_dev->dev, or&usb_interface->dev.devnode— the underlying media device node abstraction; managed by the framework, drivers don’t touch it directly.model— a human-readable model name shown to user space. It does not need to be globally unique.driver_name— optional; defaults todev->driver->namewhen left unset.serialandhw_revision— optional identification fields, useful when the same driver supports multiple hardware revisions.topology_version— a monotonically increasing counter. Any time the graph changes (an entity is added, a link is created or its state changes), this counter is bumped so user-space applications can cheaply detect “has anything changed since I last looked?”entities,pads,links— the actual list heads holding every registered entity, pad, and link on this media device.entity_notify— a callback list invoked whenever a new entity is registered, letting other parts of a driver react to dynamic entity addition.graph_mutex— protects concurrent access to the graph. Any code walkingmedia_graph_*family functions must hold it.ops— driver-supplied operation hooks of typestruct media_device_ops, most commonly used for power-management-related source enable/disable callbacks on newer kernels.
struct media_entity: One Node In The Graph
Every functional block — sensor, scaler, ISP, or capture node — is represented as one struct media_entity, defined in include/media/media-entity.h. Trimmed to the fields that matter day-to-day:
struct media_entity {
struct media_gobj graph_obj;
const char *name;
enum media_entity_type obj_type;
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;
int stream_count;
int use_count;
struct media_pipeline *pipe;
};
name— must be meaningful, since this is exactly what shows up in themedia-ctltopology dump.obj_type— runtime type identification, set by the core. Current values areMEDIA_ENTITY_TYPE_BASE(standalone entity, not embedded in a bigger structure),MEDIA_ENTITY_TYPE_VIDEO_DEVICE(embedded in avideo_device), andMEDIA_ENTITY_TYPE_V4L2_SUBDEV(embedded in av4l2_subdev).function— the entity’s role, set by the driver frominclude/uapi/linux/media.h. Common values includeMEDIA_ENT_F_CAM_SENSOR,MEDIA_ENT_F_IO_V4L(a data streaming input/output node),MEDIA_ENT_F_PROC_VIDEO_SCALER,MEDIA_ENT_F_PROC_VIDEO_ENCODER, andMEDIA_ENT_F_VID_IF_BRIDGEfor interface-bridging entities that convert between two different bus types.flags— driver-setMEDIA_ENT_FL_*flags.num_pads— total pad count (sink plus source).num_links— total link count, counting both forward links and backlinks, enabled or not.num_backlinks— how many of those links are backlinks, used purely for internal graph traversal and never shown to user space.internal_idx— a unique numeric ID assigned by the core the moment the entity is registered.pads— the array of this entity’s pads, sized bynum_pads.ops— optional link-related callbacks, of typestruct media_entity_operations, covered in a later lecture.stream_count/use_count— reference counts for active streaming and general power-management use, respectively.pipe— the pipeline this entity currently belongs to while streaming is active.
Ownership Hierarchy
Original Example: Populating Both Structures
Here’s an original bridge driver, ep_isp, filling in a media_device and a scaler-style media_entity that is not tied to a video_device or v4l2_subdev — a standalone internal processing block.
struct ep_isp_scaler {
struct media_entity entity;
struct media_pad pads[2];
};
struct ep_isp_dev {
struct device *dev;
struct media_device mdev;
struct ep_isp_scaler scaler;
};
static int ep_isp_probe(struct platform_device *pdev)
{
struct ep_isp_dev *epi;
int ret;
epi = devm_kzalloc(&pdev->dev, sizeof(*epi), GFP_KERNEL);
if (!epi)
return -ENOMEM;
epi->dev = &pdev->dev;
epi->mdev.dev = &pdev->dev;
strscpy(epi->mdev.model, "ep-isp", sizeof(epi->mdev.model));
media_device_init(&epi->mdev);
epi->scaler.entity.name = "ep-isp-scaler";
epi->scaler.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
epi->scaler.pads[0].flags = MEDIA_PAD_FL_SINK;
epi->scaler.pads[1].flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&epi->scaler.entity, 2, epi->scaler.pads);
if (ret)
return ret;
ret = media_device_register(&epi->mdev);
if (ret)
return ret;
dev_info(epi->dev, "ep-isp media device registered, topology_version=%llu\n",
epi->mdev.topology_version);
return 0;
}
Building and loading this module and checking dmesg produces output confirming registration:
$ sudo insmod ep_isp.ko
$ dmesg | tail -3
[ 102.334112] ep_isp platform: ep-isp media device registered, topology_version=2
Notice the counter is already 2, not 0, immediately after registering just one entity with two pads — the framework bumps it internally as entities and their pads are added to the graph.
Common Mistakes To Avoid
- Setting
entity.functionto an arbitrary value instead of one of the documentedMEDIA_ENT_F_*constants — user-space tools rely on this field to render a sensible topology. - Forgetting that
num_backlinksis internal bookkeeping, not something a driver ever sets directly — it’s maintained automatically by the link creation APIs covered in the next lecture. - Skipping
media_device_init()before touching any othermedia_devicefield — several fields, including the list heads, must be initialized by the core first.
Best Practices
- Always set a descriptive
modelstring — it’s one of the first things a developer sees when debugging withmedia-ctl -p. - Pick the most specific
MEDIA_ENT_F_*function value available rather than defaulting everything to a generic value — it materially improves how well generic camera-stack software can understand your hardware. - Log
topology_versionduring development; unexpected jumps are a fast way to catch double-registration bugs.
Summary
The media device is the root of the graph and owns global bookkeeping like topology_version, while each media entity represents one functional block with its own name, function, pads, and use counts. Together they form the backbone that the rest of the media controller framework — pads, links, and entity operations — builds on. Next in this free linux development course, we look at struct media_pad and struct media_link and actually wire two entities together.
FAQ
What is topology_version used for?
It’s a monotonic counter incremented whenever the graph changes, letting user space cheaply detect whether the topology has changed since it last queried it.
Does the model field in media_device need to be unique?
No, it’s just a human-readable model name and does not need to be globally unique across devices.
What are the possible values of obj_type on a media_entity?
MEDIA_ENTITY_TYPE_BASE, MEDIA_ENTITY_TYPE_VIDEO_DEVICE, and MEDIA_ENTITY_TYPE_V4L2_SUBDEV, set automatically by the core depending on what the entity is embedded in.
Can a driver set num_backlinks manually?
No. Backlinks are created and counted automatically by the link creation APIs; drivers never set this field directly.
Where does an entity’s function value come from?
The driver sets it from the MEDIA_ENT_F_* constants defined in include/uapi/linux/media.h, picking the value that best matches the entity’s real role.
Next: struct media_pad and struct media_link in depth
Continue this free linux kernel development course and actually wire two entities together.
Next Lecture Browse Full Course