Struct media_entity Explained Deeply-Free Linux Device Drivers Course

PREV_LEC  |  NEXT_LEC

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

free linux kernel development course struct media_entity free linux device drivers course free linux development course

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 current MEDIA_ENTITY_TYPE_* and MEDIA_ENT_F_* constants
  • How topology_version is 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 to dev->driver->name when left unset.
  • serial and hw_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 walking media_graph_* family functions must hold it.
  • ops — driver-supplied operation hooks of type struct 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 the media-ctl topology dump.
  • obj_type — runtime type identification, set by the core. Current values are MEDIA_ENTITY_TYPE_BASE (standalone entity, not embedded in a bigger structure), MEDIA_ENTITY_TYPE_VIDEO_DEVICE (embedded in a video_device), and MEDIA_ENTITY_TYPE_V4L2_SUBDEV (embedded in a v4l2_subdev).
  • function — the entity’s role, set by the driver from include/uapi/linux/media.h. Common values include MEDIA_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, and MEDIA_ENT_F_VID_IF_BRIDGE for interface-bridging entities that convert between two different bus types.
  • flags — driver-set MEDIA_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 by num_pads.
  • ops — optional link-related callbacks, of type struct 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

media_device (the graph) → owns a list of → media_entity (each node)
media_entity → owns an array of → media_pad (each connection point)
media_pad → connected via → media_link (each wire)

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.function to an arbitrary value instead of one of the documented MEDIA_ENT_F_* constants — user-space tools rely on this field to render a sensible topology.
  • Forgetting that num_backlinks is 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 other media_device field — several fields, including the list heads, must be initialized by the core first.

Best Practices

  • Always set a descriptive model string — it’s one of the first things a developer sees when debugging with media-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_version during 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

PREV_LEC  |  NEXT_LEC

Leave a Reply

Your email address will not be published. Required fields are marked *