diff mbox series

[v2,16/30] v4l: subdev: Add [GS]_ROUTING subdev ioctls and operations

Message ID 20181101233144.31507-17-niklas.soderlund+renesas@ragnatech.se (mailing list archive)
State New, archived
Headers show
Series v4l: add support for multiplexed streams | expand

Commit Message

Niklas Söderlund Nov. 1, 2018, 11:31 p.m. UTC
From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>

- Add sink and source streams for multiplexed links
- Copy the argument back in case of an error. This is needed to let the
  caller know the number of routes.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
 drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
 include/media/v4l2-subdev.h           |  7 +++++
 include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
 4 files changed, 94 insertions(+), 1 deletion(-)

Comments

Laurent Pinchart Jan. 15, 2019, 11:51 p.m. UTC | #1
Hi Niklas,

Thank you for the patch.

On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> 
> - Add sink and source streams for multiplexed links
> - Copy the argument back in case of an error. This is needed to let the
>   caller know the number of routes.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
>  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
>  include/media/v4l2-subdev.h           |  7 +++++
>  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++

Missing documentation :-(

>  4 files changed, 94 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index 7de041bae84fb2f2..40406acb51ec0906 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -19,6 +19,7 @@
>  #include <linux/kernel.h>
>  #include <linux/version.h>
>  
> +#include <linux/v4l2-subdev.h>
>  #include <linux/videodev2.h>
>  
>  #include <media/v4l2-common.h>
> @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
>  		}
>  		break;
>  	}
> +
> +	case VIDIOC_SUBDEV_G_ROUTING:
> +	case VIDIOC_SUBDEV_S_ROUTING: {
> +		struct v4l2_subdev_routing *route = parg;
> +
> +		if (route->num_routes > 0) {
> +			if (route->num_routes > 256)
> +				return -EINVAL;
> +
> +			*user_ptr = (void __user *)route->routes;
> +			*kernel_ptr = (void *)&route->routes;
> +			*array_size = sizeof(struct v4l2_subdev_route)
> +				    * route->num_routes;
> +			ret = 1;
> +		}
> +		break;
> +	}
>  	}
>  
>  	return ret;
> @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
>  	 * Some ioctls can return an error, but still have valid
>  	 * results that must be returned.
>  	 */
> -	if (err < 0 && !always_copy)
> +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)

This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
always_copy instead ?

>  		goto out;
>  
>  out_array_args:
> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> index 792f41dffe2329b9..1d3b37cf548fa533 100644
> --- a/drivers/media/v4l2-core/v4l2-subdev.c
> +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
>  
>  	case VIDIOC_SUBDEV_QUERYSTD:
>  		return v4l2_subdev_call(sd, video, querystd, arg);
> +
> +	case VIDIOC_SUBDEV_G_ROUTING:
> +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> +
> +	case VIDIOC_SUBDEV_S_ROUTING: {
> +		struct v4l2_subdev_routing *route = arg;
> +		unsigned int i;
> +
> +		if (route->num_routes > sd->entity.num_pads)
> +			return -EINVAL;
> +
> +		for (i = 0; i < route->num_routes; ++i) {
> +			unsigned int sink = route->routes[i].sink_pad;
> +			unsigned int source = route->routes[i].source_pad;
> +			struct media_pad *pads = sd->entity.pads;
> +
> +			if (sink >= sd->entity.num_pads ||
> +			    source >= sd->entity.num_pads)
> +				return -EINVAL;
> +
> +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> +				return -EINVAL;
> +		}
> +
> +		return v4l2_subdev_call(sd, pad, set_routing, route);
> +	}
>  #endif
> +
>  	default:
>  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
>  	}
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
>   *
>   * @set_frame_desc: set the low level media bus frame parameters, @fd array
>   *                  may be adjusted by the subdev driver to device capabilities.
> + *
> + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.

Please define the purpose of those operations instead of just pointing
to the userspace API.

>   */
>  struct v4l2_subdev_pad_ops {
>  	int (*init_cfg)(struct v4l2_subdev *sd,
> @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
>  			      struct v4l2_mbus_frame_desc *fd);
>  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
>  			      struct v4l2_mbus_frame_desc *fd);
> +	int (*get_routing)(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_routing *route);
> +	int (*set_routing)(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_routing *route);
>  };
>  
>  /**
> diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> index 03970ce3074193e6..af069bfb10ca23a5 100644
> --- a/include/uapi/linux/v4l2-subdev.h
> +++ b/include/uapi/linux/v4l2-subdev.h
> @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
>  	__u32 reserved[8];
>  };
>  
> +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> +
> +/**
> + * struct v4l2_subdev_route - A signal route inside a subdev
> + * @sink_pad: the sink pad
> + * @sink_stream: the sink stream
> + * @source_pad: the source pad
> + * @source_stream: the source stream

At this point in the series there's no concept of multiplexed streams,
so the two fields don't make sense. You may want to reorder patches, or
split this in two.

> + * @flags: route flags:
> + *
> + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> + *	active stream will start when streaming is enabled on a video
> + *	node. Set by the user.

This is very confusing as "stream" isn't defined. The documentation
needs a rewrite with more details.

> + *
> + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> + *	can it be activated and inactivated? Set by the driver.
> + */
> +struct v4l2_subdev_route {
> +	__u32 sink_pad;
> +	__u32 sink_stream;
> +	__u32 source_pad;
> +	__u32 source_stream;
> +	__u32 flags;
> +	__u32 reserved[5];
> +};
> +
> +/**
> + * struct v4l2_subdev_routing - Routing information
> + * @routes: the routes array
> + * @num_routes: the total number of routes in the routes array
> + */
> +struct v4l2_subdev_routing {
> +	struct v4l2_subdev_route *routes;

Missing __user ?

> +	__u32 num_routes;
> +	__u32 reserved[5];
> +};
> +
>  /* Backwards compatibility define --- to be removed */
>  #define v4l2_subdev_edid v4l2_edid
>  
> @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
>  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
>  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
>  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
>  
>  #endif
> -- 
> 2.19.1
>
Sakari Ailus Jan. 22, 2019, 4:14 p.m. UTC | #2
On Wed, Jan 16, 2019 at 01:51:45AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
> 
> Thank you for the patch.
> 
> On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > 
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > 
> > - Add sink and source streams for multiplexed links
> > - Copy the argument back in case of an error. This is needed to let the
> >   caller know the number of routes.
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> >  include/media/v4l2-subdev.h           |  7 +++++
> >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> 
> Missing documentation :-(
> 
> >  4 files changed, 94 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > @@ -19,6 +19,7 @@
> >  #include <linux/kernel.h>
> >  #include <linux/version.h>
> >  
> > +#include <linux/v4l2-subdev.h>
> >  #include <linux/videodev2.h>
> >  
> >  #include <media/v4l2-common.h>
> > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> >  		}
> >  		break;
> >  	}
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = parg;
> > +
> > +		if (route->num_routes > 0) {
> > +			if (route->num_routes > 256)
> > +				return -EINVAL;
> > +
> > +			*user_ptr = (void __user *)route->routes;
> > +			*kernel_ptr = (void *)&route->routes;
> > +			*array_size = sizeof(struct v4l2_subdev_route)
> > +				    * route->num_routes;
> > +			ret = 1;
> > +		}
> > +		break;
> > +	}
> >  	}
> >  
> >  	return ret;
> > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> >  	 * Some ioctls can return an error, but still have valid
> >  	 * results that must be returned.
> >  	 */
> > -	if (err < 0 && !always_copy)
> > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> 
> This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
> always_copy instead ?

Sub-device IOCTLs are partially handled in v4l2-subdev.c, not here. In
particular, __video_do_ioctl() that digs that information from v4l2_ioctls
array is not in the call path for sub-device IOCTLs. So, it'd take a
refactoring of IOCTL handling to change this, which I think should be a
different patchset --- we're already at 30 patches here.

> 
> >  		goto out;
> >  
> >  out_array_args:
> > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> >  
> >  	case VIDIOC_SUBDEV_QUERYSTD:
> >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > +
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = arg;
> > +		unsigned int i;
> > +
> > +		if (route->num_routes > sd->entity.num_pads)
> > +			return -EINVAL;
> > +
> > +		for (i = 0; i < route->num_routes; ++i) {
> > +			unsigned int sink = route->routes[i].sink_pad;
> > +			unsigned int source = route->routes[i].source_pad;
> > +			struct media_pad *pads = sd->entity.pads;
> > +
> > +			if (sink >= sd->entity.num_pads ||
> > +			    source >= sd->entity.num_pads)
> > +				return -EINVAL;
> > +
> > +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> > +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> > +				return -EINVAL;
> > +		}
> > +
> > +		return v4l2_subdev_call(sd, pad, set_routing, route);
> > +	}
> >  #endif
> > +
> >  	default:
> >  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> >  	}
> > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> > --- a/include/media/v4l2-subdev.h
> > +++ b/include/media/v4l2-subdev.h
> > @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> >   *
> >   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> >   *                  may be adjusted by the subdev driver to device capabilities.
> > + *
> > + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> > + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
> 
> Please define the purpose of those operations instead of just pointing
> to the userspace API.
> 
> >   */
> >  struct v4l2_subdev_pad_ops {
> >  	int (*init_cfg)(struct v4l2_subdev *sd,
> > @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> >  			      struct v4l2_mbus_frame_desc *fd);
> >  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> >  			      struct v4l2_mbus_frame_desc *fd);
> > +	int (*get_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> > +	int (*set_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> >  };
> >  
> >  /**
> > diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> > index 03970ce3074193e6..af069bfb10ca23a5 100644
> > --- a/include/uapi/linux/v4l2-subdev.h
> > +++ b/include/uapi/linux/v4l2-subdev.h
> > @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> >  	__u32 reserved[8];
> >  };
> >  
> > +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> > +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> > +
> > +/**
> > + * struct v4l2_subdev_route - A signal route inside a subdev
> > + * @sink_pad: the sink pad
> > + * @sink_stream: the sink stream
> > + * @source_pad: the source pad
> > + * @source_stream: the source stream
> 
> At this point in the series there's no concept of multiplexed streams,
> so the two fields don't make sense. You may want to reorder patches, or
> split this in two.

I think it would make sense to reorder, as adding an IOCTL and then
changing the argument struct would be something to avoid if possible.

> 
> > + * @flags: route flags:
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> > + *	active stream will start when streaming is enabled on a video
> > + *	node. Set by the user.
> 
> This is very confusing as "stream" isn't defined. The documentation
> needs a rewrite with more details.

Yes, we need a little more documentation on this.

> 
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> > + *	can it be activated and inactivated? Set by the driver.
> > + */
> > +struct v4l2_subdev_route {
> > +	__u32 sink_pad;
> > +	__u32 sink_stream;
> > +	__u32 source_pad;
> > +	__u32 source_stream;
> > +	__u32 flags;
> > +	__u32 reserved[5];
> > +};
> > +
> > +/**
> > + * struct v4l2_subdev_routing - Routing information
> > + * @routes: the routes array
> > + * @num_routes: the total number of routes in the routes array
> > + */
> > +struct v4l2_subdev_routing {
> > +	struct v4l2_subdev_route *routes;
> 
> Missing __user ?

We actually don't have any IOCTLs using __u64 pointer values in V4L2. I
wonder what Hans thinks, too. I guess it's the way to go. Compat code is so
awful. :-I

> 
> > +	__u32 num_routes;
> > +	__u32 reserved[5];
> > +};
> > +
> >  /* Backwards compatibility define --- to be removed */
> >  #define v4l2_subdev_edid v4l2_edid
> >  
> > @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
> >  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
> >  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
> >  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> > +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> > +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
> >  
> >  #endif
Laurent Pinchart Jan. 22, 2019, 5 p.m. UTC | #3
Hi Sakari,

On Tue, Jan 22, 2019 at 06:14:57PM +0200, Sakari Ailus wrote:
> On Wed, Jan 16, 2019 at 01:51:45AM +0200, Laurent Pinchart wrote:
> > On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> >> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >> 
> >> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> >> 
> >> - Add sink and source streams for multiplexed links
> >> - Copy the argument back in case of an error. This is needed to let the
> >>   caller know the number of routes.
> >> 
> >> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> >> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> >> ---
> >>  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> >>  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> >>  include/media/v4l2-subdev.h           |  7 +++++
> >>  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> > 
> > Missing documentation :-(
> > 
> >>  4 files changed, 94 insertions(+), 1 deletion(-)
> >> 
> >> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> >> index 7de041bae84fb2f2..40406acb51ec0906 100644
> >> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> >> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> >> @@ -19,6 +19,7 @@
> >>  #include <linux/kernel.h>
> >>  #include <linux/version.h>
> >>  
> >> +#include <linux/v4l2-subdev.h>
> >>  #include <linux/videodev2.h>
> >>  
> >>  #include <media/v4l2-common.h>
> >> @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> >>  		}
> >>  		break;
> >>  	}
> >> +
> >> +	case VIDIOC_SUBDEV_G_ROUTING:
> >> +	case VIDIOC_SUBDEV_S_ROUTING: {
> >> +		struct v4l2_subdev_routing *route = parg;
> >> +
> >> +		if (route->num_routes > 0) {
> >> +			if (route->num_routes > 256)
> >> +				return -EINVAL;
> >> +
> >> +			*user_ptr = (void __user *)route->routes;
> >> +			*kernel_ptr = (void *)&route->routes;
> >> +			*array_size = sizeof(struct v4l2_subdev_route)
> >> +				    * route->num_routes;
> >> +			ret = 1;
> >> +		}
> >> +		break;
> >> +	}
> >>  	}
> >>  
> >>  	return ret;
> >> @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> >>  	 * Some ioctls can return an error, but still have valid
> >>  	 * results that must be returned.
> >>  	 */
> >> -	if (err < 0 && !always_copy)
> >> +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> > 
> > This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
> > always_copy instead ?
> 
> Sub-device IOCTLs are partially handled in v4l2-subdev.c, not here. In
> particular, __video_do_ioctl() that digs that information from v4l2_ioctls
> array is not in the call path for sub-device IOCTLs. So, it'd take a
> refactoring of IOCTL handling to change this, which I think should be a
> different patchset --- we're already at 30 patches here.

I'm OK with that. Could we add a FIXME comment ?

> >>  		goto out;
> >>  
> >>  out_array_args:
> >> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> >> index 792f41dffe2329b9..1d3b37cf548fa533 100644
> >> --- a/drivers/media/v4l2-core/v4l2-subdev.c
> >> +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> >> @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> >>  
> >>  	case VIDIOC_SUBDEV_QUERYSTD:
> >>  		return v4l2_subdev_call(sd, video, querystd, arg);
> >> +
> >> +	case VIDIOC_SUBDEV_G_ROUTING:
> >> +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> >> +
> >> +	case VIDIOC_SUBDEV_S_ROUTING: {
> >> +		struct v4l2_subdev_routing *route = arg;
> >> +		unsigned int i;
> >> +
> >> +		if (route->num_routes > sd->entity.num_pads)
> >> +			return -EINVAL;
> >> +
> >> +		for (i = 0; i < route->num_routes; ++i) {
> >> +			unsigned int sink = route->routes[i].sink_pad;
> >> +			unsigned int source = route->routes[i].source_pad;
> >> +			struct media_pad *pads = sd->entity.pads;
> >> +
> >> +			if (sink >= sd->entity.num_pads ||
> >> +			    source >= sd->entity.num_pads)
> >> +				return -EINVAL;
> >> +
> >> +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> >> +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> >> +				return -EINVAL;
> >> +		}
> >> +
> >> +		return v4l2_subdev_call(sd, pad, set_routing, route);
> >> +	}
> >>  #endif
> >> +
> >>  	default:
> >>  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> >>  	}
> >> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> >> index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> >> --- a/include/media/v4l2-subdev.h
> >> +++ b/include/media/v4l2-subdev.h
> >> @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> >>   *
> >>   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> >>   *                  may be adjusted by the subdev driver to device capabilities.
> >> + *
> >> + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> >> + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
> > 
> > Please define the purpose of those operations instead of just pointing
> > to the userspace API.
> > 
> >>   */
> >>  struct v4l2_subdev_pad_ops {
> >>  	int (*init_cfg)(struct v4l2_subdev *sd,
> >> @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> >>  			      struct v4l2_mbus_frame_desc *fd);
> >>  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> >>  			      struct v4l2_mbus_frame_desc *fd);
> >> +	int (*get_routing)(struct v4l2_subdev *sd,
> >> +			   struct v4l2_subdev_routing *route);
> >> +	int (*set_routing)(struct v4l2_subdev *sd,
> >> +			   struct v4l2_subdev_routing *route);
> >>  };
> >>  
> >>  /**
> >> diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> >> index 03970ce3074193e6..af069bfb10ca23a5 100644
> >> --- a/include/uapi/linux/v4l2-subdev.h
> >> +++ b/include/uapi/linux/v4l2-subdev.h
> >> @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> >>  	__u32 reserved[8];
> >>  };
> >>  
> >> +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> >> +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> >> +
> >> +/**
> >> + * struct v4l2_subdev_route - A signal route inside a subdev
> >> + * @sink_pad: the sink pad
> >> + * @sink_stream: the sink stream
> >> + * @source_pad: the source pad
> >> + * @source_stream: the source stream
> > 
> > At this point in the series there's no concept of multiplexed streams,
> > so the two fields don't make sense. You may want to reorder patches, or
> > split this in two.
> 
> I think it would make sense to reorder, as adding an IOCTL and then
> changing the argument struct would be something to avoid if possible.
> 
> >> + * @flags: route flags:
> >> + *
> >> + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> >> + *	active stream will start when streaming is enabled on a video
> >> + *	node. Set by the user.
> > 
> > This is very confusing as "stream" isn't defined. The documentation
> > needs a rewrite with more details.
> 
> Yes, we need a little more documentation on this.
> 
> >> + *
> >> + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> >> + *	can it be activated and inactivated? Set by the driver.
> >> + */
> >> +struct v4l2_subdev_route {
> >> +	__u32 sink_pad;
> >> +	__u32 sink_stream;
> >> +	__u32 source_pad;
> >> +	__u32 source_stream;
> >> +	__u32 flags;
> >> +	__u32 reserved[5];
> >> +};
> >> +
> >> +/**
> >> + * struct v4l2_subdev_routing - Routing information
> >> + * @routes: the routes array
> >> + * @num_routes: the total number of routes in the routes array
> >> + */
> >> +struct v4l2_subdev_routing {
> >> +	struct v4l2_subdev_route *routes;
> > 
> > Missing __user ?
> 
> We actually don't have any IOCTLs using __u64 pointer values in V4L2. I
> wonder what Hans thinks, too. I guess it's the way to go. Compat code is so
> awful. :-I
> 
> > 
> >> +	__u32 num_routes;
> >> +	__u32 reserved[5];
> >> +};
> >> +
> >>  /* Backwards compatibility define --- to be removed */
> >>  #define v4l2_subdev_edid v4l2_edid
> >>  
> >> @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
> >>  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
> >>  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
> >>  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> >> +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> >> +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
> >>  
> >>  #endif
Jacopo Mondi Feb. 21, 2019, 2:39 p.m. UTC | #4
Hi Sakari,
   one quick question

On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
>
> - Add sink and source streams for multiplexed links
> - Copy the argument back in case of an error. This is needed to let the
>   caller know the number of routes.
>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
>  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
>  include/media/v4l2-subdev.h           |  7 +++++
>  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
>  4 files changed, 94 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index 7de041bae84fb2f2..40406acb51ec0906 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -19,6 +19,7 @@
>  #include <linux/kernel.h>
>  #include <linux/version.h>
>
> +#include <linux/v4l2-subdev.h>
>  #include <linux/videodev2.h>
>
>  #include <media/v4l2-common.h>
> @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
>  		}
>  		break;
>  	}
> +
> +	case VIDIOC_SUBDEV_G_ROUTING:
> +	case VIDIOC_SUBDEV_S_ROUTING: {
> +		struct v4l2_subdev_routing *route = parg;
> +
> +		if (route->num_routes > 0) {
> +			if (route->num_routes > 256)
> +				return -EINVAL;
> +
> +			*user_ptr = (void __user *)route->routes;
> +			*kernel_ptr = (void *)&route->routes;
> +			*array_size = sizeof(struct v4l2_subdev_route)
> +				    * route->num_routes;
> +			ret = 1;
> +		}
> +		break;
> +	}
>  	}
>
>  	return ret;
> @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
>  	 * Some ioctls can return an error, but still have valid
>  	 * results that must be returned.
>  	 */
> -	if (err < 0 && !always_copy)
> +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
>  		goto out;
>
>  out_array_args:
> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> index 792f41dffe2329b9..1d3b37cf548fa533 100644
> --- a/drivers/media/v4l2-core/v4l2-subdev.c
> +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
>
>  	case VIDIOC_SUBDEV_QUERYSTD:
>  		return v4l2_subdev_call(sd, video, querystd, arg);
> +
> +	case VIDIOC_SUBDEV_G_ROUTING:
> +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> +
> +	case VIDIOC_SUBDEV_S_ROUTING: {
> +		struct v4l2_subdev_routing *route = arg;
> +		unsigned int i;
> +
> +		if (route->num_routes > sd->entity.num_pads)
> +			return -EINVAL;

Can't the number of routes exceeds the total number of pad?

To make an example, a subdevice with 2 sink pads, and 1 multiplexed
source pad, with 2 streams would expose the following routing table,
right?

pad #0 = sink, 1 stream
pad #1 = sink, 1 stream
pad #2 = source, 2 streams

Routing table:
0/0 -> 2/0
0/0 -> 2/1
1/0 -> 2/0
1/0 -> 2/1

In general, the number of accepted routes should depend on the number
of streams, not pads, and that's better handled by drivers, am I
wrong?

Thanks
  j

> +
> +		for (i = 0; i < route->num_routes; ++i) {
> +			unsigned int sink = route->routes[i].sink_pad;
> +			unsigned int source = route->routes[i].source_pad;
> +			struct media_pad *pads = sd->entity.pads;
> +
> +			if (sink >= sd->entity.num_pads ||
> +			    source >= sd->entity.num_pads)
> +				return -EINVAL;
> +
> +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> +				return -EINVAL;
> +		}
> +
> +		return v4l2_subdev_call(sd, pad, set_routing, route);
> +	}
>  #endif
> +
>  	default:
>  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
>  	}
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
>   *
>   * @set_frame_desc: set the low level media bus frame parameters, @fd array
>   *                  may be adjusted by the subdev driver to device capabilities.
> + *
> + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
>   */
>  struct v4l2_subdev_pad_ops {
>  	int (*init_cfg)(struct v4l2_subdev *sd,
> @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
>  			      struct v4l2_mbus_frame_desc *fd);
>  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
>  			      struct v4l2_mbus_frame_desc *fd);
> +	int (*get_routing)(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_routing *route);
> +	int (*set_routing)(struct v4l2_subdev *sd,
> +			   struct v4l2_subdev_routing *route);
>  };
>
>  /**
> diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> index 03970ce3074193e6..af069bfb10ca23a5 100644
> --- a/include/uapi/linux/v4l2-subdev.h
> +++ b/include/uapi/linux/v4l2-subdev.h
> @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
>  	__u32 reserved[8];
>  };
>
> +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> +
> +/**
> + * struct v4l2_subdev_route - A signal route inside a subdev
> + * @sink_pad: the sink pad
> + * @sink_stream: the sink stream
> + * @source_pad: the source pad
> + * @source_stream: the source stream
> + * @flags: route flags:
> + *
> + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> + *	active stream will start when streaming is enabled on a video
> + *	node. Set by the user.
> + *
> + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> + *	can it be activated and inactivated? Set by the driver.
> + */
> +struct v4l2_subdev_route {
> +	__u32 sink_pad;
> +	__u32 sink_stream;
> +	__u32 source_pad;
> +	__u32 source_stream;
> +	__u32 flags;
> +	__u32 reserved[5];
> +};
> +
> +/**
> + * struct v4l2_subdev_routing - Routing information
> + * @routes: the routes array
> + * @num_routes: the total number of routes in the routes array
> + */
> +struct v4l2_subdev_routing {
> +	struct v4l2_subdev_route *routes;
> +	__u32 num_routes;
> +	__u32 reserved[5];
> +};
> +
>  /* Backwards compatibility define --- to be removed */
>  #define v4l2_subdev_edid v4l2_edid
>
> @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
>  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
>  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
>  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
>
>  #endif
> --
> 2.19.1
>
Jacopo Mondi Feb. 21, 2019, 2:59 p.m. UTC | #5
Hi Sakari, Laurent, Niklas,
   (another) quick question, but a different one :)

On Wed, Jan 16, 2019 at 01:51:45AM +0200, Laurent Pinchart wrote:
> Hi Niklas,
>
> Thank you for the patch.
>
> On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> >
> > - Add sink and source streams for multiplexed links
> > - Copy the argument back in case of an error. This is needed to let the
> >   caller know the number of routes.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> >  include/media/v4l2-subdev.h           |  7 +++++
> >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
>
> Missing documentation :-(
>
> >  4 files changed, 94 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > @@ -19,6 +19,7 @@
> >  #include <linux/kernel.h>
> >  #include <linux/version.h>
> >
> > +#include <linux/v4l2-subdev.h>
> >  #include <linux/videodev2.h>
> >
> >  #include <media/v4l2-common.h>
> > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> >  		}
> >  		break;
> >  	}
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = parg;
> > +
> > +		if (route->num_routes > 0) {
> > +			if (route->num_routes > 256)
> > +				return -EINVAL;
> > +
> > +			*user_ptr = (void __user *)route->routes;
> > +			*kernel_ptr = (void *)&route->routes;
> > +			*array_size = sizeof(struct v4l2_subdev_route)
> > +				    * route->num_routes;
> > +			ret = 1;
> > +		}
> > +		break;
> > +	}
> >  	}
> >
> >  	return ret;
> > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> >  	 * Some ioctls can return an error, but still have valid
> >  	 * results that must be returned.
> >  	 */
> > -	if (err < 0 && !always_copy)
> > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
>
> This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
> always_copy instead ?
>
> >  		goto out;
> >
> >  out_array_args:
> > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> >
> >  	case VIDIOC_SUBDEV_QUERYSTD:
> >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > +
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = arg;
> > +		unsigned int i;
> > +
> > +		if (route->num_routes > sd->entity.num_pads)
> > +			return -EINVAL;
> > +
> > +		for (i = 0; i < route->num_routes; ++i) {

How have you envisioned the number of routes to be negotiated with
applications? I'm writing the documentation for this ioctl, and I
would like to insert this part as well.

Would a model like the one implemented in G_TOPOLOGY work in your
opinion? In my understanding, at the moment applications do not have a
way to reserve a known number of routes entries, but would likely
reserve 'enough(tm)' (ie 256) and pass them to the G_ROUTING ioctl that the
first time will likely adjust the number of num_routes and return -ENOSPC.

Wouldn't it work to make the IOCTL behave in a way that it
expects the first call to be performed with (num_routes == 0) and no routes
entries reserved, and just adjust 'num_routes' in that case?
So that applications should call G_ROUTING a first time with
num_routes = 0, get back the number of routes entries, reserve memory
for them, and then call G_ROUTING again to have the entries populated
by the driver. Do you have different ideas or was this the intended
behavior already?

Thanks
   j

> > +			unsigned int sink = route->routes[i].sink_pad;
> > +			unsigned int source = route->routes[i].source_pad;
> > +			struct media_pad *pads = sd->entity.pads;
> > +
> > +			if (sink >= sd->entity.num_pads ||
> > +			    source >= sd->entity.num_pads)
> > +				return -EINVAL;
> > +
> > +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> > +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> > +				return -EINVAL;
> > +		}
> > +
> > +		return v4l2_subdev_call(sd, pad, set_routing, route);
> > +	}
> >  #endif
> > +
> >  	default:
> >  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> >  	}
> > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> > --- a/include/media/v4l2-subdev.h
> > +++ b/include/media/v4l2-subdev.h
> > @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> >   *
> >   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> >   *                  may be adjusted by the subdev driver to device capabilities.
> > + *
> > + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> > + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
>
> Please define the purpose of those operations instead of just pointing
> to the userspace API.
>
> >   */
> >  struct v4l2_subdev_pad_ops {
> >  	int (*init_cfg)(struct v4l2_subdev *sd,
> > @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> >  			      struct v4l2_mbus_frame_desc *fd);
> >  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> >  			      struct v4l2_mbus_frame_desc *fd);
> > +	int (*get_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> > +	int (*set_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> >  };
> >
> >  /**
> > diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> > index 03970ce3074193e6..af069bfb10ca23a5 100644
> > --- a/include/uapi/linux/v4l2-subdev.h
> > +++ b/include/uapi/linux/v4l2-subdev.h
> > @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> >  	__u32 reserved[8];
> >  };
> >
> > +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> > +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> > +
> > +/**
> > + * struct v4l2_subdev_route - A signal route inside a subdev
> > + * @sink_pad: the sink pad
> > + * @sink_stream: the sink stream
> > + * @source_pad: the source pad
> > + * @source_stream: the source stream
>
> At this point in the series there's no concept of multiplexed streams,
> so the two fields don't make sense. You may want to reorder patches, or
> split this in two.
>
> > + * @flags: route flags:
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> > + *	active stream will start when streaming is enabled on a video
> > + *	node. Set by the user.
>
> This is very confusing as "stream" isn't defined. The documentation
> needs a rewrite with more details.
>
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> > + *	can it be activated and inactivated? Set by the driver.
> > + */
> > +struct v4l2_subdev_route {
> > +	__u32 sink_pad;
> > +	__u32 sink_stream;
> > +	__u32 source_pad;
> > +	__u32 source_stream;
> > +	__u32 flags;
> > +	__u32 reserved[5];
> > +};
> > +
> > +/**
> > + * struct v4l2_subdev_routing - Routing information
> > + * @routes: the routes array
> > + * @num_routes: the total number of routes in the routes array
> > + */
> > +struct v4l2_subdev_routing {
> > +	struct v4l2_subdev_route *routes;
>
> Missing __user ?
>
> > +	__u32 num_routes;
> > +	__u32 reserved[5];
> > +};
> > +
> >  /* Backwards compatibility define --- to be removed */
> >  #define v4l2_subdev_edid v4l2_edid
> >
> > @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
> >  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
> >  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
> >  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> > +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> > +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
> >
> >  #endif
> > --
> > 2.19.1
> >
>
> --
> Regards,
>
> Laurent Pinchart
Sakari Ailus Feb. 21, 2019, 10:31 p.m. UTC | #6
Hi Jacopo,

On Thu, Feb 21, 2019 at 03:39:40PM +0100, Jacopo Mondi wrote:
> Hi Sakari,
>    one quick question
> 
> On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> >
> > - Add sink and source streams for multiplexed links
> > - Copy the argument back in case of an error. This is needed to let the
> >   caller know the number of routes.
> >
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> >  include/media/v4l2-subdev.h           |  7 +++++
> >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> >  4 files changed, 94 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > @@ -19,6 +19,7 @@
> >  #include <linux/kernel.h>
> >  #include <linux/version.h>
> >
> > +#include <linux/v4l2-subdev.h>
> >  #include <linux/videodev2.h>
> >
> >  #include <media/v4l2-common.h>
> > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> >  		}
> >  		break;
> >  	}
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = parg;
> > +
> > +		if (route->num_routes > 0) {
> > +			if (route->num_routes > 256)
> > +				return -EINVAL;
> > +
> > +			*user_ptr = (void __user *)route->routes;
> > +			*kernel_ptr = (void *)&route->routes;
> > +			*array_size = sizeof(struct v4l2_subdev_route)
> > +				    * route->num_routes;
> > +			ret = 1;
> > +		}
> > +		break;
> > +	}
> >  	}
> >
> >  	return ret;
> > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> >  	 * Some ioctls can return an error, but still have valid
> >  	 * results that must be returned.
> >  	 */
> > -	if (err < 0 && !always_copy)
> > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> >  		goto out;
> >
> >  out_array_args:
> > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> >
> >  	case VIDIOC_SUBDEV_QUERYSTD:
> >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > +
> > +	case VIDIOC_SUBDEV_G_ROUTING:
> > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > +
> > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > +		struct v4l2_subdev_routing *route = arg;
> > +		unsigned int i;
> > +
> > +		if (route->num_routes > sd->entity.num_pads)
> > +			return -EINVAL;
> 
> Can't the number of routes exceeds the total number of pad?
> 
> To make an example, a subdevice with 2 sink pads, and 1 multiplexed
> source pad, with 2 streams would expose the following routing table,
> right?
> 
> pad #0 = sink, 1 stream
> pad #1 = sink, 1 stream
> pad #2 = source, 2 streams
> 
> Routing table:
> 0/0 -> 2/0
> 0/0 -> 2/1
> 1/0 -> 2/0
> 1/0 -> 2/1
> 
> In general, the number of accepted routes should depend on the number
> of streams, not pads, and that's better handled by drivers, am I
> wrong?

Good point. Is the above configuration meaningful? I.e. you have a mux
device that does some processing as well by combining the streams?

It's far-fetched but at the moment the API does not really bend for that.
It still might in the future.

I guess we could just remove the check, and let drivers handle it.

> 
> Thanks
>   j
> 
> > +
> > +		for (i = 0; i < route->num_routes; ++i) {
> > +			unsigned int sink = route->routes[i].sink_pad;
> > +			unsigned int source = route->routes[i].source_pad;
> > +			struct media_pad *pads = sd->entity.pads;
> > +
> > +			if (sink >= sd->entity.num_pads ||
> > +			    source >= sd->entity.num_pads)
> > +				return -EINVAL;
> > +
> > +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> > +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> > +				return -EINVAL;
> > +		}
> > +
> > +		return v4l2_subdev_call(sd, pad, set_routing, route);
> > +	}
> >  #endif
> > +
> >  	default:
> >  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> >  	}
> > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> > --- a/include/media/v4l2-subdev.h
> > +++ b/include/media/v4l2-subdev.h
> > @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> >   *
> >   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> >   *                  may be adjusted by the subdev driver to device capabilities.
> > + *
> > + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> > + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
> >   */
> >  struct v4l2_subdev_pad_ops {
> >  	int (*init_cfg)(struct v4l2_subdev *sd,
> > @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> >  			      struct v4l2_mbus_frame_desc *fd);
> >  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> >  			      struct v4l2_mbus_frame_desc *fd);
> > +	int (*get_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> > +	int (*set_routing)(struct v4l2_subdev *sd,
> > +			   struct v4l2_subdev_routing *route);
> >  };
> >
> >  /**
> > diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> > index 03970ce3074193e6..af069bfb10ca23a5 100644
> > --- a/include/uapi/linux/v4l2-subdev.h
> > +++ b/include/uapi/linux/v4l2-subdev.h
> > @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> >  	__u32 reserved[8];
> >  };
> >
> > +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> > +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> > +
> > +/**
> > + * struct v4l2_subdev_route - A signal route inside a subdev
> > + * @sink_pad: the sink pad
> > + * @sink_stream: the sink stream
> > + * @source_pad: the source pad
> > + * @source_stream: the source stream
> > + * @flags: route flags:
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> > + *	active stream will start when streaming is enabled on a video
> > + *	node. Set by the user.
> > + *
> > + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> > + *	can it be activated and inactivated? Set by the driver.
> > + */
> > +struct v4l2_subdev_route {
> > +	__u32 sink_pad;
> > +	__u32 sink_stream;
> > +	__u32 source_pad;
> > +	__u32 source_stream;
> > +	__u32 flags;
> > +	__u32 reserved[5];
> > +};
> > +
> > +/**
> > + * struct v4l2_subdev_routing - Routing information
> > + * @routes: the routes array
> > + * @num_routes: the total number of routes in the routes array
> > + */
> > +struct v4l2_subdev_routing {
> > +	struct v4l2_subdev_route *routes;

This should be just __u64, to avoid writing compat code. The patch was
written before we started doing that. :-) Please see e.g. the media device
topology IOCTL.

> > +	__u32 num_routes;
> > +	__u32 reserved[5];
> > +};
> > +
> >  /* Backwards compatibility define --- to be removed */
> >  #define v4l2_subdev_edid v4l2_edid
> >
> > @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
> >  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
> >  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
> >  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> > +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> > +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
> >
> >  #endif
Sakari Ailus Feb. 21, 2019, 11:49 p.m. UTC | #7
Hi Jacopo,

On Thu, Feb 21, 2019 at 03:59:20PM +0100, Jacopo Mondi wrote:
> Hi Sakari, Laurent, Niklas,
>    (another) quick question, but a different one :)
> 
> On Wed, Jan 16, 2019 at 01:51:45AM +0200, Laurent Pinchart wrote:
> > Hi Niklas,
> >
> > Thank you for the patch.
> >
> > On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > >
> > > - Add sink and source streams for multiplexed links
> > > - Copy the argument back in case of an error. This is needed to let the
> > >   caller know the number of routes.
> > >
> > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > > ---
> > >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> > >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> > >  include/media/v4l2-subdev.h           |  7 +++++
> > >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> >
> > Missing documentation :-(
> >
> > >  4 files changed, 94 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > @@ -19,6 +19,7 @@
> > >  #include <linux/kernel.h>
> > >  #include <linux/version.h>
> > >
> > > +#include <linux/v4l2-subdev.h>
> > >  #include <linux/videodev2.h>
> > >
> > >  #include <media/v4l2-common.h>
> > > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> > >  		}
> > >  		break;
> > >  	}
> > > +
> > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > +		struct v4l2_subdev_routing *route = parg;
> > > +
> > > +		if (route->num_routes > 0) {
> > > +			if (route->num_routes > 256)
> > > +				return -EINVAL;
> > > +
> > > +			*user_ptr = (void __user *)route->routes;
> > > +			*kernel_ptr = (void *)&route->routes;
> > > +			*array_size = sizeof(struct v4l2_subdev_route)
> > > +				    * route->num_routes;
> > > +			ret = 1;
> > > +		}
> > > +		break;
> > > +	}
> > >  	}
> > >
> > >  	return ret;
> > > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> > >  	 * Some ioctls can return an error, but still have valid
> > >  	 * results that must be returned.
> > >  	 */
> > > -	if (err < 0 && !always_copy)
> > > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> >
> > This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
> > always_copy instead ?
> >
> > >  		goto out;
> > >
> > >  out_array_args:
> > > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> > >
> > >  	case VIDIOC_SUBDEV_QUERYSTD:
> > >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > > +
> > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > > +
> > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > +		struct v4l2_subdev_routing *route = arg;
> > > +		unsigned int i;
> > > +
> > > +		if (route->num_routes > sd->entity.num_pads)
> > > +			return -EINVAL;
> > > +
> > > +		for (i = 0; i < route->num_routes; ++i) {
> 
> How have you envisioned the number of routes to be negotiated with
> applications? I'm writing the documentation for this ioctl, and I
> would like to insert this part as well.
> 
> Would a model like the one implemented in G_TOPOLOGY work in your
> opinion? In my understanding, at the moment applications do not have a
> way to reserve a known number of routes entries, but would likely
> reserve 'enough(tm)' (ie 256) and pass them to the G_ROUTING ioctl that the
> first time will likely adjust the number of num_routes and return -ENOSPC.
> 
> Wouldn't it work to make the IOCTL behave in a way that it
> expects the first call to be performed with (num_routes == 0) and no routes
> entries reserved, and just adjust 'num_routes' in that case?
> So that applications should call G_ROUTING a first time with
> num_routes = 0, get back the number of routes entries, reserve memory
> for them, and then call G_ROUTING again to have the entries populated
> by the driver. Do you have different ideas or was this the intended
> behavior already?

I think whenever the number of routes isn't enough to return them all, the
IOCTL should return -ENOSPC, and set the actual number of routes there. Not
just zero. The user could e.g. try with a static allocation of some, and
allocate memory if the static allocation turns not to be enough.

Btw. the idea behind S_ROUTING behaviour was to allow multiple users to
work on a single sub-device without having to know about each other. That's
why there are flags to tell which routes are enabled and which are not.

I'll be better available tomorrow, let's discuss e.g. on #v4l then.
Jacopo Mondi Feb. 22, 2019, 8:40 a.m. UTC | #8
Hi Sakari,

On Fri, Feb 22, 2019 at 12:31:32AM +0200, Sakari Ailus wrote:
> Hi Jacopo,
>
> On Thu, Feb 21, 2019 at 03:39:40PM +0100, Jacopo Mondi wrote:
> > Hi Sakari,
> >    one quick question
> >
> > On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > >
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > >
> > > - Add sink and source streams for multiplexed links
> > > - Copy the argument back in case of an error. This is needed to let the
> > >   caller know the number of routes.
> > >
> > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > > ---
> > >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> > >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> > >  include/media/v4l2-subdev.h           |  7 +++++
> > >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> > >  4 files changed, 94 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > @@ -19,6 +19,7 @@
> > >  #include <linux/kernel.h>
> > >  #include <linux/version.h>
> > >
> > > +#include <linux/v4l2-subdev.h>
> > >  #include <linux/videodev2.h>
> > >
> > >  #include <media/v4l2-common.h>
> > > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> > >  		}
> > >  		break;
> > >  	}
> > > +
> > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > +		struct v4l2_subdev_routing *route = parg;
> > > +
> > > +		if (route->num_routes > 0) {
> > > +			if (route->num_routes > 256)
> > > +				return -EINVAL;
> > > +
> > > +			*user_ptr = (void __user *)route->routes;
> > > +			*kernel_ptr = (void *)&route->routes;
> > > +			*array_size = sizeof(struct v4l2_subdev_route)
> > > +				    * route->num_routes;
> > > +			ret = 1;
> > > +		}
> > > +		break;
> > > +	}
> > >  	}
> > >
> > >  	return ret;
> > > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> > >  	 * Some ioctls can return an error, but still have valid
> > >  	 * results that must be returned.
> > >  	 */
> > > -	if (err < 0 && !always_copy)
> > > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> > >  		goto out;
> > >
> > >  out_array_args:
> > > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> > >
> > >  	case VIDIOC_SUBDEV_QUERYSTD:
> > >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > > +
> > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > > +
> > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > +		struct v4l2_subdev_routing *route = arg;
> > > +		unsigned int i;
> > > +
> > > +		if (route->num_routes > sd->entity.num_pads)
> > > +			return -EINVAL;
> >
> > Can't the number of routes exceeds the total number of pad?
> >
> > To make an example, a subdevice with 2 sink pads, and 1 multiplexed
> > source pad, with 2 streams would expose the following routing table,
> > right?
> >
> > pad #0 = sink, 1 stream
> > pad #1 = sink, 1 stream
> > pad #2 = source, 2 streams
> >
> > Routing table:
> > 0/0 -> 2/0
> > 0/0 -> 2/1
> > 1/0 -> 2/0
> > 1/0 -> 2/1
> >
> > In general, the number of accepted routes should depend on the number
> > of streams, not pads, and that's better handled by drivers, am I
> > wrong?
>
> Good point. Is the above configuration meaningful? I.e. you have a mux
> device that does some processing as well by combining the streams?
>
> It's far-fetched but at the moment the API does not really bend for that.
> It still might in the future.

Well, how would you expect a routing table for a device that
supports multiplexing using Virtual Channels to look like?

As far as I got it, even with a single sink and a single source, it
would be:

[SINK/SINK_STREAM -> SOURCE/SOURCE_STREAM]
0/0 -> 1/0
0/0 -> 1/1
0/0 -> 1/2
0/0 -> 1/3

On the previous example, I thought about GMSL-like devices, that can
output the video streams received from different remotes in a
separate virtual channel, at the same time.

A possible routing table in that case would be like:

Pads 0, 1, 2, 3 = SINKS
Pad 4 = SOURCE with 4 streams (1 for each VC)

0/0 -> 4/0
0/0 -> 4/1
0/0 -> 4/2
0/0 -> 4/3
1/0 -> 4/0
1/0 -> 4/1
1/0 -> 4/2
1/0 -> 4/3
2/0 -> 4/0
2/0 -> 4/1
2/0 -> 4/2
2/0 -> 4/3
3/0 -> 4/0
3/0 -> 4/1
3/0 -> 4/2
3/0 -> 4/3

With only one route per virtual channel active at a time.

Does this match your idea?

>
> I guess we could just remove the check, and let drivers handle it.
>

Yup, I agree!

> >
> > Thanks
> >   j
> >
> > > +
> > > +		for (i = 0; i < route->num_routes; ++i) {
> > > +			unsigned int sink = route->routes[i].sink_pad;
> > > +			unsigned int source = route->routes[i].source_pad;
> > > +			struct media_pad *pads = sd->entity.pads;
> > > +
> > > +			if (sink >= sd->entity.num_pads ||
> > > +			    source >= sd->entity.num_pads)
> > > +				return -EINVAL;
> > > +
> > > +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> > > +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> > > +				return -EINVAL;
> > > +		}
> > > +
> > > +		return v4l2_subdev_call(sd, pad, set_routing, route);
> > > +	}
> > >  #endif
> > > +
> > >  	default:
> > >  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> > >  	}
> > > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > > index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> > > --- a/include/media/v4l2-subdev.h
> > > +++ b/include/media/v4l2-subdev.h
> > > @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> > >   *
> > >   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> > >   *                  may be adjusted by the subdev driver to device capabilities.
> > > + *
> > > + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> > > + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
> > >   */
> > >  struct v4l2_subdev_pad_ops {
> > >  	int (*init_cfg)(struct v4l2_subdev *sd,
> > > @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> > >  			      struct v4l2_mbus_frame_desc *fd);
> > >  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> > >  			      struct v4l2_mbus_frame_desc *fd);
> > > +	int (*get_routing)(struct v4l2_subdev *sd,
> > > +			   struct v4l2_subdev_routing *route);
> > > +	int (*set_routing)(struct v4l2_subdev *sd,
> > > +			   struct v4l2_subdev_routing *route);
> > >  };
> > >
> > >  /**
> > > diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> > > index 03970ce3074193e6..af069bfb10ca23a5 100644
> > > --- a/include/uapi/linux/v4l2-subdev.h
> > > +++ b/include/uapi/linux/v4l2-subdev.h
> > > @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> > >  	__u32 reserved[8];
> > >  };
> > >
> > > +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> > > +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> > > +
> > > +/**
> > > + * struct v4l2_subdev_route - A signal route inside a subdev
> > > + * @sink_pad: the sink pad
> > > + * @sink_stream: the sink stream
> > > + * @source_pad: the source pad
> > > + * @source_stream: the source stream
> > > + * @flags: route flags:
> > > + *
> > > + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> > > + *	active stream will start when streaming is enabled on a video
> > > + *	node. Set by the user.
> > > + *
> > > + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> > > + *	can it be activated and inactivated? Set by the driver.
> > > + */
> > > +struct v4l2_subdev_route {
> > > +	__u32 sink_pad;
> > > +	__u32 sink_stream;
> > > +	__u32 source_pad;
> > > +	__u32 source_stream;
> > > +	__u32 flags;
> > > +	__u32 reserved[5];
> > > +};
> > > +
> > > +/**
> > > + * struct v4l2_subdev_routing - Routing information
> > > + * @routes: the routes array
> > > + * @num_routes: the total number of routes in the routes array
> > > + */
> > > +struct v4l2_subdev_routing {
> > > +	struct v4l2_subdev_route *routes;
>
> This should be just __u64, to avoid writing compat code. The patch was
> written before we started doing that. :-) Please see e.g. the media device
> topology IOCTL.
>

Thanks, I had a look at the MEDIA_ ioctls yesterday, G_TOPOLOGY in
particular, which uses several pointers to arrays.

Unfortunately, I didn't come up with anything better than using a
translation structure, from the IOCTL layer to the subdevice
operations layer:
https://paste.debian.net/hidden/b192969d/
(sharing a link for early comments, I can send v3 and you can comment
there directly if you prefer to :)

Thanks
   j

> > > +	__u32 num_routes;
> > > +	__u32 reserved[5];
> > > +};
> > > +
> > >  /* Backwards compatibility define --- to be removed */
> > >  #define v4l2_subdev_edid v4l2_edid
> > >
> > > @@ -181,5 +219,7 @@ struct v4l2_subdev_selection {
> > >  #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
> > >  #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
> > >  #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
> > > +#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
> > > +#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
> > >
> > >  #endif
>
> --
> Regards,
>
> Sakari Ailus
> sakari.ailus@linux.intel.com
Jacopo Mondi Feb. 22, 2019, 8:46 a.m. UTC | #9
Hi Sakari,

On Fri, Feb 22, 2019 at 01:49:36AM +0200, Sakari Ailus wrote:
> Hi Jacopo,
>
> On Thu, Feb 21, 2019 at 03:59:20PM +0100, Jacopo Mondi wrote:
> > Hi Sakari, Laurent, Niklas,
> >    (another) quick question, but a different one :)
> >
> > On Wed, Jan 16, 2019 at 01:51:45AM +0200, Laurent Pinchart wrote:
> > > Hi Niklas,
> > >
> > > Thank you for the patch.
> > >
> > > On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > > > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > >
> > > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > > >
> > > > - Add sink and source streams for multiplexed links
> > > > - Copy the argument back in case of an error. This is needed to let the
> > > >   caller know the number of routes.
> > > >
> > > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > > > ---
> > > >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> > > >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> > > >  include/media/v4l2-subdev.h           |  7 +++++
> > > >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> > >
> > > Missing documentation :-(
> > >
> > > >  4 files changed, 94 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > @@ -19,6 +19,7 @@
> > > >  #include <linux/kernel.h>
> > > >  #include <linux/version.h>
> > > >
> > > > +#include <linux/v4l2-subdev.h>
> > > >  #include <linux/videodev2.h>
> > > >
> > > >  #include <media/v4l2-common.h>
> > > > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> > > >  		}
> > > >  		break;
> > > >  	}
> > > > +
> > > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > > +		struct v4l2_subdev_routing *route = parg;
> > > > +
> > > > +		if (route->num_routes > 0) {
> > > > +			if (route->num_routes > 256)
> > > > +				return -EINVAL;
> > > > +
> > > > +			*user_ptr = (void __user *)route->routes;
> > > > +			*kernel_ptr = (void *)&route->routes;
> > > > +			*array_size = sizeof(struct v4l2_subdev_route)
> > > > +				    * route->num_routes;
> > > > +			ret = 1;
> > > > +		}
> > > > +		break;
> > > > +	}
> > > >  	}
> > > >
> > > >  	return ret;
> > > > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> > > >  	 * Some ioctls can return an error, but still have valid
> > > >  	 * results that must be returned.
> > > >  	 */
> > > > -	if (err < 0 && !always_copy)
> > > > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> > >
> > > This seems like a hack. Shouldn't VIDIOC_SUBDEV_G_ROUTING set
> > > always_copy instead ?
> > >
> > > >  		goto out;
> > > >
> > > >  out_array_args:
> > > > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > > > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > > > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> > > >
> > > >  	case VIDIOC_SUBDEV_QUERYSTD:
> > > >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > > > +
> > > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > > > +
> > > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > > +		struct v4l2_subdev_routing *route = arg;
> > > > +		unsigned int i;
> > > > +
> > > > +		if (route->num_routes > sd->entity.num_pads)
> > > > +			return -EINVAL;
> > > > +
> > > > +		for (i = 0; i < route->num_routes; ++i) {
> >
> > How have you envisioned the number of routes to be negotiated with
> > applications? I'm writing the documentation for this ioctl, and I
> > would like to insert this part as well.
> >
> > Would a model like the one implemented in G_TOPOLOGY work in your
> > opinion? In my understanding, at the moment applications do not have a
> > way to reserve a known number of routes entries, but would likely
> > reserve 'enough(tm)' (ie 256) and pass them to the G_ROUTING ioctl that the
> > first time will likely adjust the number of num_routes and return -ENOSPC.
> >
> > Wouldn't it work to make the IOCTL behave in a way that it
> > expects the first call to be performed with (num_routes == 0) and no routes
> > entries reserved, and just adjust 'num_routes' in that case?
> > So that applications should call G_ROUTING a first time with
> > num_routes = 0, get back the number of routes entries, reserve memory
> > for them, and then call G_ROUTING again to have the entries populated
> > by the driver. Do you have different ideas or was this the intended
> > behavior already?
>
> I think whenever the number of routes isn't enough to return them all, the
> IOCTL should return -ENOSPC, and set the actual number of routes there. Not
> just zero. The user could e.g. try with a static allocation of some, and
> allocate memory if the static allocation turns not to be enough.

I see. That's fine, I just wanted to make sure I was not missing
something... Fine with me if num_routes is not adequate, it should be
corrected by the driver and -ENOSPC returned. How applications deal
with allocation is up to them (even if documentation might suggest to
perform and "call with 0, allocate, call again" sequence as a way to
ease this)

>
> Btw. the idea behind S_ROUTING behaviour was to allow multiple users to
> work on a single sub-device without having to know about each other. That's
> why there are flags to tell which routes are enabled and which are not.
>
> I'll be better available tomorrow, let's discuss e.g. on #v4l then.
>

Unfortunately I won't too much today :) I'll keep pinging in the next
days then, sorry about this :p

Thanks
   j

> --
> Sakari Ailus
> sakari.ailus@linux.intel.com
Sakari Ailus Feb. 22, 2019, 11:04 a.m. UTC | #10
Hi Jacopo,

On Fri, Feb 22, 2019 at 09:40:19AM +0100, Jacopo Mondi wrote:
> Hi Sakari,
> 
> On Fri, Feb 22, 2019 at 12:31:32AM +0200, Sakari Ailus wrote:
> > Hi Jacopo,
> >
> > On Thu, Feb 21, 2019 at 03:39:40PM +0100, Jacopo Mondi wrote:
> > > Hi Sakari,
> > >    one quick question
> > >
> > > On Fri, Nov 02, 2018 at 12:31:30AM +0100, Niklas Söderlund wrote:
> > > > From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > >
> > > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > > Signed-off-by: Michal Simek <michal.simek@xilinx.com>
> > > >
> > > > - Add sink and source streams for multiplexed links
> > > > - Copy the argument back in case of an error. This is needed to let the
> > > >   caller know the number of routes.
> > > >
> > > > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > > > Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > > > ---
> > > >  drivers/media/v4l2-core/v4l2-ioctl.c  | 20 +++++++++++++-
> > > >  drivers/media/v4l2-core/v4l2-subdev.c | 28 +++++++++++++++++++
> > > >  include/media/v4l2-subdev.h           |  7 +++++
> > > >  include/uapi/linux/v4l2-subdev.h      | 40 +++++++++++++++++++++++++++
> > > >  4 files changed, 94 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > index 7de041bae84fb2f2..40406acb51ec0906 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> > > > @@ -19,6 +19,7 @@
> > > >  #include <linux/kernel.h>
> > > >  #include <linux/version.h>
> > > >
> > > > +#include <linux/v4l2-subdev.h>
> > > >  #include <linux/videodev2.h>
> > > >
> > > >  #include <media/v4l2-common.h>
> > > > @@ -2924,6 +2925,23 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
> > > >  		}
> > > >  		break;
> > > >  	}
> > > > +
> > > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > > +		struct v4l2_subdev_routing *route = parg;
> > > > +
> > > > +		if (route->num_routes > 0) {
> > > > +			if (route->num_routes > 256)
> > > > +				return -EINVAL;
> > > > +
> > > > +			*user_ptr = (void __user *)route->routes;
> > > > +			*kernel_ptr = (void *)&route->routes;
> > > > +			*array_size = sizeof(struct v4l2_subdev_route)
> > > > +				    * route->num_routes;
> > > > +			ret = 1;
> > > > +		}
> > > > +		break;
> > > > +	}
> > > >  	}
> > > >
> > > >  	return ret;
> > > > @@ -3033,7 +3051,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
> > > >  	 * Some ioctls can return an error, but still have valid
> > > >  	 * results that must be returned.
> > > >  	 */
> > > > -	if (err < 0 && !always_copy)
> > > > +	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
> > > >  		goto out;
> > > >
> > > >  out_array_args:
> > > > diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
> > > > index 792f41dffe2329b9..1d3b37cf548fa533 100644
> > > > --- a/drivers/media/v4l2-core/v4l2-subdev.c
> > > > +++ b/drivers/media/v4l2-core/v4l2-subdev.c
> > > > @@ -516,7 +516,35 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
> > > >
> > > >  	case VIDIOC_SUBDEV_QUERYSTD:
> > > >  		return v4l2_subdev_call(sd, video, querystd, arg);
> > > > +
> > > > +	case VIDIOC_SUBDEV_G_ROUTING:
> > > > +		return v4l2_subdev_call(sd, pad, get_routing, arg);
> > > > +
> > > > +	case VIDIOC_SUBDEV_S_ROUTING: {
> > > > +		struct v4l2_subdev_routing *route = arg;
> > > > +		unsigned int i;
> > > > +
> > > > +		if (route->num_routes > sd->entity.num_pads)
> > > > +			return -EINVAL;
> > >
> > > Can't the number of routes exceeds the total number of pad?
> > >
> > > To make an example, a subdevice with 2 sink pads, and 1 multiplexed
> > > source pad, with 2 streams would expose the following routing table,
> > > right?
> > >
> > > pad #0 = sink, 1 stream
> > > pad #1 = sink, 1 stream
> > > pad #2 = source, 2 streams
> > >
> > > Routing table:
> > > 0/0 -> 2/0
> > > 0/0 -> 2/1
> > > 1/0 -> 2/0
> > > 1/0 -> 2/1
> > >
> > > In general, the number of accepted routes should depend on the number
> > > of streams, not pads, and that's better handled by drivers, am I
> > > wrong?
> >
> > Good point. Is the above configuration meaningful? I.e. you have a mux
> > device that does some processing as well by combining the streams?
> >
> > It's far-fetched but at the moment the API does not really bend for that.
> > It still might in the future.
> 
> Well, how would you expect a routing table for a device that
> supports multiplexing using Virtual Channels to look like?
> 
> As far as I got it, even with a single sink and a single source, it
> would be:
> 
> [SINK/SINK_STREAM -> SOURCE/SOURCE_STREAM]
> 0/0 -> 1/0
> 0/0 -> 1/1
> 0/0 -> 1/2
> 0/0 -> 1/3
> 
> On the previous example, I thought about GMSL-like devices, that can
> output the video streams received from different remotes in a
> separate virtual channel, at the same time.
> 
> A possible routing table in that case would be like:
> 
> Pads 0, 1, 2, 3 = SINKS
> Pad 4 = SOURCE with 4 streams (1 for each VC)
> 
> 0/0 -> 4/0
> 0/0 -> 4/1
> 0/0 -> 4/2
> 0/0 -> 4/3
> 1/0 -> 4/0
> 1/0 -> 4/1
> 1/0 -> 4/2
> 1/0 -> 4/3
> 2/0 -> 4/0
> 2/0 -> 4/1
> 2/0 -> 4/2
> 2/0 -> 4/3
> 3/0 -> 4/0
> 3/0 -> 4/1
> 3/0 -> 4/2
> 3/0 -> 4/3

If more than one pad can handle multiplexed streams, then you may end up in
a situation like that. Indeed.

> 
> With only one route per virtual channel active at a time.
> 
> Does this match your idea?
> 
> >
> > I guess we could just remove the check, and let drivers handle it.
> >
> 
> Yup, I agree!
> 
> > >
> > > Thanks
> > >   j
> > >
> > > > +
> > > > +		for (i = 0; i < route->num_routes; ++i) {
> > > > +			unsigned int sink = route->routes[i].sink_pad;
> > > > +			unsigned int source = route->routes[i].source_pad;
> > > > +			struct media_pad *pads = sd->entity.pads;
> > > > +
> > > > +			if (sink >= sd->entity.num_pads ||
> > > > +			    source >= sd->entity.num_pads)
> > > > +				return -EINVAL;
> > > > +
> > > > +			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
> > > > +			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
> > > > +				return -EINVAL;
> > > > +		}
> > > > +
> > > > +		return v4l2_subdev_call(sd, pad, set_routing, route);
> > > > +	}
> > > >  #endif
> > > > +
> > > >  	default:
> > > >  		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
> > > >  	}
> > > > diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> > > > index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
> > > > --- a/include/media/v4l2-subdev.h
> > > > +++ b/include/media/v4l2-subdev.h
> > > > @@ -679,6 +679,9 @@ struct v4l2_subdev_pad_config {
> > > >   *
> > > >   * @set_frame_desc: set the low level media bus frame parameters, @fd array
> > > >   *                  may be adjusted by the subdev driver to device capabilities.
> > > > + *
> > > > + * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
> > > > + * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
> > > >   */
> > > >  struct v4l2_subdev_pad_ops {
> > > >  	int (*init_cfg)(struct v4l2_subdev *sd,
> > > > @@ -719,6 +722,10 @@ struct v4l2_subdev_pad_ops {
> > > >  			      struct v4l2_mbus_frame_desc *fd);
> > > >  	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
> > > >  			      struct v4l2_mbus_frame_desc *fd);
> > > > +	int (*get_routing)(struct v4l2_subdev *sd,
> > > > +			   struct v4l2_subdev_routing *route);
> > > > +	int (*set_routing)(struct v4l2_subdev *sd,
> > > > +			   struct v4l2_subdev_routing *route);
> > > >  };
> > > >
> > > >  /**
> > > > diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
> > > > index 03970ce3074193e6..af069bfb10ca23a5 100644
> > > > --- a/include/uapi/linux/v4l2-subdev.h
> > > > +++ b/include/uapi/linux/v4l2-subdev.h
> > > > @@ -155,6 +155,44 @@ struct v4l2_subdev_selection {
> > > >  	__u32 reserved[8];
> > > >  };
> > > >
> > > > +#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
> > > > +#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
> > > > +
> > > > +/**
> > > > + * struct v4l2_subdev_route - A signal route inside a subdev
> > > > + * @sink_pad: the sink pad
> > > > + * @sink_stream: the sink stream
> > > > + * @source_pad: the source pad
> > > > + * @source_stream: the source stream
> > > > + * @flags: route flags:
> > > > + *
> > > > + *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
> > > > + *	active stream will start when streaming is enabled on a video
> > > > + *	node. Set by the user.
> > > > + *
> > > > + *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
> > > > + *	can it be activated and inactivated? Set by the driver.
> > > > + */
> > > > +struct v4l2_subdev_route {
> > > > +	__u32 sink_pad;
> > > > +	__u32 sink_stream;
> > > > +	__u32 source_pad;
> > > > +	__u32 source_stream;
> > > > +	__u32 flags;
> > > > +	__u32 reserved[5];
> > > > +};
> > > > +
> > > > +/**
> > > > + * struct v4l2_subdev_routing - Routing information
> > > > + * @routes: the routes array
> > > > + * @num_routes: the total number of routes in the routes array
> > > > + */
> > > > +struct v4l2_subdev_routing {
> > > > +	struct v4l2_subdev_route *routes;
> >
> > This should be just __u64, to avoid writing compat code. The patch was
> > written before we started doing that. :-) Please see e.g. the media device
> > topology IOCTL.
> >
> 
> Thanks, I had a look at the MEDIA_ ioctls yesterday, G_TOPOLOGY in
> particular, which uses several pointers to arrays.
> 
> Unfortunately, I didn't come up with anything better than using a
> translation structure, from the IOCTL layer to the subdevice
> operations layer:
> https://paste.debian.net/hidden/b192969d/
> (sharing a link for early comments, I can send v3 and you can comment
> there directly if you prefer to :)

Hmm. That is a downside indeed. It's still a lesser problem than the compat
code in general --- which has been a source for bugs as well as nasty
security problems over time.

I think we need a naming scheme for such structs. How about just
calling that struct e.g. v4l2_subdev_krouting instead? It's simple, easy to
understand and it includes a suggestion which one is the kernel-only
variant.

You can btw. zero the struct memory by assigning { 0 } to it in
declaration. memset() in general is much more trouble. In this case you
could even do the assignments in delaration as well.

There is a check that requires that one pad is a source and another is a
sink; I think we could remove that check as well.
Jacopo Mondi Feb. 22, 2019, 11:17 a.m. UTC | #11
Hi Sakari,
    thanks for your suggestions.

On Fri, Feb 22, 2019 at 01:04:29PM +0200, Sakari Ailus wrote:
> Hi Jacopo,

[snip]

> > On the previous example, I thought about GMSL-like devices, that can
> > output the video streams received from different remotes in a
> > separate virtual channel, at the same time.
> >
> > A possible routing table in that case would be like:
> >
> > Pads 0, 1, 2, 3 = SINKS
> > Pad 4 = SOURCE with 4 streams (1 for each VC)
> >
> > 0/0 -> 4/0
> > 0/0 -> 4/1
> > 0/0 -> 4/2
> > 0/0 -> 4/3
> > 1/0 -> 4/0
> > 1/0 -> 4/1
> > 1/0 -> 4/2
> > 1/0 -> 4/3
> > 2/0 -> 4/0
> > 2/0 -> 4/1
> > 2/0 -> 4/2
> > 2/0 -> 4/3
> > 3/0 -> 4/0
> > 3/0 -> 4/1
> > 3/0 -> 4/2
> > 3/0 -> 4/3
>
> If more than one pad can handle multiplexed streams, then you may end up in
> a situation like that. Indeed.
>

Please note that in this case there is only one pad that can handle
multiplexed stream. The size of the routing table is the
multiplication of the total number of pads by the product of all
streams per pad. In this case (4 * (1 * 1 * 1 * 4))

> >
> > With only one route per virtual channel active at a time.

[snip]

> >
> > Thanks, I had a look at the MEDIA_ ioctls yesterday, G_TOPOLOGY in
> > particular, which uses several pointers to arrays.
> >
> > Unfortunately, I didn't come up with anything better than using a
> > translation structure, from the IOCTL layer to the subdevice
> > operations layer:
> > https://paste.debian.net/hidden/b192969d/
> > (sharing a link for early comments, I can send v3 and you can comment
> > there directly if you prefer to :)
>
> Hmm. That is a downside indeed. It's still a lesser problem than the compat
> code in general --- which has been a source for bugs as well as nasty
> security problems over time.
>

Good!

> I think we need a naming scheme for such structs. How about just
> calling that struct e.g. v4l2_subdev_krouting instead? It's simple, easy to
> understand and it includes a suggestion which one is the kernel-only
> variant.
>

I kind of like that! thanks!

> You can btw. zero the struct memory by assigning { 0 } to it in
> declaration. memset() in general is much more trouble. In this case you
> could even do the assignments in delaration as well.
>

Thanks, noted. I have been lazy and copied memset from other places in
the ioctl handling code. I should check on your suggestions because I
remember one of the many 0-initialization statement was a GCC specific one,
don't remember which...

Initializing in-place would solve both issues :)

> There is a check that requires that one pad is a source and another is a
> sink; I think we could remove that check as well.

Correct, I'll handle that!

Thanks again
   j

>
> --
> Regards,
>
> Sakari Ailus
> sakari.ailus@linux.intel.com
Sakari Ailus Feb. 22, 2019, 11:29 a.m. UTC | #12
Hi Jacopo,

On Fri, Feb 22, 2019 at 12:17:47PM +0100, Jacopo Mondi wrote:
> Hi Sakari,
>     thanks for your suggestions.
> 
> On Fri, Feb 22, 2019 at 01:04:29PM +0200, Sakari Ailus wrote:
> > Hi Jacopo,
> 
> [snip]
> 
> > > On the previous example, I thought about GMSL-like devices, that can
> > > output the video streams received from different remotes in a
> > > separate virtual channel, at the same time.
> > >
> > > A possible routing table in that case would be like:
> > >
> > > Pads 0, 1, 2, 3 = SINKS
> > > Pad 4 = SOURCE with 4 streams (1 for each VC)
> > >
> > > 0/0 -> 4/0
> > > 0/0 -> 4/1
> > > 0/0 -> 4/2
> > > 0/0 -> 4/3
> > > 1/0 -> 4/0
> > > 1/0 -> 4/1
> > > 1/0 -> 4/2
> > > 1/0 -> 4/3
> > > 2/0 -> 4/0
> > > 2/0 -> 4/1
> > > 2/0 -> 4/2
> > > 2/0 -> 4/3
> > > 3/0 -> 4/0
> > > 3/0 -> 4/1
> > > 3/0 -> 4/2
> > > 3/0 -> 4/3
> >
> > If more than one pad can handle multiplexed streams, then you may end up in
> > a situation like that. Indeed.
> >
> 
> Please note that in this case there is only one pad that can handle
> multiplexed stream. The size of the routing table is the
> multiplication of the total number of pads by the product of all
> streams per pad. In this case (4 * (1 * 1 * 1 * 4))

Oh, good point, that's the case for G_ROUTING. I thought of S_ROUTING only.
:-)

> 
> > >
> > > With only one route per virtual channel active at a time.
> 
> [snip]
> 
> > >
> > > Thanks, I had a look at the MEDIA_ ioctls yesterday, G_TOPOLOGY in
> > > particular, which uses several pointers to arrays.
> > >
> > > Unfortunately, I didn't come up with anything better than using a
> > > translation structure, from the IOCTL layer to the subdevice
> > > operations layer:
> > > https://paste.debian.net/hidden/b192969d/
> > > (sharing a link for early comments, I can send v3 and you can comment
> > > there directly if you prefer to :)
> >
> > Hmm. That is a downside indeed. It's still a lesser problem than the compat
> > code in general --- which has been a source for bugs as well as nasty
> > security problems over time.
> >
> 
> Good!
> 
> > I think we need a naming scheme for such structs. How about just
> > calling that struct e.g. v4l2_subdev_krouting instead? It's simple, easy to
> > understand and it includes a suggestion which one is the kernel-only
> > variant.
> >
> 
> I kind of like that! thanks!
> 
> > You can btw. zero the struct memory by assigning { 0 } to it in
> > declaration. memset() in general is much more trouble. In this case you
> > could even do the assignments in delaration as well.
> >
> 
> Thanks, noted. I have been lazy and copied memset from other places in
> the ioctl handling code. I should check on your suggestions because I
> remember one of the many 0-initialization statement was a GCC specific one,
> don't remember which...

{} is GCC specific whereas { 0 } is not. But there have been long-standing
GCC bugs related to the use of { 0 } which is quite unfortunate --- they've
produced warnings or errors from code that is valid C...
Ian Arkver Feb. 22, 2019, 1:37 p.m. UTC | #13
Hi,

On 22/02/2019 11:29, Sakari Ailus wrote:
> Hi Jacopo,
> 
> On Fri, Feb 22, 2019 at 12:17:47PM +0100, Jacopo Mondi wrote:
>> Hi Sakari,
>>      thanks for your suggestions.
>>
>> On Fri, Feb 22, 2019 at 01:04:29PM +0200, Sakari Ailus wrote:
>>> Hi Jacopo,
>>
>> [snip]
>>
>>>> On the previous example, I thought about GMSL-like devices, that can
>>>> output the video streams received from different remotes in a
>>>> separate virtual channel, at the same time.
>>>>
>>>> A possible routing table in that case would be like:
>>>>
>>>> Pads 0, 1, 2, 3 = SINKS
>>>> Pad 4 = SOURCE with 4 streams (1 for each VC)
>>>>
>>>> 0/0 -> 4/0
>>>> 0/0 -> 4/1
>>>> 0/0 -> 4/2
>>>> 0/0 -> 4/3
>>>> 1/0 -> 4/0
>>>> 1/0 -> 4/1
>>>> 1/0 -> 4/2
>>>> 1/0 -> 4/3
>>>> 2/0 -> 4/0
>>>> 2/0 -> 4/1
>>>> 2/0 -> 4/2
>>>> 2/0 -> 4/3
>>>> 3/0 -> 4/0
>>>> 3/0 -> 4/1
>>>> 3/0 -> 4/2
>>>> 3/0 -> 4/3
>>>
>>> If more than one pad can handle multiplexed streams, then you may end up in
>>> a situation like that. Indeed.
>>>
>>
>> Please note that in this case there is only one pad that can handle
>> multiplexed stream. The size of the routing table is the
>> multiplication of the total number of pads by the product of all
>> streams per pad. In this case (4 * (1 * 1 * 1 * 4))
> 
> Oh, good point, that's the case for G_ROUTING. I thought of S_ROUTING only.
> :-)
> 
>>
>>>>
>>>> With only one route per virtual channel active at a time.
>>
>> [snip]
>>
>>>>
>>>> Thanks, I had a look at the MEDIA_ ioctls yesterday, G_TOPOLOGY in
>>>> particular, which uses several pointers to arrays.
>>>>
>>>> Unfortunately, I didn't come up with anything better than using a
>>>> translation structure, from the IOCTL layer to the subdevice
>>>> operations layer:
>>>> https://paste.debian.net/hidden/b192969d/
>>>> (sharing a link for early comments, I can send v3 and you can comment
>>>> there directly if you prefer to :)
>>>
>>> Hmm. That is a downside indeed. It's still a lesser problem than the compat
>>> code in general --- which has been a source for bugs as well as nasty
>>> security problems over time.
>>>
>>
>> Good!
>>
>>> I think we need a naming scheme for such structs. How about just
>>> calling that struct e.g. v4l2_subdev_krouting instead? It's simple, easy to
>>> understand and it includes a suggestion which one is the kernel-only
>>> variant.
>>>
>>
>> I kind of like that! thanks!
>>
>>> You can btw. zero the struct memory by assigning { 0 } to it in
>>> declaration. memset() in general is much more trouble. In this case you
>>> could even do the assignments in delaration as well.
>>>
>>
>> Thanks, noted. I have been lazy and copied memset from other places in
>> the ioctl handling code. I should check on your suggestions because I
>> remember one of the many 0-initialization statement was a GCC specific one,
>> don't remember which...
> 
> {} is GCC specific whereas { 0 } is not. But there have been long-standing
> GCC bugs related to the use of { 0 } which is quite unfortunate --- they've
> produced warnings or errors from code that is valid C...
> 

Using = {} to intialise structs is all over the kernel and quite 
accepted. Eg. recent discussion with Mauro at [1].

[1] https://lore.kernel.org/linux-media/20181207105816.4c53aeaa@coco.lan/

Regards,
Ian
Geert Uytterhoeven Feb. 22, 2019, 1:50 p.m. UTC | #14
Hi Sakari,

On Fri, Feb 22, 2019 at 12:30 PM Sakari Ailus
<sakari.ailus@linux.intel.com> wrote:
> On Fri, Feb 22, 2019 at 12:17:47PM +0100, Jacopo Mondi wrote:
> > On Fri, Feb 22, 2019 at 01:04:29PM +0200, Sakari Ailus wrote:
> > > You can btw. zero the struct memory by assigning { 0 } to it in
> > > declaration. memset() in general is much more trouble. In this case you
> > > could even do the assignments in delaration as well.
> > >
> >
> > Thanks, noted. I have been lazy and copied memset from other places in
> > the ioctl handling code. I should check on your suggestions because I
> > remember one of the many 0-initialization statement was a GCC specific one,
> > don't remember which...
>
> {} is GCC specific whereas { 0 } is not. But there have been long-standing
> GCC bugs related to the use of { 0 } which is quite unfortunate --- they've
> produced warnings or errors from code that is valid C...

Most of these are gone since commit cafa0010cd51fb71 ("Raise the minimum
required gcc version to 4.6").

Gr{oetje,eeting}s,

                        Geert


--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
diff mbox series

Patch

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 7de041bae84fb2f2..40406acb51ec0906 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -19,6 +19,7 @@ 
 #include <linux/kernel.h>
 #include <linux/version.h>
 
+#include <linux/v4l2-subdev.h>
 #include <linux/videodev2.h>
 
 #include <media/v4l2-common.h>
@@ -2924,6 +2925,23 @@  static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
 		}
 		break;
 	}
+
+	case VIDIOC_SUBDEV_G_ROUTING:
+	case VIDIOC_SUBDEV_S_ROUTING: {
+		struct v4l2_subdev_routing *route = parg;
+
+		if (route->num_routes > 0) {
+			if (route->num_routes > 256)
+				return -EINVAL;
+
+			*user_ptr = (void __user *)route->routes;
+			*kernel_ptr = (void *)&route->routes;
+			*array_size = sizeof(struct v4l2_subdev_route)
+				    * route->num_routes;
+			ret = 1;
+		}
+		break;
+	}
 	}
 
 	return ret;
@@ -3033,7 +3051,7 @@  video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
 	 * Some ioctls can return an error, but still have valid
 	 * results that must be returned.
 	 */
-	if (err < 0 && !always_copy)
+	if (err < 0 && !always_copy && cmd != VIDIOC_SUBDEV_G_ROUTING)
 		goto out;
 
 out_array_args:
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 792f41dffe2329b9..1d3b37cf548fa533 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -516,7 +516,35 @@  static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 
 	case VIDIOC_SUBDEV_QUERYSTD:
 		return v4l2_subdev_call(sd, video, querystd, arg);
+
+	case VIDIOC_SUBDEV_G_ROUTING:
+		return v4l2_subdev_call(sd, pad, get_routing, arg);
+
+	case VIDIOC_SUBDEV_S_ROUTING: {
+		struct v4l2_subdev_routing *route = arg;
+		unsigned int i;
+
+		if (route->num_routes > sd->entity.num_pads)
+			return -EINVAL;
+
+		for (i = 0; i < route->num_routes; ++i) {
+			unsigned int sink = route->routes[i].sink_pad;
+			unsigned int source = route->routes[i].source_pad;
+			struct media_pad *pads = sd->entity.pads;
+
+			if (sink >= sd->entity.num_pads ||
+			    source >= sd->entity.num_pads)
+				return -EINVAL;
+
+			if (!(pads[sink].flags & MEDIA_PAD_FL_SINK) ||
+			    !(pads[source].flags & MEDIA_PAD_FL_SOURCE))
+				return -EINVAL;
+		}
+
+		return v4l2_subdev_call(sd, pad, set_routing, route);
+	}
 #endif
+
 	default:
 		return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
 	}
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 9102d6ca566e01f2..5acaeeb9b3cacefa 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -679,6 +679,9 @@  struct v4l2_subdev_pad_config {
  *
  * @set_frame_desc: set the low level media bus frame parameters, @fd array
  *                  may be adjusted by the subdev driver to device capabilities.
+ *
+ * @get_routing: callback for VIDIOC_SUBDEV_G_ROUTING IOCTL handler.
+ * @set_routing: callback for VIDIOC_SUBDEV_S_ROUTING IOCTL handler.
  */
 struct v4l2_subdev_pad_ops {
 	int (*init_cfg)(struct v4l2_subdev *sd,
@@ -719,6 +722,10 @@  struct v4l2_subdev_pad_ops {
 			      struct v4l2_mbus_frame_desc *fd);
 	int (*set_frame_desc)(struct v4l2_subdev *sd, unsigned int pad,
 			      struct v4l2_mbus_frame_desc *fd);
+	int (*get_routing)(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_routing *route);
+	int (*set_routing)(struct v4l2_subdev *sd,
+			   struct v4l2_subdev_routing *route);
 };
 
 /**
diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
index 03970ce3074193e6..af069bfb10ca23a5 100644
--- a/include/uapi/linux/v4l2-subdev.h
+++ b/include/uapi/linux/v4l2-subdev.h
@@ -155,6 +155,44 @@  struct v4l2_subdev_selection {
 	__u32 reserved[8];
 };
 
+#define V4L2_SUBDEV_ROUTE_FL_ACTIVE	(1 << 0)
+#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE	(1 << 1)
+
+/**
+ * struct v4l2_subdev_route - A signal route inside a subdev
+ * @sink_pad: the sink pad
+ * @sink_stream: the sink stream
+ * @source_pad: the source pad
+ * @source_stream: the source stream
+ * @flags: route flags:
+ *
+ *	V4L2_SUBDEV_ROUTE_FL_ACTIVE: Is the stream in use or not? An
+ *	active stream will start when streaming is enabled on a video
+ *	node. Set by the user.
+ *
+ *	V4L2_SUBDEV_ROUTE_FL_IMMUTABLE: Is the stream immutable, i.e.
+ *	can it be activated and inactivated? Set by the driver.
+ */
+struct v4l2_subdev_route {
+	__u32 sink_pad;
+	__u32 sink_stream;
+	__u32 source_pad;
+	__u32 source_stream;
+	__u32 flags;
+	__u32 reserved[5];
+};
+
+/**
+ * struct v4l2_subdev_routing - Routing information
+ * @routes: the routes array
+ * @num_routes: the total number of routes in the routes array
+ */
+struct v4l2_subdev_routing {
+	struct v4l2_subdev_route *routes;
+	__u32 num_routes;
+	__u32 reserved[5];
+};
+
 /* Backwards compatibility define --- to be removed */
 #define v4l2_subdev_edid v4l2_edid
 
@@ -181,5 +219,7 @@  struct v4l2_subdev_selection {
 #define VIDIOC_SUBDEV_ENUM_DV_TIMINGS		_IOWR('V', 98, struct v4l2_enum_dv_timings)
 #define VIDIOC_SUBDEV_QUERY_DV_TIMINGS		_IOR('V', 99, struct v4l2_dv_timings)
 #define VIDIOC_SUBDEV_DV_TIMINGS_CAP		_IOWR('V', 100, struct v4l2_dv_timings_cap)
+#define VIDIOC_SUBDEV_G_ROUTING			_IOWR('V', 38, struct v4l2_subdev_routing)
+#define VIDIOC_SUBDEV_S_ROUTING			_IOWR('V', 39, struct v4l2_subdev_routing)
 
 #endif