From 1651333b09743887bc2dd3d158a11853a2be3fe7 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 9 Dec 2009 08:40:01 -0300 Subject: [PATCH] [media] media: Entities, pads and links enumeration Create the following two ioctls and implement them at the media device level to enumerate entities, pads and links. - MEDIA_IOC_ENUM_ENTITIES: Enumerate entities and their properties - MEDIA_IOC_ENUM_LINKS: Enumerate all pads and links for a given entity Entity IDs can be non-contiguous. Userspace applications should enumerate entities using the MEDIA_ENT_ID_FLAG_NEXT flag. When the flag is set in the entity ID, the MEDIA_IOC_ENUM_ENTITIES will return the next entity with an ID bigger than the requested one. Only forward links that originate at one of the entity's source pads are returned during the enumeration process. Signed-off-by: Laurent Pinchart Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media-entities.tmpl | 8 + .../DocBook/v4l/media-controller.xml | 2 + .../DocBook/v4l/media-ioc-device-info.xml | 3 +- .../DocBook/v4l/media-ioc-enum-entities.xml | 308 ++++++++++++++++++ .../DocBook/v4l/media-ioc-enum-links.xml | 202 ++++++++++++ drivers/media/media-device.c | 123 +++++++ include/linux/media.h | 85 +++++ include/media/media-entity.h | 24 +- 8 files changed, 731 insertions(+), 24 deletions(-) create mode 100644 Documentation/DocBook/v4l/media-ioc-enum-entities.xml create mode 100644 Documentation/DocBook/v4l/media-ioc-enum-links.xml diff --git a/Documentation/DocBook/media-entities.tmpl b/Documentation/DocBook/media-entities.tmpl index 034f891399ed..2bd7b27f8553 100644 --- a/Documentation/DocBook/media-entities.tmpl +++ b/Documentation/DocBook/media-entities.tmpl @@ -92,6 +92,8 @@ VIDIOC_UNSUBSCRIBE_EVENT"> MEDIA_IOC_DEVICE_INFO"> +MEDIA_IOC_ENUM_ENTITIES"> +MEDIA_IOC_ENUM_LINKS"> v4l2_std_id"> @@ -191,6 +193,10 @@ v4l2_window"> media_device_info"> +media_entity_desc"> +media_links_enum"> +media_pad_desc"> +media_link_desc"> EACCES error code"> @@ -340,6 +346,8 @@ + + diff --git a/Documentation/DocBook/v4l/media-controller.xml b/Documentation/DocBook/v4l/media-controller.xml index a46b786e9f2b..2c4fd2b27683 100644 --- a/Documentation/DocBook/v4l/media-controller.xml +++ b/Documentation/DocBook/v4l/media-controller.xml @@ -83,4 +83,6 @@ &sub-media-ioctl; &sub-media-ioc-device-info; + &sub-media-ioc-enum-entities; + &sub-media-ioc-enum-links; diff --git a/Documentation/DocBook/v4l/media-ioc-device-info.xml b/Documentation/DocBook/v4l/media-ioc-device-info.xml index 278a3120ee2e..1f3237351bba 100644 --- a/Documentation/DocBook/v4l/media-ioc-device-info.xml +++ b/Documentation/DocBook/v4l/media-ioc-device-info.xml @@ -27,7 +27,8 @@ fd - &fd; + File descriptor returned by + open(). diff --git a/Documentation/DocBook/v4l/media-ioc-enum-entities.xml b/Documentation/DocBook/v4l/media-ioc-enum-entities.xml new file mode 100644 index 000000000000..13d0cc44865a --- /dev/null +++ b/Documentation/DocBook/v4l/media-ioc-enum-entities.xml @@ -0,0 +1,308 @@ + + + ioctl MEDIA_IOC_ENUM_ENTITIES + &manvol; + + + + MEDIA_IOC_ENUM_ENTITIES + Enumerate entities and their properties + + + + + + int ioctl + int fd + int request + struct media_entity_desc *argp + + + + + + Arguments + + + + fd + + File descriptor returned by + open(). + + + + request + + MEDIA_IOC_ENUM_ENTITIES + + + + argp + + + + + + + + + Description + To query the attributes of an entity, applications set the id field + of a &media-entity-desc; structure and call the MEDIA_IOC_ENUM_ENTITIES + ioctl with a pointer to this structure. The driver fills the rest of the + structure or returns an &EINVAL; when the id is invalid. + Entities can be enumerated by or'ing the id with the + MEDIA_ENT_ID_FLAG_NEXT flag. The driver will return + information about the entity with the smallest id strictly larger than the + requested one ('next entity'), or the &EINVAL; if there is none. + Entity IDs can be non-contiguous. Applications must + not try to enumerate entities by calling + MEDIA_IOC_ENUM_ENTITIES with increasing id's until they get an error. + Two or more entities that share a common non-zero + group_id value are considered as logically + grouped. Groups are used to report + + ALSA, VBI and video nodes that carry the same media + stream + lens and flash controllers associated with a sensor + + + + + struct <structname>media_entity_desc</structname> + + + + + + + + + __u32 + id + + + Entity id, set by the application. When the id is or'ed with + MEDIA_ENT_ID_FLAG_NEXT, the driver clears the + flag and returns the first entity with a larger id. + + + char + name[32] + + + Entity name as an UTF-8 NULL-terminated string. + + + __u32 + type + + + Entity type, see for details. + + + __u32 + revision + + + Entity revision in a driver/hardware specific format. + + + __u32 + flags + + + Entity flags, see for details. + + + __u32 + group_id + + + Entity group ID + + + __u16 + pads + + + Number of pads + + + __u16 + links + + + Total number of outbound links. Inbound links are not counted + in this field. + + + union + + + + struct + v4l + + Valid for V4L sub-devices and nodes only. + + + + + __u32 + major + V4L device node major number. For V4L sub-devices with no + device node, set by the driver to 0. + + + + + __u32 + minor + V4L device node minor number. For V4L sub-devices with no + device node, set by the driver to 0. + + + + struct + fb + + Valid for frame buffer nodes only. + + + + + __u32 + major + Frame buffer device node major number. + + + + + __u32 + minor + Frame buffer device node minor number. + + + + struct + alsa + + Valid for ALSA devices only. + + + + + __u32 + card + ALSA card number + + + + + __u32 + device + ALSA device number + + + + + __u32 + subdevice + ALSA sub-device number + + + + int + dvb + + DVB card number + + + + __u8 + raw[180] + + + + + +
+ + + Media entity types + + + + + + MEDIA_ENT_T_DEVNODE + Unknown device node + + + MEDIA_ENT_T_DEVNODE_V4L + V4L video, radio or vbi device node + + + MEDIA_ENT_T_DEVNODE_FB + Frame buffer device node + + + MEDIA_ENT_T_DEVNODE_ALSA + ALSA card + + + MEDIA_ENT_T_DEVNODE_DVB + DVB card + + + MEDIA_ENT_T_V4L2_SUBDEV + Unknown V4L sub-device + + + MEDIA_ENT_T_V4L2_SUBDEV_SENSOR + Video sensor + + + MEDIA_ENT_T_V4L2_SUBDEV_FLASH + Flash controller + + + MEDIA_ENT_T_V4L2_SUBDEV_LENS + Lens controller + + + +
+ + + Media entity flags + + + + + + MEDIA_ENT_FL_DEFAULT + Default entity for its type. Used to discover the default + audio, VBI and video devices, the default camera sensor, ... + + + +
+
+ + + &return-value; + + + + EINVAL + + The &media-entity-desc; id references + a non-existing entity. + + + + +
diff --git a/Documentation/DocBook/v4l/media-ioc-enum-links.xml b/Documentation/DocBook/v4l/media-ioc-enum-links.xml new file mode 100644 index 000000000000..6da884159cab --- /dev/null +++ b/Documentation/DocBook/v4l/media-ioc-enum-links.xml @@ -0,0 +1,202 @@ + + + ioctl MEDIA_IOC_ENUM_LINKS + &manvol; + + + + MEDIA_IOC_ENUM_LINKS + Enumerate all pads and links for a given entity + + + + + + int ioctl + int fd + int request + struct media_links_enum *argp + + + + + + Arguments + + + + fd + + File descriptor returned by + open(). + + + + request + + MEDIA_IOC_ENUM_LINKS + + + + argp + + + + + + + + + Description + + To enumerate pads and/or links for a given entity, applications set + the entity field of a &media-links-enum; structure and initialize the + &media-pad-desc; and &media-link-desc; structure arrays pointed by the + pads and links fields. + They then call the MEDIA_IOC_ENUM_LINKS ioctl with a pointer to this + structure. + If the pads field is not NULL, the driver + fills the pads array with information about the + entity's pads. The array must have enough room to store all the entity's + pads. The number of pads can be retrieved with the &MEDIA-IOC-ENUM-ENTITIES; + ioctl. + If the links field is not NULL, the driver + fills the links array with information about the + entity's outbound links. The array must have enough room to store all the + entity's outbound links. The number of outbound links can be retrieved with + the &MEDIA-IOC-ENUM-ENTITIES; ioctl. + Only forward links that originate at one of the entity's source pads + are returned during the enumeration process. + + + struct <structname>media_links_enum</structname> + + &cs-str; + + + __u32 + entity + Entity id, set by the application. + + + struct &media-pad-desc; + *pads + Pointer to a pads array allocated by the application. Ignored + if NULL. + + + struct &media-link-desc; + *links + Pointer to a links array allocated by the application. Ignored + if NULL. + + + + + + + struct <structname>media_pad_desc</structname> + + &cs-str; + + + __u32 + entity + ID of the entity this pad belongs to. + + + __u16 + index + 0-based pad index. + + + __u32 + flags + Pad flags, see for more details. + + + +
+ + + Media pad flags + + + + + + MEDIA_PAD_FL_SINK + Input pad, relative to the entity. Input pads sink data and + are targets of links. + + + MEDIA_PAD_FL_SOURCE + Output pad, relative to the entity. Output pads source data + and are origins of links. + + + +
+ + + struct <structname>media_links_desc</structname> + + &cs-str; + + + struct &media-pad-desc; + source + Pad at the origin of this link. + + + struct &media-pad-desc; + sink + Pad at the target of this link. + + + __u32 + flags + Link flags, see for more details. + + + + + + + Media link flags + + + + + + MEDIA_LNK_FL_ENABLED + 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. + + + MEDIA_LNK_FL_IMMUTABLE + The link enabled state can't be modified at runtime. An + immutable link is always enabled. + + + + + One and only one of MEDIA_PAD_FL_SINK and + MEDIA_PAD_FL_SOURCE must be set for every pad. +
+ + + &return-value; + + + + EINVAL + + The &media-links-enum; id references + a non-existing entity. + + + + +
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 92e0d4eb84b8..648a9d892ac1 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -61,6 +61,117 @@ static int media_device_get_info(struct media_device *dev, return copy_to_user(__info, &info, sizeof(*__info)); } +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; + + spin_lock(&mdev->lock); + + media_device_for_each_entity(entity, mdev) { + if ((entity->id == id && !next) || + (entity->id > id && next)) { + spin_unlock(&mdev->lock); + return entity; + } + } + + spin_unlock(&mdev->lock); + + return NULL; +} + +static long media_device_enum_entities(struct media_device *mdev, + struct media_entity_desc __user *uent) +{ + struct media_entity *ent; + struct media_entity_desc u_ent; + + if (copy_from_user(&u_ent.id, &uent->id, sizeof(u_ent.id))) + return -EFAULT; + + ent = find_entity(mdev, u_ent.id); + + if (ent == NULL) + return -EINVAL; + + u_ent.id = ent->id; + u_ent.name[0] = '\0'; + if (ent->name) + strlcpy(u_ent.name, ent->name, sizeof(u_ent.name)); + u_ent.type = ent->type; + u_ent.revision = ent->revision; + u_ent.flags = ent->flags; + u_ent.group_id = ent->group_id; + u_ent.pads = ent->num_pads; + u_ent.links = ent->num_links - ent->num_backlinks; + u_ent.v4l.major = ent->v4l.major; + u_ent.v4l.minor = ent->v4l.minor; + if (copy_to_user(uent, &u_ent, sizeof(u_ent))) + return -EFAULT; + return 0; +} + +static void media_device_kpad_to_upad(const struct media_pad *kpad, + struct media_pad_desc *upad) +{ + upad->entity = kpad->entity->id; + upad->index = kpad->index; + upad->flags = kpad->flags; +} + +static long media_device_enum_links(struct media_device *mdev, + struct media_links_enum __user *ulinks) +{ + struct media_entity *entity; + struct media_links_enum links; + + if (copy_from_user(&links, ulinks, sizeof(links))) + return -EFAULT; + + 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; + 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_desc __user *ulink; + unsigned int l; + + for (l = 0, ulink = links.links; l < entity->num_links; l++) { + struct media_link_desc link; + + /* Ignore backlinks. */ + if (entity->links[l].source->entity != entity) + continue; + + media_device_kpad_to_upad(entity->links[l].source, + &link.source); + media_device_kpad_to_upad(entity->links[l].sink, + &link.sink); + link.flags = entity->links[l].flags; + if (copy_to_user(ulink, &link, sizeof(*ulink))) + return -EFAULT; + ulink++; + } + } + if (copy_to_user(ulinks, &links, sizeof(*ulinks))) + return -EFAULT; + return 0; +} + static long media_device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -74,6 +185,18 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd, (struct media_device_info __user *)arg); break; + case MEDIA_IOC_ENUM_ENTITIES: + ret = media_device_enum_entities(dev, + (struct media_entity_desc __user *)arg); + break; + + case MEDIA_IOC_ENUM_LINKS: + mutex_lock(&dev->graph_mutex); + ret = media_device_enum_links(dev, + (struct media_links_enum __user *)arg); + mutex_unlock(&dev->graph_mutex); + break; + default: ret = -ENOIOCTLCMD; } diff --git a/include/linux/media.h b/include/linux/media.h index 64090db3c1fc..17c93a413677 100644 --- a/include/linux/media.h +++ b/include/linux/media.h @@ -40,6 +40,91 @@ struct media_device_info { __u32 reserved[31]; }; +#define MEDIA_ENT_ID_FLAG_NEXT (1 << 31) + +#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_FB (MEDIA_ENT_T_DEVNODE + 2) +#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3) +#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4) + +#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) + +#define MEDIA_ENT_FL_DEFAULT (1 << 0) + +struct media_entity_desc { + __u32 id; + char name[32]; + __u32 type; + __u32 revision; + __u32 flags; + __u32 group_id; + __u16 pads; + __u16 links; + + __u32 reserved[4]; + + union { + /* Node specifications */ + struct { + __u32 major; + __u32 minor; + } v4l; + struct { + __u32 major; + __u32 minor; + } fb; + struct { + __u32 card; + __u32 device; + __u32 subdevice; + } alsa; + int dvb; + + /* Sub-device specifications */ + /* Nothing needed yet */ + __u8 raw[184]; + }; +}; + +#define MEDIA_PAD_FL_SINK (1 << 0) +#define MEDIA_PAD_FL_SOURCE (1 << 1) + +struct media_pad_desc { + __u32 entity; /* entity ID */ + __u16 index; /* pad index */ + __u32 flags; /* pad flags */ + __u32 reserved[2]; +}; + +#define MEDIA_LNK_FL_ENABLED (1 << 0) +#define MEDIA_LNK_FL_IMMUTABLE (1 << 1) + +struct media_link_desc { + struct media_pad_desc source; + struct media_pad_desc sink; + __u32 flags; + __u32 reserved[2]; +}; + +struct media_links_enum { + __u32 entity; + /* Should have enough room for pads elements */ + struct media_pad_desc __user *pads; + /* Should have enough room for links elements */ + struct media_link_desc __user *links; + __u32 reserved[4]; +}; + #define MEDIA_IOC_DEVICE_INFO _IOWR('M', 1, struct media_device_info) +#define MEDIA_IOC_ENUM_ENTITIES _IOWR('M', 2, struct media_entity_desc) +#define MEDIA_IOC_ENUM_LINKS _IOWR('M', 3, struct media_links_enum) #endif /* __LINUX_MEDIA_H */ diff --git a/include/media/media-entity.h b/include/media/media-entity.h index a9b31d98e3c6..51bdafce72c7 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -24,29 +24,7 @@ #define _MEDIA_ENTITY_H #include - -#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_FB (MEDIA_ENT_T_DEVNODE + 2) -#define MEDIA_ENT_T_DEVNODE_ALSA (MEDIA_ENT_T_DEVNODE + 3) -#define MEDIA_ENT_T_DEVNODE_DVB (MEDIA_ENT_T_DEVNODE + 4) - -#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) - -#define MEDIA_ENT_FL_DEFAULT (1 << 0) - -#define MEDIA_LNK_FL_ENABLED (1 << 0) -#define MEDIA_LNK_FL_IMMUTABLE (1 << 1) - -#define MEDIA_PAD_FL_SINK (1 << 0) -#define MEDIA_PAD_FL_SOURCE (1 << 1) +#include struct media_link { struct media_pad *source; /* Source pad */ -- 2.20.1