linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFCv2 PATCH 0/3] Media Controller Properties
@ 2018-08-07 10:28 Hans Verkuil
  2018-08-07 10:28 ` [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support Hans Verkuil
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Hans Verkuil @ 2018-08-07 10:28 UTC (permalink / raw)
  To: linux-media

From: Hans Verkuil <hans.verkuil@cisco.com>

This RFC patch series implements properties for the media controller.

The main changes since RFCv1 are:

- it is now possible to add properties even if mdev is not yet known.
  It's fixed up in media_device_register_entity().

- Dropped struct media_v2_topology_1 and instead just added a G_TOPOLOGY_OLD
  ioctl define.

- The properties are now laid out in order: first the properties for
  all entities, then the properties for all pads. The properties
  belonging to the same object are always consecutive in the property
  list.

This is not finished, but I wanted to post this so people can discuss
this further. I especially would like to get feedback on the two
proposals at the end.

No documentation yet (too early for that).

An updated v4l2-ctl and v4l2-compliance that can report properties
is available here:

https://git.linuxtv.org/hverkuil/v4l-utils.git/log/?h=props

Currently I support u64, s64 and const char * property types. But it
can be anything including binary data if needed. No array support (as we
have for controls), but there are enough reserved fields in media_v2_prop
to add this if needed.

I added properties for entities and pads to vimc, so I could test this.

We had a discussion whether we should only export properties for objects
that we query for. E.g. if set ptr_pad to 0, then don't include pad
properties in the property list.

I decided not to do that after all. It became messy and the behavior was
weird. The typical use-case is that you call G_TOPOLOGY once with all
pointers set to 0, then again after allocating the required memory.

So in the first call it will report that there are e.g. 100 properties,
but if you call it again with for example ptr_pad set to 0, then it
might only fill the first 50 properties since it is skipping the pads.
But you still need to allocate space for 100 properties since the first
call has no way of knowing that you only want to get the entity
properties.

It's just weird and I really see no reason to not always return all
properties.

I also have two proposals (not implemented yet):

1) Since the properties are now laid out in a consistent way we can do this:

struct media_v2_entity {
        __u32 id;
        char name[64];
        __u32 function;         /* Main function of the entity */
        __u32 flags;
        __u16 pad_idx;
        __u16 prop_idx;
        __u32 reserved[4];
} __attribute__ ((packed));

struct media_v2_pad {
        __u32 id;
        __u32 entity_id;
        __u32 flags;
        __u32 index;
        __u16 link_idx;
        __u16 prop_idx;
        __u32 reserved[3];
} __attribute__ ((packed));

I.e. the entity and pad structs can be extended with two fields:

pad_idx is the index of the first pad belonging to this entity in the
ptr_pad array and prop_idx is the index of the first property belonging
to this entity in the ptr_prop array.

The same for link_idx and prop_idx in the pad struct.

You can loop over e.g. all the properties of an entity by doing:

        for (i = ent->prop_idx;
             i < topo->num_props && props[i].owner_id == ent->id; i++) {
                // use property
        }

Note 1: since index can be 0 we will need flags to signal which index
fields are valid.

Note 2: the pad/link_idx fields require that we also lay out the pad
structs per entity and the link struct per pad.

2) Since we are adding properties to the topology struct, should we
   perhaps also add support for backlinks? Currently we leave it to
   userspace to deduce the backlinks, but it would not be hard to
   add a ptr_backlinks section to the topology struct. We have all
   the information and it simplifies userspace code. The pad struct
   can then also have a backlink_idx field.

Regards,

        Hans

Hans Verkuil (3):
  uapi/linux/media.h: add property support
  media: add support for properties
  vimc: add test properties

 drivers/media/media-device.c              | 162 +++++++++++++++++--
 drivers/media/media-entity.c              |  79 ++++++++-
 drivers/media/platform/vimc/vimc-common.c |  18 +++
 include/media/media-device.h              |   6 +
 include/media/media-entity.h              | 186 ++++++++++++++++++++++
 include/uapi/linux/media.h                |  40 +++++
 6 files changed, 477 insertions(+), 14 deletions(-)

-- 
2.18.0

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support
  2018-08-07 10:28 [RFCv2 PATCH 0/3] Media Controller Properties Hans Verkuil
@ 2018-08-07 10:28 ` Hans Verkuil
  2018-08-08  7:11   ` Hans Verkuil
  2018-09-04 13:01   ` Sakari Ailus
  2018-08-07 10:28 ` [RFCv2 PATCH 2/3] media: add support for properties Hans Verkuil
  2018-08-07 10:28 ` [RFCv2 PATCH 3/3] vimc: add test properties Hans Verkuil
  2 siblings, 2 replies; 9+ messages in thread
From: Hans Verkuil @ 2018-08-07 10:28 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Add a new topology struct that includes properties.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 include/uapi/linux/media.h | 40 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
index 36f76e777ef9..1910c091601e 100644
--- a/include/uapi/linux/media.h
+++ b/include/uapi/linux/media.h
@@ -342,6 +342,40 @@ struct media_v2_link {
 	__u32 reserved[6];
 } __attribute__ ((packed));
 
+#define MEDIA_PROP_TYPE_U64	1
+#define MEDIA_PROP_TYPE_S64	2
+#define MEDIA_PROP_TYPE_STRING	3
+
+/**
+ * struct media_v2_prop - A media property
+ *
+ * @id:		The unique non-zero ID of this property
+ * @owner_id:	The ID of the object this property belongs to
+ * @type:	Property type
+ * @flags:	Property flags
+ * @payload_size: Property payload size, 0 for U64/S64
+ * @payload_offset: Property payload starts at this offset from &prop.id.
+ *		This is 0 for U64/S64.
+ * @reserved:	Property reserved field, will be zeroed.
+ * @name:	Property name
+ * @uval:	Property value (unsigned)
+ * @sval:	Property value (signed)
+ */
+struct media_v2_prop {
+	__u32 id;
+	__u32 owner_id;
+	__u32 type;
+	__u32 flags;
+	__u32 payload_size;
+	__u32 payload_offset;
+	__u32 reserved[18];
+	char name[32];
+	union {
+		__u64 uval;
+		__s64 sval;
+	};
+} __attribute__ ((packed));
+
 struct media_v2_topology {
 	__u64 topology_version;
 
@@ -360,6 +394,10 @@ struct media_v2_topology {
 	__u32 num_links;
 	__u32 reserved4;
 	__u64 ptr_links;
+
+	__u32 num_props;
+	__u32 props_payload_size;
+	__u64 ptr_props;
 } __attribute__ ((packed));
 
 /* ioctls */
@@ -368,6 +406,8 @@ struct media_v2_topology {
 #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)
+/* Old MEDIA_IOC_G_TOPOLOGY ioctl without props support */
+#define MEDIA_IOC_G_TOPOLOGY_OLD 0xc0487c04
 #define MEDIA_IOC_G_TOPOLOGY	_IOWR('|', 0x04, struct media_v2_topology)
 
 #ifndef __KERNEL__
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFCv2 PATCH 2/3] media: add support for properties
  2018-08-07 10:28 [RFCv2 PATCH 0/3] Media Controller Properties Hans Verkuil
  2018-08-07 10:28 ` [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support Hans Verkuil
@ 2018-08-07 10:28 ` Hans Verkuil
  2018-08-07 10:28 ` [RFCv2 PATCH 3/3] vimc: add test properties Hans Verkuil
  2 siblings, 0 replies; 9+ messages in thread
From: Hans Verkuil @ 2018-08-07 10:28 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Initially support u64/s64 and string properties.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/media-device.c | 162 ++++++++++++++++++++++++++++--
 drivers/media/media-entity.c |  79 ++++++++++++++-
 include/media/media-device.h |   6 ++
 include/media/media-entity.h | 186 +++++++++++++++++++++++++++++++++++
 4 files changed, 419 insertions(+), 14 deletions(-)

diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index fcdf3d5dc4b6..cdf80cfcf87e 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -234,6 +234,63 @@ static long media_device_setup_link(struct media_device *mdev, void *arg)
 	return __media_entity_setup_link(link, linkd->flags);
 }
 
+static long copy_props_to_user(struct media_v2_topology *topo,
+			       int *prop_idx,
+			       unsigned int *payload_size,
+			       unsigned int *payload_offset,
+			       struct list_head *list,
+			       struct media_v2_prop __user *uprop_start)
+{
+	struct media_v2_prop __user *uprop;
+	struct media_v2_prop kprop;
+	struct media_prop *prop;
+	long ret = 0;
+
+	uprop = uprop_start + *prop_idx;
+
+	list_for_each_entry(prop, list, list) {
+		(*prop_idx)++;
+
+		if (ret)
+			continue;
+
+		if (*prop_idx > topo->num_props) {
+			ret = -ENOSPC;
+			continue;
+		}
+		memset(&kprop, 0, sizeof(kprop));
+
+		/* Copy prop fields to userspace struct */
+		kprop.id = prop->graph_obj.id;
+		kprop.owner_id = prop->owner->id;
+		kprop.type = prop->type;
+		kprop.flags = 0;
+		kprop.payload_size = prop->payload_size;
+		if (kprop.payload_size)
+			kprop.payload_offset = *payload_offset -
+				(*prop_idx - 1) * sizeof(*uprop);
+		else
+			kprop.payload_offset = 0;
+		memcpy(kprop.name, prop->name, sizeof(kprop.name));
+		kprop.uval = prop->uval;
+
+		if (copy_to_user(uprop, &kprop, sizeof(kprop))) {
+			ret = -EFAULT;
+			continue;
+		}
+		uprop++;
+		*payload_size += prop->payload_size;
+		if (topo->props_payload_size < *payload_size)
+			ret = -ENOSPC;
+		else if (copy_to_user((u8 __user *)uprop_start + *payload_offset,
+				      prop->string, prop->payload_size))
+			ret = -EFAULT;
+		*payload_offset += prop->payload_size;
+	}
+
+	return ret;
+}
+
 static long media_device_get_topology(struct media_device *mdev, void *arg)
 {
 	struct media_v2_topology *topo = arg;
@@ -241,10 +298,14 @@ static long media_device_get_topology(struct media_device *mdev, void *arg)
 	struct media_interface *intf;
 	struct media_pad *pad;
 	struct media_link *link;
+	struct media_prop *prop;
 	struct media_v2_entity kentity, __user *uentity;
 	struct media_v2_interface kintf, __user *uintf;
 	struct media_v2_pad kpad, __user *upad;
 	struct media_v2_link klink, __user *ulink;
+	struct media_v2_prop __user *uprop;
+	unsigned int payload_size = 0;
+	unsigned int payload_offset = 0;
 	unsigned int i;
 	int ret = 0;
 
@@ -374,6 +435,36 @@ static long media_device_get_topology(struct media_device *mdev, void *arg)
 	topo->num_links = i;
 	topo->reserved4 = 0;
 
+	/* Get properties and number of properties */
+	uprop = media_get_uptr(topo->ptr_props);
+	if (!uprop) {
+		topo->num_props = 0;
+		topo->props_payload_size = 0;
+		media_device_for_each_prop(prop, mdev) {
+			topo->props_payload_size += prop->payload_size;
+			topo->num_props++;
+		}
+		return ret;
+	}
+
+	payload_offset = topo->num_props * sizeof(*uprop);
+	i = 0;
+	media_device_for_each_entity(entity, mdev) {
+		long res = copy_props_to_user(topo, &i, &payload_size,
+					      &payload_offset,
+					      &entity->props, uprop);
+		if (!ret)
+			ret = res;
+	}
+	media_device_for_each_pad(pad, mdev) {
+		long res = copy_props_to_user(topo, &i, &payload_size,
+					      &payload_offset,
+					      &pad->props, uprop);
+		if (!ret)
+			ret = res;
+	}
+	topo->num_props = i;
+	topo->props_payload_size = payload_size;
 	return ret;
 }
 
@@ -398,9 +489,10 @@ static long copy_arg_to_user(void __user *uarg, void *karg, unsigned int cmd)
 /* Do acquire the graph mutex */
 #define MEDIA_IOC_FL_GRAPH_MUTEX	BIT(0)
 
-#define MEDIA_IOC_ARG(__cmd, func, fl, from_user, to_user)		\
+#define MEDIA_IOC_ARG(__cmd, alts, func, fl, from_user, to_user)	\
 	[_IOC_NR(MEDIA_IOC_##__cmd)] = {				\
 		.cmd = MEDIA_IOC_##__cmd,				\
+		.alternatives = (alts),					\
 		.fn = (long (*)(struct media_device *, void *))func,	\
 		.flags = fl,						\
 		.arg_from_user = from_user,				\
@@ -408,23 +500,32 @@ static long copy_arg_to_user(void __user *uarg, void *karg, unsigned int cmd)
 	}
 
 #define MEDIA_IOC(__cmd, func, fl)					\
-	MEDIA_IOC_ARG(__cmd, func, fl, copy_arg_from_user, copy_arg_to_user)
+	MEDIA_IOC_ARG(__cmd, NULL, func, fl, copy_arg_from_user, copy_arg_to_user)
+#define MEDIA_IOC_ALTS(__cmd, alts, func, fl)				\
+	MEDIA_IOC_ARG(__cmd, alts, func, fl, copy_arg_from_user, copy_arg_to_user)
 
 /* the table is indexed by _IOC_NR(cmd) */
 struct media_ioctl_info {
 	unsigned int cmd;
+	const unsigned int *alternatives;
 	unsigned short flags;
 	long (*fn)(struct media_device *dev, void *arg);
 	long (*arg_from_user)(void *karg, void __user *uarg, unsigned int cmd);
 	long (*arg_to_user)(void __user *uarg, void *karg, unsigned int cmd);
 };
 
+static const unsigned int topo_alts[] = {
+	/* Old MEDIA_IOC_G_TOPOLOGY without props support */
+	MEDIA_IOC_G_TOPOLOGY_OLD,
+	0
+};
+
 static const struct media_ioctl_info ioctl_info[] = {
 	MEDIA_IOC(DEVICE_INFO, media_device_get_info, MEDIA_IOC_FL_GRAPH_MUTEX),
 	MEDIA_IOC(ENUM_ENTITIES, media_device_enum_entities, MEDIA_IOC_FL_GRAPH_MUTEX),
 	MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX),
 	MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_FL_GRAPH_MUTEX),
-	MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX),
+	MEDIA_IOC_ALTS(G_TOPOLOGY, topo_alts, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX),
 };
 
 static long media_device_ioctl(struct file *filp, unsigned int cmd,
@@ -437,17 +538,29 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
 	char __karg[256], *karg = __karg;
 	long ret;
 
-	if (_IOC_NR(cmd) >= ARRAY_SIZE(ioctl_info)
-	    || ioctl_info[_IOC_NR(cmd)].cmd != cmd)
+	if (_IOC_NR(cmd) >= ARRAY_SIZE(ioctl_info))
 		return -ENOIOCTLCMD;
 
 	info = &ioctl_info[_IOC_NR(cmd)];
 
+	if (info->cmd != cmd) {
+		const unsigned int *p;
+
+		for (p = info->alternatives; p && *p; p++)
+			if (*p == cmd)
+				break;
+		if (!p || !*p)
+			return -ENOIOCTLCMD;
+	}
+
 	if (_IOC_SIZE(info->cmd) > sizeof(__karg)) {
 		karg = kmalloc(_IOC_SIZE(info->cmd), GFP_KERNEL);
 		if (!karg)
 			return -ENOMEM;
 	}
+	if (_IOC_SIZE(info->cmd) > _IOC_SIZE(cmd))
+		memset(karg + _IOC_SIZE(cmd), 0,
+		       _IOC_SIZE(info->cmd) - _IOC_SIZE(cmd));
 
 	if (info->arg_from_user) {
 		ret = info->arg_from_user(karg, arg, cmd);
@@ -569,6 +682,7 @@ int __must_check media_device_register_entity(struct media_device *mdev,
 					      struct media_entity *entity)
 {
 	struct media_entity_notify *notify, *next;
+	struct media_prop *prop;
 	unsigned int i;
 	int ret;
 
@@ -581,9 +695,8 @@ int __must_check media_device_register_entity(struct media_device *mdev,
 	/* Warn if we apparently re-register an entity */
 	WARN_ON(entity->graph_obj.mdev != NULL);
 	entity->graph_obj.mdev = mdev;
-	INIT_LIST_HEAD(&entity->links);
-	entity->num_links = 0;
-	entity->num_backlinks = 0;
+	if (!entity->inited)
+		media_entity_init(entity);
 
 	if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL))
 		return -ENOMEM;
@@ -603,11 +716,22 @@ int __must_check media_device_register_entity(struct media_device *mdev,
 	/* Initialize media_gobj embedded at the entity */
 	media_gobj_create(mdev, MEDIA_GRAPH_ENTITY, &entity->graph_obj);
 
+	/* Initialize objects at the props */
+	list_for_each_entry(prop, &entity->props, list)
+		media_gobj_create(mdev, MEDIA_GRAPH_PROP,
+			       &prop->graph_obj);
+
 	/* Initialize objects at the pads */
-	for (i = 0; i < entity->num_pads; i++)
+	for (i = 0; i < entity->num_pads; i++) {
 		media_gobj_create(mdev, MEDIA_GRAPH_PAD,
 			       &entity->pads[i].graph_obj);
 
+		/* Initialize objects at the pad props */
+		list_for_each_entry(prop, &entity->pads[i].props, list)
+			media_gobj_create(mdev, MEDIA_GRAPH_PROP,
+					  &prop->graph_obj);
+	}
+
 	/* invoke entity_notify callbacks */
 	list_for_each_entry_safe(notify, next, &mdev->entity_notify, list)
 		notify->notify(entity, notify->notify_data);
@@ -635,6 +759,18 @@ int __must_check media_device_register_entity(struct media_device *mdev,
 }
 EXPORT_SYMBOL_GPL(media_device_register_entity);
 
+static void media_device_free_props(struct list_head *list)
+{
+	while (!list_empty(list)) {
+		struct media_prop *prop;
+
+		prop = list_first_entry(list, struct media_prop, list);
+		list_del(&prop->list);
+		media_gobj_destroy(&prop->graph_obj);
+		kfree(prop);
+	}
+}
+
 static void __media_device_unregister_entity(struct media_entity *entity)
 {
 	struct media_device *mdev = entity->graph_obj.mdev;
@@ -656,8 +792,13 @@ static void __media_device_unregister_entity(struct media_entity *entity)
 	__media_entity_remove_links(entity);
 
 	/* Remove all pads that belong to this entity */
-	for (i = 0; i < entity->num_pads; i++)
+	for (i = 0; i < entity->num_pads; i++) {
+		media_device_free_props(&entity->pads[i].props);
 		media_gobj_destroy(&entity->pads[i].graph_obj);
+	}
+
+	/* Remove all props that belong to this entity */
+	media_device_free_props(&entity->props);
 
 	/* Remove the entity */
 	media_gobj_destroy(&entity->graph_obj);
@@ -696,6 +837,7 @@ void media_device_init(struct media_device *mdev)
 	INIT_LIST_HEAD(&mdev->interfaces);
 	INIT_LIST_HEAD(&mdev->pads);
 	INIT_LIST_HEAD(&mdev->links);
+	INIT_LIST_HEAD(&mdev->props);
 	INIT_LIST_HEAD(&mdev->entity_notify);
 	mutex_init(&mdev->graph_mutex);
 	ida_init(&mdev->entity_internal_idx);
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 3498551e618e..fec681a4dc5f 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -34,6 +34,8 @@ static inline const char *gobj_type(enum media_gobj_type type)
 		return "link";
 	case MEDIA_GRAPH_INTF_DEVNODE:
 		return "intf-devnode";
+	case MEDIA_GRAPH_PROP:
+		return "prop";
 	default:
 		return "unknown";
 	}
@@ -106,7 +108,7 @@ static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
 	switch (media_type(gobj)) {
 	case MEDIA_GRAPH_ENTITY:
 		dev_dbg(gobj->mdev->dev,
-			"%s id %u: entity '%s'\n",
+			"%s id 0x%08x: entity '%s'\n",
 			event_name, media_id(gobj),
 			gobj_to_entity(gobj)->name);
 		break;
@@ -115,7 +117,7 @@ static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
 		struct media_link *link = gobj_to_link(gobj);
 
 		dev_dbg(gobj->mdev->dev,
-			"%s id %u: %s link id %u ==> id %u\n",
+			"%s id 0x%08x: %s link id 0x%08x ==> id 0x%08x\n",
 			event_name, media_id(gobj),
 			media_type(link->gobj0) == MEDIA_GRAPH_PAD ?
 				"data" : "interface",
@@ -128,7 +130,7 @@ static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
 		struct media_pad *pad = gobj_to_pad(gobj);
 
 		dev_dbg(gobj->mdev->dev,
-			"%s id %u: %s%spad '%s':%d\n",
+			"%s id 0x%08x: %s%spad '%s':%d\n",
 			event_name, media_id(gobj),
 			pad->flags & MEDIA_PAD_FL_SINK   ? "sink " : "",
 			pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "",
@@ -141,12 +143,22 @@ static void dev_dbg_obj(const char *event_name,  struct media_gobj *gobj)
 		struct media_intf_devnode *devnode = intf_to_devnode(intf);
 
 		dev_dbg(gobj->mdev->dev,
-			"%s id %u: intf_devnode %s - major: %d, minor: %d\n",
+			"%s id 0x%08x: intf_devnode %s - major: %d, minor: %d\n",
 			event_name, media_id(gobj),
 			intf_type(intf),
 			devnode->major, devnode->minor);
 		break;
 	}
+	case MEDIA_GRAPH_PROP:
+	{
+		struct media_prop *prop = gobj_to_prop(gobj);
+
+		dev_dbg(gobj->mdev->dev,
+			"%s id 0x%08x: prop '%s':0x%08x\n",
+			event_name, media_id(gobj),
+			prop->name, media_id(prop->owner));
+		break;
+	}
 	}
 #endif
 }
@@ -175,6 +187,9 @@ void media_gobj_create(struct media_device *mdev,
 	case MEDIA_GRAPH_INTF_DEVNODE:
 		list_add_tail(&gobj->list, &mdev->interfaces);
 		break;
+	case MEDIA_GRAPH_PROP:
+		list_add_tail(&gobj->list, &mdev->props);
+		break;
 	}
 
 	mdev->topology_version++;
@@ -212,6 +227,8 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
 	if (num_pads >= MEDIA_ENTITY_MAX_PADS)
 		return -E2BIG;
 
+	if (!entity->inited)
+		media_entity_init(entity);
 	entity->num_pads = num_pads;
 	entity->pads = pads;
 
@@ -221,6 +238,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
 	for (i = 0; i < num_pads; i++) {
 		pads[i].entity = entity;
 		pads[i].index = i;
+		INIT_LIST_HEAD(&pads[i].props);
 		if (mdev)
 			media_gobj_create(mdev, MEDIA_GRAPH_PAD,
 					&entity->pads[i].graph_obj);
@@ -233,6 +251,59 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
 }
 EXPORT_SYMBOL_GPL(media_entity_pads_init);
 
+static struct media_prop *media_create_prop(struct media_gobj *owner, u32 type,
+		const char *name, u64 val, const void *ptr, u32 payload_size)
+{
+	struct media_prop *prop = kzalloc(sizeof(*prop) + payload_size,
+					  GFP_KERNEL);
+
+	if (!prop)
+		return NULL;
+	prop->type = type;
+	strlcpy(prop->name, name, sizeof(prop->name));
+	if (owner->mdev)
+		media_gobj_create(owner->mdev, MEDIA_GRAPH_PROP,
+				  &prop->graph_obj);
+	prop->owner = owner;
+	if (payload_size) {
+		prop->string = (char *)&prop[1];
+		memcpy(prop->string, ptr, payload_size);
+		prop->payload_size = payload_size;
+	} else {
+		prop->uval = val;
+	}
+	return prop;
+}
+
+int media_entity_add_prop(struct media_entity *ent, u32 type,
+		const char *name, u64 val, const void *ptr, u32 payload_size)
+{
+	struct media_prop *prop;
+
+	if (!ent->inited)
+		media_entity_init(ent);
+	prop = media_create_prop(&ent->graph_obj, type,
+				 name, val, ptr, payload_size);
+	if (!prop)
+		return -ENOMEM;
+	list_add_tail(&prop->list, &ent->props);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(media_entity_add_prop);
+
+int media_pad_add_prop(struct media_pad *pad, u32 type,
+		const char *name, u64 val, const void *ptr, u32 payload_size)
+{
+	struct media_prop *prop = media_create_prop(&pad->graph_obj, type,
+						name, val, ptr, payload_size);
+
+	if (!prop)
+		return -ENOMEM;
+	list_add_tail(&prop->list, &pad->props);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(media_pad_add_prop);
+
 /* -----------------------------------------------------------------------------
  * Graph traversal
  */
diff --git a/include/media/media-device.h b/include/media/media-device.h
index bcc6ec434f1f..a30a931df00b 100644
--- a/include/media/media-device.h
+++ b/include/media/media-device.h
@@ -78,6 +78,7 @@ struct media_device_ops {
  * @interfaces:	List of registered interfaces
  * @pads:	List of registered pads
  * @links:	List of registered links
+ * @props:	List of registered properties
  * @entity_notify: List of registered entity_notify callbacks
  * @graph_mutex: Protects access to struct media_device data
  * @pm_count_walk: Graph walk for power state walk. Access serialised using
@@ -144,6 +145,7 @@ struct media_device {
 	struct list_head interfaces;
 	struct list_head pads;
 	struct list_head links;
+	struct list_head props;
 
 	/* notify callback list invoked when a new entity is registered */
 	struct list_head entity_notify;
@@ -382,6 +384,10 @@ void media_device_unregister_entity_notify(struct media_device *mdev,
 #define media_device_for_each_link(link, mdev)			\
 	list_for_each_entry(link, &(mdev)->links, graph_obj.list)
 
+/* Iterate over all props. */
+#define media_device_for_each_prop(prop, mdev)			\
+	list_for_each_entry(prop, &(mdev)->props, graph_obj.list)
+
 /**
  * media_device_pci_init() - create and initialize a
  *	struct &media_device from a PCI device.
diff --git a/include/media/media-entity.h b/include/media/media-entity.h
index 3aa3d58d1d58..8bb4457b8b15 100644
--- a/include/media/media-entity.h
+++ b/include/media/media-entity.h
@@ -36,12 +36,14 @@
  * @MEDIA_GRAPH_LINK:		Identify a media link
  * @MEDIA_GRAPH_INTF_DEVNODE:	Identify a media Kernel API interface via
  *				a device node
+ * @MEDIA_GRAPH_PROP:		Identify a media property
  */
 enum media_gobj_type {
 	MEDIA_GRAPH_ENTITY,
 	MEDIA_GRAPH_PAD,
 	MEDIA_GRAPH_LINK,
 	MEDIA_GRAPH_INTF_DEVNODE,
+	MEDIA_GRAPH_PROP,
 };
 
 #define MEDIA_BITS_PER_TYPE		8
@@ -164,12 +166,44 @@ struct media_link {
  * @flags:	Pad flags, as defined in
  *		:ref:`include/uapi/linux/media.h <media_header>`
  *		(seek for ``MEDIA_PAD_FL_*``)
+ * @num_props:	Number of pad properties
+ * @props:	The list pad properties
  */
 struct media_pad {
 	struct media_gobj graph_obj;	/* must be first field in struct */
 	struct media_entity *entity;
 	u16 index;
 	unsigned long flags;
+	u16 num_props;
+	struct list_head props;
+};
+
+/**
+ * struct media_prop - A media property graph object.
+ *
+ * @graph_obj:	Embedded structure containing the media object common data
+ * @list:	Linked list associated with the object that owns the link.
+ * @owner:	Graph object this property belongs to
+ * @index:	Property index for the owner property array, numbered from 0 to n
+ * @type:	Property type
+ * @payload_size: Property payload size (i.e. additional bytes beyond this struct)
+ * @name:	Property name
+ * @uval:	Property value (unsigned)
+ * @sval:	Property value (signed)
+ * @string:	Property string value
+ */
+struct media_prop {
+	struct media_gobj graph_obj;	/* must be first field in struct */
+	struct list_head list;
+	struct media_gobj *owner;
+	u32 type;
+	u32 payload_size;
+	char name[32];
+	union {
+		u64 uval;
+		s64 sval;
+		char *string;
+	};
 };
 
 /**
@@ -236,6 +270,7 @@ enum media_entity_type {
  * @flags:	Entity flags, as defined in
  *		:ref:`include/uapi/linux/media.h <media_header>`
  *		(seek for ``MEDIA_ENT_FL_*``)
+ * @inited:	This struct was initialized.
  * @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
@@ -243,6 +278,7 @@ enum media_entity_type {
  *		re-used if entities are unregistered or registered again.
  * @pads:	Pads array with the size defined by @num_pads.
  * @links:	List of data links.
+ * @props:	List of entity properties.
  * @ops:	Entity operations.
  * @stream_count: Stream count for the entity.
  * @use_count:	Use count for the entity.
@@ -270,6 +306,7 @@ struct media_entity {
 	enum media_entity_type obj_type;
 	u32 function;
 	unsigned long flags;
+	bool inited;
 
 	u16 num_pads;
 	u16 num_links;
@@ -278,6 +315,7 @@ struct media_entity {
 
 	struct media_pad *pads;
 	struct list_head links;
+	struct list_head props;
 
 	const struct media_entity_operations *ops;
 
@@ -332,6 +370,20 @@ struct media_intf_devnode {
 	u32				minor;
 };
 
+/**
+ * media_entity_init() - initialize the media entity struct
+ *
+ * @entity:	pointer to &media_entity
+ */
+static inline void media_entity_init(struct media_entity *entity)
+{
+	INIT_LIST_HEAD(&entity->links);
+	INIT_LIST_HEAD(&entity->props);
+	entity->num_links = 0;
+	entity->num_backlinks = 0;
+	entity->inited = true;
+}
+
 /**
  * media_entity_id() - return the media entity graph object id
  *
@@ -565,6 +617,15 @@ static inline bool media_entity_enum_intersects(
 #define gobj_to_intf(gobj) \
 		container_of(gobj, struct media_interface, graph_obj)
 
+/**
+ * gobj_to_prop - returns the struct &media_prop pointer from the
+ *	@gobj contained on it.
+ *
+ * @gobj: Pointer to the struct &media_gobj graph object
+ */
+#define gobj_to_prop(gobj) \
+		container_of(gobj, struct media_prop, graph_obj)
+
 /**
  * intf_to_devnode - returns the struct media_intf_devnode pointer from the
  *	@intf contained on it.
@@ -727,6 +788,131 @@ int media_create_pad_links(const struct media_device *mdev,
 
 void __media_entity_remove_links(struct media_entity *entity);
 
+/**
+ * media_entity_add_prop() - Add property to entity
+ *
+ * @entity:	entity where to add the property
+ * @type:	property type
+ * @name:	property name
+ * @val:	property value: use if payload_size == 0
+ * @ptr:	property pointer to payload
+ * @payload_size: property payload size
+ *
+ * Returns 0 on success, or an error on failure.
+ */
+int media_entity_add_prop(struct media_entity *ent, u32 type,
+		const char *name, u64 val, const void *ptr, u32 payload_size);
+
+/**
+ * media_pad_add_prop() - Add property to pad
+ *
+ * @pad:	pad where to add the property
+ * @type:	property type
+ * @name:	property name
+ * @val:	property value: use if payload_size == 0
+ * @ptr:	property pointer to payload
+ * @payload_size: property payload size
+ *
+ * Returns 0 on success, or an error on failure.
+ */
+int media_pad_add_prop(struct media_pad *pad, u32 type,
+		const char *name, u64 val, const void *ptr, u32 payload_size);
+
+/**
+ * media_entity_add_prop_u64() - Add u64 property to entity
+ *
+ * @entity:	entity where to add the property
+ * @name:	property name
+ * @val:	property value
+ *
+ * Returns 0 on success, or an error on failure.
+ */
+static inline int media_entity_add_prop_u64(struct media_entity *entity,
+					    const char *name, u64 val)
+{
+	return media_entity_add_prop(entity, MEDIA_PROP_TYPE_U64,
+				     name, val, NULL, 0);
+}
+
+/**
+ * media_entity_add_prop_s64() - Add s64 property to entity
+ *
+ * @entity:	entity where to add the property
+ * @name:	property name
+ * @val:	property value
+ *
+ * Returns 0 on success, or an error on failure.
+ */
+static inline int media_entity_add_prop_s64(struct media_entity *entity,
+					    const char *name, s64 val)
+{
+	return media_entity_add_prop(entity, MEDIA_PROP_TYPE_S64,
+				     name, (u64)val, NULL, 0);
+}
+
+/**
+ * media_entity_add_prop_string() - Add string property to entity
+ *
+ * @entity:	entity where to add the property
+ * @name:	property name
+ * @string:	property string value
+ *
+ * Returns 0 on success, or an error on failure.
+ */
+static inline int media_entity_add_prop_string(struct media_entity *entity,
+					const char *name, const char *string)
+{
+	return media_entity_add_prop(entity, MEDIA_PROP_TYPE_STRING,
+				     name, 0, string, strlen(string) + 1);
+}
+
+/**
+ * media_pad_add_prop_u64() - Add u64 property to pad
+ *
+ * @pad:	pad where to add the property
+ * @name:	property name
+ * @val:	property value
+ *
+ * Returns 0 on success, or an error on failure.
+ */
+static inline int media_pad_add_prop_u64(struct media_pad *pad,
+					 const char *name, u64 val)
+{
+	return media_pad_add_prop(pad, MEDIA_PROP_TYPE_U64, name, val, NULL, 0);
+}
+
+/**
+ * media_pad_add_prop_s64() - Add s64 property to pad
+ *
+ * @pad:	pad where to add the property
+ * @name:	property name
+ * @val:	property value
+ *
+ * Returns 0 on success, or an error on failure.
+ */
+static inline int media_pad_add_prop_s64(struct media_pad *pad,
+					 const char *name, s64 val)
+{
+	return media_pad_add_prop(pad, MEDIA_PROP_TYPE_S64,
+				  name, (u64)val, NULL, 0);
+}
+
+/**
+ * media_pad_add_prop_string() - Add string property to pad
+ *
+ * @pad:	pad where to add the property
+ * @name:	property name
+ * @string:	property string value
+ *
+ * Returns 0 on success, or an error on failure.
+ */
+static inline int media_pad_add_prop_string(struct media_pad *pad,
+					const char *name, const char *string)
+{
+	return media_pad_add_prop(pad, MEDIA_PROP_TYPE_STRING,
+				  name, 0, string, strlen(string) + 1);
+}
+
 /**
  * media_entity_remove_links() - remove all links associated with an entity
  *
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFCv2 PATCH 3/3] vimc: add test properties
  2018-08-07 10:28 [RFCv2 PATCH 0/3] Media Controller Properties Hans Verkuil
  2018-08-07 10:28 ` [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support Hans Verkuil
  2018-08-07 10:28 ` [RFCv2 PATCH 2/3] media: add support for properties Hans Verkuil
@ 2018-08-07 10:28 ` Hans Verkuil
  2 siblings, 0 replies; 9+ messages in thread
From: Hans Verkuil @ 2018-08-07 10:28 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/platform/vimc/vimc-common.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c
index 617415c224fe..db8a8d1eca54 100644
--- a/drivers/media/platform/vimc/vimc-common.c
+++ b/drivers/media/platform/vimc/vimc-common.c
@@ -452,6 +452,24 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
 		goto err_clean_m_ent;
 	}
 
+	ret = media_entity_add_prop_u64(&sd->entity, "u64", ~1);
+	if (!ret)
+		ret = media_entity_add_prop_s64(&sd->entity, "s64", -5);
+	if (!ret)
+		ret = media_entity_add_prop_string(&sd->entity, "string",
+						   sd->name);
+	if (!ret)
+		ret = media_pad_add_prop_u64(&sd->entity.pads[num_pads - 1],
+					     "u64", ~1);
+	if (!ret)
+		ret = media_pad_add_prop_s64(&sd->entity.pads[num_pads - 1],
+					     "s64", -5);
+	if (!ret)
+		ret = media_pad_add_prop_string(&sd->entity.pads[0],
+						"string", sd->name);
+	if (ret)
+		goto err_clean_m_ent;
+
 	return 0;
 
 err_clean_m_ent:
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support
  2018-08-07 10:28 ` [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support Hans Verkuil
@ 2018-08-08  7:11   ` Hans Verkuil
  2018-09-04 13:01   ` Sakari Ailus
  1 sibling, 0 replies; 9+ messages in thread
From: Hans Verkuil @ 2018-08-08  7:11 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil

On 08/07/2018 12:28 PM, Hans Verkuil wrote:
> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Add a new topology struct that includes properties.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  include/uapi/linux/media.h | 40 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
> 
> diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
> index 36f76e777ef9..1910c091601e 100644
> --- a/include/uapi/linux/media.h
> +++ b/include/uapi/linux/media.h
> @@ -342,6 +342,40 @@ struct media_v2_link {
>  	__u32 reserved[6];
>  } __attribute__ ((packed));
>  
> +#define MEDIA_PROP_TYPE_U64	1
> +#define MEDIA_PROP_TYPE_S64	2
> +#define MEDIA_PROP_TYPE_STRING	3
> +
> +/**
> + * struct media_v2_prop - A media property
> + *
> + * @id:		The unique non-zero ID of this property
> + * @owner_id:	The ID of the object this property belongs to
> + * @type:	Property type
> + * @flags:	Property flags
> + * @payload_size: Property payload size, 0 for U64/S64
> + * @payload_offset: Property payload starts at this offset from &prop.id.
> + *		This is 0 for U64/S64.
> + * @reserved:	Property reserved field, will be zeroed.
> + * @name:	Property name
> + * @uval:	Property value (unsigned)
> + * @sval:	Property value (signed)
> + */
> +struct media_v2_prop {
> +	__u32 id;
> +	__u32 owner_id;
> +	__u32 type;
> +	__u32 flags;
> +	__u32 payload_size;
> +	__u32 payload_offset;
> +	__u32 reserved[18];
> +	char name[32];
> +	union {
> +		__u64 uval;
> +		__s64 sval;
> +	};

I'm inclined to drop this union and always use payload_size/offset.

Just add simple access functions here to get to the payload:

static inline const char *media_prop2s(const struct media_v2_prop *prop)
{
        return (const char *)prop + prop->payload_offset;
}

static inline __u64 media_prop2u64(const struct media_v2_prop *prop)
{
        return *(const __u64 *)((const char *)prop + prop->payload_offset);
}

static inline __s64 media_prop2s64(const struct media_v2_prop *prop)
{
        return *(const __s64 *)((const char *)prop + prop->payload_offset);
}

Regards,

	Hans

> +} __attribute__ ((packed));
> +
>  struct media_v2_topology {
>  	__u64 topology_version;
>  
> @@ -360,6 +394,10 @@ struct media_v2_topology {
>  	__u32 num_links;
>  	__u32 reserved4;
>  	__u64 ptr_links;
> +
> +	__u32 num_props;
> +	__u32 props_payload_size;
> +	__u64 ptr_props;
>  } __attribute__ ((packed));
>  
>  /* ioctls */
> @@ -368,6 +406,8 @@ struct media_v2_topology {
>  #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)
> +/* Old MEDIA_IOC_G_TOPOLOGY ioctl without props support */
> +#define MEDIA_IOC_G_TOPOLOGY_OLD 0xc0487c04
>  #define MEDIA_IOC_G_TOPOLOGY	_IOWR('|', 0x04, struct media_v2_topology)
>  
>  #ifndef __KERNEL__
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support
  2018-08-07 10:28 ` [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support Hans Verkuil
  2018-08-08  7:11   ` Hans Verkuil
@ 2018-09-04 13:01   ` Sakari Ailus
  2018-09-04 13:50     ` Hans Verkuil
  1 sibling, 1 reply; 9+ messages in thread
From: Sakari Ailus @ 2018-09-04 13:01 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: linux-media, Hans Verkuil

Hi Hans,

Thanks for the set.

On Tue, Aug 07, 2018 at 12:28:45PM +0200, Hans Verkuil wrote:
> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Add a new topology struct that includes properties.
> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  include/uapi/linux/media.h | 40 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
> 
> diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
> index 36f76e777ef9..1910c091601e 100644
> --- a/include/uapi/linux/media.h
> +++ b/include/uapi/linux/media.h
> @@ -342,6 +342,40 @@ struct media_v2_link {
>  	__u32 reserved[6];
>  } __attribute__ ((packed));
>  
> +#define MEDIA_PROP_TYPE_U64	1
> +#define MEDIA_PROP_TYPE_S64	2
> +#define MEDIA_PROP_TYPE_STRING	3
> +
> +/**
> + * struct media_v2_prop - A media property
> + *
> + * @id:		The unique non-zero ID of this property
> + * @owner_id:	The ID of the object this property belongs to

This assumes everything has a graph object ID. Speaking of "everything",
one of the use cases for this could be telling the user whether the media
device registration is finished.

One approach could be to create a special graph object with a constant ID
for that purpose. As the type is a part of the ID field, we could simply
create a new type of constant objects.

On a sidenote, the proposed API effectively prohibits conveying structured
data. One use case for that would be to tell about camera modules. We don't
have that right now as part of the uAPI as there's nothing the kernel
currently knows about camera modules --- because there's nothing to control
there. The user space would still be interested in knowing quite a few
parameters of these devices which means the concept of the camera module
would be good to have in precisely this kind of an interface. What should
be there could in practice be what does the module contain (some of the
components are sub-devices whereas some would not be, such as an IR filter
or the lens) and their parameters (e.g. focal length).

I'm not demanding this must be a part of the API in the beginning, however
this was one of the reasons why I originally proposed using JSON:

<URL:https://www.spinics.net/lists/linux-media/msg90160.html>

The downside with JSON would be that it does not fit very well with the
rest of the MC API.

> + * @type:	Property type
> + * @flags:	Property flags
> + * @payload_size: Property payload size, 0 for U64/S64
> + * @payload_offset: Property payload starts at this offset from &prop.id.
> + *		This is 0 for U64/S64.
> + * @reserved:	Property reserved field, will be zeroed.
> + * @name:	Property name
> + * @uval:	Property value (unsigned)
> + * @sval:	Property value (signed)
> + */
> +struct media_v2_prop {
> +	__u32 id;
> +	__u32 owner_id;
> +	__u32 type;
> +	__u32 flags;
> +	__u32 payload_size;
> +	__u32 payload_offset;
> +	__u32 reserved[18];

That's plenty. What is the typical size of the properties array for a media
device with, say, a few hundred entities with some four pads each, linked
with a single link on average?

> +	char name[32];

Is 32 enough? For controls and formats it's been sometimes a bit limiting.

Another approach could be to make this variable size, but that would make
parsing a little bit more complicated. As you already have separated the
property descriptor and the payload, that wouldn't be a major change
anymore.

> +	union {
> +		__u64 uval;
> +		__s64 sval;
> +	};
> +} __attribute__ ((packed));
> +
>  struct media_v2_topology {
>  	__u64 topology_version;
>  
> @@ -360,6 +394,10 @@ struct media_v2_topology {
>  	__u32 num_links;
>  	__u32 reserved4;
>  	__u64 ptr_links;
> +
> +	__u32 num_props;
> +	__u32 props_payload_size;
> +	__u64 ptr_props;
>  } __attribute__ ((packed));
>  
>  /* ioctls */
> @@ -368,6 +406,8 @@ struct media_v2_topology {
>  #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)
> +/* Old MEDIA_IOC_G_TOPOLOGY ioctl without props support */
> +#define MEDIA_IOC_G_TOPOLOGY_OLD 0xc0487c04
>  #define MEDIA_IOC_G_TOPOLOGY	_IOWR('|', 0x04, struct media_v2_topology)
>  
>  #ifndef __KERNEL__

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support
  2018-09-04 13:01   ` Sakari Ailus
@ 2018-09-04 13:50     ` Hans Verkuil
  2018-09-04 15:43       ` Sakari Ailus
  0 siblings, 1 reply; 9+ messages in thread
From: Hans Verkuil @ 2018-09-04 13:50 UTC (permalink / raw)
  To: Sakari Ailus, Hans Verkuil; +Cc: linux-media, Hans Verkuil

On 09/04/18 15:01, Sakari Ailus wrote:
> Hi Hans,
> 
> Thanks for the set.
> 
> On Tue, Aug 07, 2018 at 12:28:45PM +0200, Hans Verkuil wrote:
>> From: Hans Verkuil <hans.verkuil@cisco.com>
>>
>> Add a new topology struct that includes properties.
>>
>> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
>> ---
>>  include/uapi/linux/media.h | 40 ++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 40 insertions(+)
>>
>> diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
>> index 36f76e777ef9..1910c091601e 100644
>> --- a/include/uapi/linux/media.h
>> +++ b/include/uapi/linux/media.h
>> @@ -342,6 +342,40 @@ struct media_v2_link {
>>  	__u32 reserved[6];
>>  } __attribute__ ((packed));
>>  
>> +#define MEDIA_PROP_TYPE_U64	1
>> +#define MEDIA_PROP_TYPE_S64	2
>> +#define MEDIA_PROP_TYPE_STRING	3
>> +
>> +/**
>> + * struct media_v2_prop - A media property
>> + *
>> + * @id:		The unique non-zero ID of this property
>> + * @owner_id:	The ID of the object this property belongs to
> 
> This assumes everything has a graph object ID. Speaking of "everything",
> one of the use cases for this could be telling the user whether the media
> device registration is finished.
> 
> One approach could be to create a special graph object with a constant ID
> for that purpose. As the type is a part of the ID field, we could simply
> create a new type of constant objects.

Why would you use properties for that? Why not just allow polling for
exceptions (i.e. new events) on the media device node, similar to events
for V4L2? It's very easy to use with select() et al.

> On a sidenote, the proposed API effectively prohibits conveying structured
> data. One use case for that would be to tell about camera modules. We don't
> have that right now as part of the uAPI as there's nothing the kernel
> currently knows about camera modules --- because there's nothing to control
> there. The user space would still be interested in knowing quite a few
> parameters of these devices which means the concept of the camera module
> would be good to have in precisely this kind of an interface. What should
> be there could in practice be what does the module contain (some of the
> components are sub-devices whereas some would not be, such as an IR filter
> or the lens) and their parameters (e.g. focal length).

You can easily (but indeed not yet implemented in this initial version) create
hierarchical properties by simply setting the owner_id to a parent property.

And you obviously need to carefully define and document how data is
represented in properties.

If people feel strongly enough about this, then I can implement it in the
next RFC. But I want feedback on this RFC first.

> I'm not demanding this must be a part of the API in the beginning, however
> this was one of the reasons why I originally proposed using JSON:
> 
> <URL:https://www.spinics.net/lists/linux-media/msg90160.html>
> 
> The downside with JSON would be that it does not fit very well with the
> rest of the MC API.
> 
>> + * @type:	Property type
>> + * @flags:	Property flags
>> + * @payload_size: Property payload size, 0 for U64/S64
>> + * @payload_offset: Property payload starts at this offset from &prop.id.
>> + *		This is 0 for U64/S64.
>> + * @reserved:	Property reserved field, will be zeroed.
>> + * @name:	Property name
>> + * @uval:	Property value (unsigned)
>> + * @sval:	Property value (signed)
>> + */
>> +struct media_v2_prop {
>> +	__u32 id;
>> +	__u32 owner_id;
>> +	__u32 type;
>> +	__u32 flags;
>> +	__u32 payload_size;
>> +	__u32 payload_offset;
>> +	__u32 reserved[18];
> 
> That's plenty. What is the typical size of the properties array for a media
> device with, say, a few hundred entities with some four pads each, linked
> with a single link on average?
> 
>> +	char name[32];
> 
> Is 32 enough? For controls and formats it's been sometimes a bit limiting.
> 
> Another approach could be to make this variable size, but that would make
> parsing a little bit more complicated. As you already have separated the
> property descriptor and the payload, that wouldn't be a major change
> anymore.

I'll have to experiment a bit with that.

Thanks for looking at this!

Regards,

	Hans

> 
>> +	union {
>> +		__u64 uval;
>> +		__s64 sval;
>> +	};
>> +} __attribute__ ((packed));
>> +
>>  struct media_v2_topology {
>>  	__u64 topology_version;
>>  
>> @@ -360,6 +394,10 @@ struct media_v2_topology {
>>  	__u32 num_links;
>>  	__u32 reserved4;
>>  	__u64 ptr_links;
>> +
>> +	__u32 num_props;
>> +	__u32 props_payload_size;
>> +	__u64 ptr_props;
>>  } __attribute__ ((packed));
>>  
>>  /* ioctls */
>> @@ -368,6 +406,8 @@ struct media_v2_topology {
>>  #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)
>> +/* Old MEDIA_IOC_G_TOPOLOGY ioctl without props support */
>> +#define MEDIA_IOC_G_TOPOLOGY_OLD 0xc0487c04
>>  #define MEDIA_IOC_G_TOPOLOGY	_IOWR('|', 0x04, struct media_v2_topology)
>>  
>>  #ifndef __KERNEL__
> 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support
  2018-09-04 13:50     ` Hans Verkuil
@ 2018-09-04 15:43       ` Sakari Ailus
  2018-09-04 15:44         ` Sakari Ailus
  0 siblings, 1 reply; 9+ messages in thread
From: Sakari Ailus @ 2018-09-04 15:43 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: Hans Verkuil, linux-media, Hans Verkuil

Hi Hans,

On Tue, Sep 04, 2018 at 03:50:33PM +0200, Hans Verkuil wrote:
> On 09/04/18 15:01, Sakari Ailus wrote:
> > Hi Hans,
> > 
> > Thanks for the set.
> > 
> > On Tue, Aug 07, 2018 at 12:28:45PM +0200, Hans Verkuil wrote:
> >> From: Hans Verkuil <hans.verkuil@cisco.com>
> >>
> >> Add a new topology struct that includes properties.
> >>
> >> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> >> ---
> >>  include/uapi/linux/media.h | 40 ++++++++++++++++++++++++++++++++++++++
> >>  1 file changed, 40 insertions(+)
> >>
> >> diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h
> >> index 36f76e777ef9..1910c091601e 100644
> >> --- a/include/uapi/linux/media.h
> >> +++ b/include/uapi/linux/media.h
> >> @@ -342,6 +342,40 @@ struct media_v2_link {
> >>  	__u32 reserved[6];
> >>  } __attribute__ ((packed));
> >>  
> >> +#define MEDIA_PROP_TYPE_U64	1
> >> +#define MEDIA_PROP_TYPE_S64	2
> >> +#define MEDIA_PROP_TYPE_STRING	3
> >> +
> >> +/**
> >> + * struct media_v2_prop - A media property
> >> + *
> >> + * @id:		The unique non-zero ID of this property
> >> + * @owner_id:	The ID of the object this property belongs to
> > 
> > This assumes everything has a graph object ID. Speaking of "everything",
> > one of the use cases for this could be telling the user whether the media
> > device registration is finished.
> > 
> > One approach could be to create a special graph object with a constant ID
> > for that purpose. As the type is a part of the ID field, we could simply
> > create a new type of constant objects.
> 
> Why would you use properties for that? Why not just allow polling for
> exceptions (i.e. new events) on the media device node, similar to events
> for V4L2? It's very easy to use with select() et al.

Yes, that's needed; there was actually a support for media events on an
older version of my take of the request API.

But events are not all that's needed: how does the user know registration
has finished if it has already happened when the user opens a device?
Event-wise, I think a "topology change" event is all that's needed.

> 
> > On a sidenote, the proposed API effectively prohibits conveying structured
> > data. One use case for that would be to tell about camera modules. We don't
> > have that right now as part of the uAPI as there's nothing the kernel
> > currently knows about camera modules --- because there's nothing to control
> > there. The user space would still be interested in knowing quite a few
> > parameters of these devices which means the concept of the camera module
> > would be good to have in precisely this kind of an interface. What should
> > be there could in practice be what does the module contain (some of the
> > components are sub-devices whereas some would not be, such as an IR filter
> > or the lens) and their parameters (e.g. focal length).
> 
> You can easily (but indeed not yet implemented in this initial version) create
> hierarchical properties by simply setting the owner_id to a parent property.

Good point. For arrays we could e.g. add a new field to struct
media_v2_prop, called e.g. payload_length. I also think we should have the
size (and length) of the property in a specific unit, such as bytes, so the
parser does not have to know a given property type to determine it
correctly.

> 
> And you obviously need to carefully define and document how data is
> represented in properties.
> 
> If people feel strongly enough about this, then I can implement it in the
> next RFC. But I want feedback on this RFC first.

Feel free to go ahead with that but I'm fine with the current scope as
well. Just remember it was one of the use cases. :-)

> 
> > I'm not demanding this must be a part of the API in the beginning, however
> > this was one of the reasons why I originally proposed using JSON:
> > 
> > <URL:https://www.spinics.net/lists/linux-media/msg90160.html>
> > 
> > The downside with JSON would be that it does not fit very well with the
> > rest of the MC API.
> > 
> >> + * @type:	Property type
> >> + * @flags:	Property flags
> >> + * @payload_size: Property payload size, 0 for U64/S64
> >> + * @payload_offset: Property payload starts at this offset from &prop.id.
> >> + *		This is 0 for U64/S64.
> >> + * @reserved:	Property reserved field, will be zeroed.
> >> + * @name:	Property name
> >> + * @uval:	Property value (unsigned)
> >> + * @sval:	Property value (signed)
> >> + */
> >> +struct media_v2_prop {
> >> +	__u32 id;
> >> +	__u32 owner_id;
> >> +	__u32 type;
> >> +	__u32 flags;
> >> +	__u32 payload_size;
> >> +	__u32 payload_offset;
> >> +	__u32 reserved[18];
> > 
> > That's plenty. What is the typical size of the properties array for a media
> > device with, say, a few hundred entities with some four pads each, linked
> > with a single link on average?
> > 
> >> +	char name[32];
> > 
> > Is 32 enough? For controls and formats it's been sometimes a bit limiting.
> > 
> > Another approach could be to make this variable size, but that would make
> > parsing a little bit more complicated. As you already have separated the
> > property descriptor and the payload, that wouldn't be a major change
> > anymore.
> 
> I'll have to experiment a bit with that.
> 
> Thanks for looking at this!

Thanks for working on this! :-)

-- 
Kind regards,

Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support
  2018-09-04 15:43       ` Sakari Ailus
@ 2018-09-04 15:44         ` Sakari Ailus
  0 siblings, 0 replies; 9+ messages in thread
From: Sakari Ailus @ 2018-09-04 15:44 UTC (permalink / raw)
  To: Hans Verkuil; +Cc: Hans Verkuil, linux-media, Hans Verkuil

On Tue, Sep 04, 2018 at 06:43:20PM +0300, Sakari Ailus wrote:
> media_v2_prop, called e.g. payload_length. I also think we should have the
> size (and length) of the property in a specific unit, such as bytes, so the
> parser does not have to know a given property type to determine it
> correctly.

Ah, please ignore this. I see you ended up to the same conclusion yourself
already.

-- 
Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2018-09-04 20:09 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-07 10:28 [RFCv2 PATCH 0/3] Media Controller Properties Hans Verkuil
2018-08-07 10:28 ` [RFCv2 PATCH 1/3] uapi/linux/media.h: add property support Hans Verkuil
2018-08-08  7:11   ` Hans Verkuil
2018-09-04 13:01   ` Sakari Ailus
2018-09-04 13:50     ` Hans Verkuil
2018-09-04 15:43       ` Sakari Ailus
2018-09-04 15:44         ` Sakari Ailus
2018-08-07 10:28 ` [RFCv2 PATCH 2/3] media: add support for properties Hans Verkuil
2018-08-07 10:28 ` [RFCv2 PATCH 3/3] vimc: add test properties Hans Verkuil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).