diff options
author | Helen Fornazier <helen.koike@collabora.com> | 2017-06-19 13:00:14 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2017-06-23 08:05:38 -0400 |
commit | 288a22d45c631f5be5e1c8b83977a78841083d3c (patch) | |
tree | 976410940d5a414d438afbcc53eedb386c9dacd4 /drivers/media/platform/vimc | |
parent | bf5fb95c261de259e912e49973c66347a0a5b3d3 (diff) |
[media] vimc: common: Add vimc_link_validate
All links will be checked in the same way. Adding a helper function for
that
Signed-off-by: Helen Koike <helen.koike@collabora.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/platform/vimc')
-rw-r--r-- | drivers/media/platform/vimc/vimc-capture.c | 78 | ||||
-rw-r--r-- | drivers/media/platform/vimc/vimc-common.c | 121 | ||||
-rw-r--r-- | drivers/media/platform/vimc/vimc-common.h | 14 |
3 files changed, 145 insertions, 68 deletions
diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c index 93f6a0916329..5bdecd103d55 100644 --- a/drivers/media/platform/vimc/vimc-capture.c +++ b/drivers/media/platform/vimc/vimc-capture.c | |||
@@ -64,6 +64,15 @@ static int vimc_cap_querycap(struct file *file, void *priv, | |||
64 | return 0; | 64 | return 0; |
65 | } | 65 | } |
66 | 66 | ||
67 | static void vimc_cap_get_format(struct vimc_ent_device *ved, | ||
68 | struct v4l2_pix_format *fmt) | ||
69 | { | ||
70 | struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, | ||
71 | ved); | ||
72 | |||
73 | *fmt = vcap->format; | ||
74 | } | ||
75 | |||
67 | static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, | 76 | static int vimc_cap_fmt_vid_cap(struct file *file, void *priv, |
68 | struct v4l2_format *f) | 77 | struct v4l2_format *f) |
69 | { | 78 | { |
@@ -231,74 +240,8 @@ static const struct vb2_ops vimc_cap_qops = { | |||
231 | .wait_finish = vb2_ops_wait_finish, | 240 | .wait_finish = vb2_ops_wait_finish, |
232 | }; | 241 | }; |
233 | 242 | ||
234 | /* | ||
235 | * NOTE: this function is a copy of v4l2_subdev_link_validate_get_format | ||
236 | * maybe the v4l2 function should be public | ||
237 | */ | ||
238 | static int vimc_cap_v4l2_subdev_link_validate_get_format(struct media_pad *pad, | ||
239 | struct v4l2_subdev_format *fmt) | ||
240 | { | ||
241 | struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(pad->entity); | ||
242 | |||
243 | fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
244 | fmt->pad = pad->index; | ||
245 | |||
246 | return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); | ||
247 | } | ||
248 | |||
249 | static int vimc_cap_link_validate(struct media_link *link) | ||
250 | { | ||
251 | struct v4l2_subdev_format source_fmt; | ||
252 | const struct vimc_pix_map *vpix; | ||
253 | struct vimc_cap_device *vcap = container_of(link->sink->entity, | ||
254 | struct vimc_cap_device, | ||
255 | vdev.entity); | ||
256 | struct v4l2_pix_format *sink_fmt = &vcap->format; | ||
257 | int ret; | ||
258 | |||
259 | /* | ||
260 | * if it is a raw node from vimc-core, ignore the link for now | ||
261 | * TODO: remove this when there are no more raw nodes in the | ||
262 | * core and return error instead | ||
263 | */ | ||
264 | if (link->source->entity->obj_type == MEDIA_ENTITY_TYPE_BASE) | ||
265 | return 0; | ||
266 | |||
267 | /* Get the the format of the subdev */ | ||
268 | ret = vimc_cap_v4l2_subdev_link_validate_get_format(link->source, | ||
269 | &source_fmt); | ||
270 | if (ret) | ||
271 | return ret; | ||
272 | |||
273 | dev_dbg(vcap->vdev.v4l2_dev->dev, | ||
274 | "%s: link validate formats src:%dx%d %d sink:%dx%d %d\n", | ||
275 | vcap->vdev.name, | ||
276 | source_fmt.format.width, source_fmt.format.height, | ||
277 | source_fmt.format.code, | ||
278 | sink_fmt->width, sink_fmt->height, | ||
279 | sink_fmt->pixelformat); | ||
280 | |||
281 | /* The width, height and code must match. */ | ||
282 | vpix = vimc_pix_map_by_pixelformat(sink_fmt->pixelformat); | ||
283 | if (source_fmt.format.width != sink_fmt->width | ||
284 | || source_fmt.format.height != sink_fmt->height | ||
285 | || vpix->code != source_fmt.format.code) | ||
286 | return -EPIPE; | ||
287 | |||
288 | /* | ||
289 | * The field order must match, or the sink field order must be NONE | ||
290 | * to support interlaced hardware connected to bridges that support | ||
291 | * progressive formats only. | ||
292 | */ | ||
293 | if (source_fmt.format.field != sink_fmt->field && | ||
294 | sink_fmt->field != V4L2_FIELD_NONE) | ||
295 | return -EPIPE; | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static const struct media_entity_operations vimc_cap_mops = { | 243 | static const struct media_entity_operations vimc_cap_mops = { |
301 | .link_validate = vimc_cap_link_validate, | 244 | .link_validate = vimc_link_validate, |
302 | }; | 245 | }; |
303 | 246 | ||
304 | static void vimc_cap_destroy(struct vimc_ent_device *ved) | 247 | static void vimc_cap_destroy(struct vimc_ent_device *ved) |
@@ -434,6 +377,7 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | |||
434 | vcap->ved.destroy = vimc_cap_destroy; | 377 | vcap->ved.destroy = vimc_cap_destroy; |
435 | vcap->ved.ent = &vcap->vdev.entity; | 378 | vcap->ved.ent = &vcap->vdev.entity; |
436 | vcap->ved.process_frame = vimc_cap_process_frame; | 379 | vcap->ved.process_frame = vimc_cap_process_frame; |
380 | vcap->ved.vdev_get_format = vimc_cap_get_format; | ||
437 | 381 | ||
438 | /* Initialize the video_device struct */ | 382 | /* Initialize the video_device struct */ |
439 | vdev = &vcap->vdev; | 383 | vdev = &vcap->vdev; |
diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index f809a9d756b9..6ad77fdc04ad 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c | |||
@@ -252,8 +252,127 @@ int vimc_pipeline_s_stream(struct media_entity *ent, int enable) | |||
252 | return 0; | 252 | return 0; |
253 | } | 253 | } |
254 | 254 | ||
255 | static int vimc_get_mbus_format(struct media_pad *pad, | ||
256 | struct v4l2_subdev_format *fmt) | ||
257 | { | ||
258 | if (is_media_entity_v4l2_subdev(pad->entity)) { | ||
259 | struct v4l2_subdev *sd = | ||
260 | media_entity_to_v4l2_subdev(pad->entity); | ||
261 | int ret; | ||
262 | |||
263 | fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; | ||
264 | fmt->pad = pad->index; | ||
265 | |||
266 | ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); | ||
267 | if (ret) | ||
268 | return ret; | ||
269 | |||
270 | } else if (is_media_entity_v4l2_video_device(pad->entity)) { | ||
271 | struct video_device *vdev = container_of(pad->entity, | ||
272 | struct video_device, | ||
273 | entity); | ||
274 | struct vimc_ent_device *ved = video_get_drvdata(vdev); | ||
275 | const struct vimc_pix_map *vpix; | ||
276 | struct v4l2_pix_format vdev_fmt; | ||
277 | |||
278 | if (!ved->vdev_get_format) | ||
279 | return -ENOIOCTLCMD; | ||
280 | |||
281 | ved->vdev_get_format(ved, &vdev_fmt); | ||
282 | vpix = vimc_pix_map_by_pixelformat(vdev_fmt.pixelformat); | ||
283 | v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, vpix->code); | ||
284 | } else { | ||
285 | return -EINVAL; | ||
286 | } | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | int vimc_link_validate(struct media_link *link) | ||
292 | { | ||
293 | struct v4l2_subdev_format source_fmt, sink_fmt; | ||
294 | int ret; | ||
295 | |||
296 | /* | ||
297 | * if it is a raw node from vimc-core, ignore the link for now | ||
298 | * TODO: remove this when there are no more raw nodes in the | ||
299 | * core and return error instead | ||
300 | */ | ||
301 | if (link->source->entity->obj_type == MEDIA_ENTITY_TYPE_BASE) | ||
302 | return 0; | ||
303 | |||
304 | ret = vimc_get_mbus_format(link->source, &source_fmt); | ||
305 | if (ret) | ||
306 | return ret; | ||
307 | |||
308 | ret = vimc_get_mbus_format(link->sink, &sink_fmt); | ||
309 | if (ret) | ||
310 | return ret; | ||
311 | |||
312 | pr_info("vimc link validate: " | ||
313 | "%s:src:%dx%d (0x%x, %d, %d, %d, %d) " | ||
314 | "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n", | ||
315 | /* src */ | ||
316 | link->source->entity->name, | ||
317 | source_fmt.format.width, source_fmt.format.height, | ||
318 | source_fmt.format.code, source_fmt.format.colorspace, | ||
319 | source_fmt.format.quantization, source_fmt.format.xfer_func, | ||
320 | source_fmt.format.ycbcr_enc, | ||
321 | /* sink */ | ||
322 | link->sink->entity->name, | ||
323 | sink_fmt.format.width, sink_fmt.format.height, | ||
324 | sink_fmt.format.code, sink_fmt.format.colorspace, | ||
325 | sink_fmt.format.quantization, sink_fmt.format.xfer_func, | ||
326 | sink_fmt.format.ycbcr_enc); | ||
327 | |||
328 | /* The width, height and code must match. */ | ||
329 | if (source_fmt.format.width != sink_fmt.format.width | ||
330 | || source_fmt.format.height != sink_fmt.format.height | ||
331 | || source_fmt.format.code != sink_fmt.format.code) | ||
332 | return -EPIPE; | ||
333 | |||
334 | /* | ||
335 | * The field order must match, or the sink field order must be NONE | ||
336 | * to support interlaced hardware connected to bridges that support | ||
337 | * progressive formats only. | ||
338 | */ | ||
339 | if (source_fmt.format.field != sink_fmt.format.field && | ||
340 | sink_fmt.format.field != V4L2_FIELD_NONE) | ||
341 | return -EPIPE; | ||
342 | |||
343 | /* | ||
344 | * If colorspace is DEFAULT, then assume all the colorimetry is also | ||
345 | * DEFAULT, return 0 to skip comparing the other colorimetry parameters | ||
346 | */ | ||
347 | if (source_fmt.format.colorspace == V4L2_COLORSPACE_DEFAULT | ||
348 | || sink_fmt.format.colorspace == V4L2_COLORSPACE_DEFAULT) | ||
349 | return 0; | ||
350 | |||
351 | /* Colorspace must match. */ | ||
352 | if (source_fmt.format.colorspace != sink_fmt.format.colorspace) | ||
353 | return -EPIPE; | ||
354 | |||
355 | /* Colorimetry must match if they are not set to DEFAULT */ | ||
356 | if (source_fmt.format.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT | ||
357 | && sink_fmt.format.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT | ||
358 | && source_fmt.format.ycbcr_enc != sink_fmt.format.ycbcr_enc) | ||
359 | return -EPIPE; | ||
360 | |||
361 | if (source_fmt.format.quantization != V4L2_QUANTIZATION_DEFAULT | ||
362 | && sink_fmt.format.quantization != V4L2_QUANTIZATION_DEFAULT | ||
363 | && source_fmt.format.quantization != sink_fmt.format.quantization) | ||
364 | return -EPIPE; | ||
365 | |||
366 | if (source_fmt.format.xfer_func != V4L2_XFER_FUNC_DEFAULT | ||
367 | && sink_fmt.format.xfer_func != V4L2_XFER_FUNC_DEFAULT | ||
368 | && source_fmt.format.xfer_func != sink_fmt.format.xfer_func) | ||
369 | return -EPIPE; | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
255 | static const struct media_entity_operations vimc_ent_sd_mops = { | 374 | static const struct media_entity_operations vimc_ent_sd_mops = { |
256 | .link_validate = v4l2_subdev_link_validate, | 375 | .link_validate = vimc_link_validate, |
257 | }; | 376 | }; |
258 | 377 | ||
259 | int vimc_ent_sd_register(struct vimc_ent_device *ved, | 378 | int vimc_ent_sd_register(struct vimc_ent_device *ved, |
diff --git a/drivers/media/platform/vimc/vimc-common.h b/drivers/media/platform/vimc/vimc-common.h index 73e7e9479956..60ebde28f56b 100644 --- a/drivers/media/platform/vimc/vimc-common.h +++ b/drivers/media/platform/vimc/vimc-common.h | |||
@@ -45,6 +45,9 @@ struct vimc_pix_map { | |||
45 | * @pads: the list of pads of the node | 45 | * @pads: the list of pads of the node |
46 | * @destroy: callback to destroy the node | 46 | * @destroy: callback to destroy the node |
47 | * @process_frame: callback send a frame to that node | 47 | * @process_frame: callback send a frame to that node |
48 | * @vdev_get_format: callback that returns the current format a pad, used | ||
49 | * only when is_media_entity_v4l2_video_device(ent) returns | ||
50 | * true | ||
48 | * | 51 | * |
49 | * Each node of the topology must create a vimc_ent_device struct. Depending on | 52 | * Each node of the topology must create a vimc_ent_device struct. Depending on |
50 | * the node it will be of an instance of v4l2_subdev or video_device struct | 53 | * the node it will be of an instance of v4l2_subdev or video_device struct |
@@ -60,6 +63,8 @@ struct vimc_ent_device { | |||
60 | void (*destroy)(struct vimc_ent_device *); | 63 | void (*destroy)(struct vimc_ent_device *); |
61 | void (*process_frame)(struct vimc_ent_device *ved, | 64 | void (*process_frame)(struct vimc_ent_device *ved, |
62 | struct media_pad *sink, const void *frame); | 65 | struct media_pad *sink, const void *frame); |
66 | void (*vdev_get_format)(struct vimc_ent_device *ved, | ||
67 | struct v4l2_pix_format *fmt); | ||
63 | }; | 68 | }; |
64 | 69 | ||
65 | /** | 70 | /** |
@@ -160,4 +165,13 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, | |||
160 | void vimc_ent_sd_unregister(struct vimc_ent_device *ved, | 165 | void vimc_ent_sd_unregister(struct vimc_ent_device *ved, |
161 | struct v4l2_subdev *sd); | 166 | struct v4l2_subdev *sd); |
162 | 167 | ||
168 | /** | ||
169 | * vimc_link_validate - validates a media link | ||
170 | * | ||
171 | * @link: pointer to &struct media_link | ||
172 | * | ||
173 | * This function calls validates if a media link is valid for streaming. | ||
174 | */ | ||
175 | int vimc_link_validate(struct media_link *link); | ||
176 | |||
163 | #endif | 177 | #endif |