aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/v4l2-subdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/v4l2-subdev.c')
-rw-r--r--drivers/media/video/v4l2-subdev.c143
1 files changed, 131 insertions, 12 deletions
diff --git a/drivers/media/video/v4l2-subdev.c b/drivers/media/video/v4l2-subdev.c
index 6fe88e965a8c..db6e859b93d4 100644
--- a/drivers/media/video/v4l2-subdev.c
+++ b/drivers/media/video/v4l2-subdev.c
@@ -35,14 +35,9 @@
35static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd) 35static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
36{ 36{
37#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 37#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
38 /* Allocate try format and crop in the same memory block */ 38 fh->pad = kzalloc(sizeof(*fh->pad) * sd->entity.num_pads, GFP_KERNEL);
39 fh->try_fmt = kzalloc((sizeof(*fh->try_fmt) + sizeof(*fh->try_crop)) 39 if (fh->pad == NULL)
40 * sd->entity.num_pads, GFP_KERNEL);
41 if (fh->try_fmt == NULL)
42 return -ENOMEM; 40 return -ENOMEM;
43
44 fh->try_crop = (struct v4l2_rect *)
45 (fh->try_fmt + sd->entity.num_pads);
46#endif 41#endif
47 return 0; 42 return 0;
48} 43}
@@ -50,9 +45,8 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
50static void subdev_fh_free(struct v4l2_subdev_fh *fh) 45static void subdev_fh_free(struct v4l2_subdev_fh *fh)
51{ 46{
52#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) 47#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
53 kfree(fh->try_fmt); 48 kfree(fh->pad);
54 fh->try_fmt = NULL; 49 fh->pad = NULL;
55 fh->try_crop = NULL;
56#endif 50#endif
57} 51}
58 52
@@ -234,6 +228,8 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
234 228
235 case VIDIOC_SUBDEV_G_CROP: { 229 case VIDIOC_SUBDEV_G_CROP: {
236 struct v4l2_subdev_crop *crop = arg; 230 struct v4l2_subdev_crop *crop = arg;
231 struct v4l2_subdev_selection sel;
232 int rval;
237 233
238 if (crop->which != V4L2_SUBDEV_FORMAT_TRY && 234 if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
239 crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) 235 crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -242,11 +238,27 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
242 if (crop->pad >= sd->entity.num_pads) 238 if (crop->pad >= sd->entity.num_pads)
243 return -EINVAL; 239 return -EINVAL;
244 240
245 return v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop); 241 rval = v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
242 if (rval != -ENOIOCTLCMD)
243 return rval;
244
245 memset(&sel, 0, sizeof(sel));
246 sel.which = crop->which;
247 sel.pad = crop->pad;
248 sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL;
249
250 rval = v4l2_subdev_call(
251 sd, pad, get_selection, subdev_fh, &sel);
252
253 crop->rect = sel.r;
254
255 return rval;
246 } 256 }
247 257
248 case VIDIOC_SUBDEV_S_CROP: { 258 case VIDIOC_SUBDEV_S_CROP: {
249 struct v4l2_subdev_crop *crop = arg; 259 struct v4l2_subdev_crop *crop = arg;
260 struct v4l2_subdev_selection sel;
261 int rval;
250 262
251 if (crop->which != V4L2_SUBDEV_FORMAT_TRY && 263 if (crop->which != V4L2_SUBDEV_FORMAT_TRY &&
252 crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) 264 crop->which != V4L2_SUBDEV_FORMAT_ACTIVE)
@@ -255,7 +267,22 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
255 if (crop->pad >= sd->entity.num_pads) 267 if (crop->pad >= sd->entity.num_pads)
256 return -EINVAL; 268 return -EINVAL;
257 269
258 return v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop); 270 rval = v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
271 if (rval != -ENOIOCTLCMD)
272 return rval;
273
274 memset(&sel, 0, sizeof(sel));
275 sel.which = crop->which;
276 sel.pad = crop->pad;
277 sel.target = V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL;
278 sel.r = crop->rect;
279
280 rval = v4l2_subdev_call(
281 sd, pad, set_selection, subdev_fh, &sel);
282
283 crop->rect = sel.r;
284
285 return rval;
259 } 286 }
260 287
261 case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { 288 case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
@@ -293,6 +320,34 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
293 return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh, 320 return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh,
294 fie); 321 fie);
295 } 322 }
323
324 case VIDIOC_SUBDEV_G_SELECTION: {
325 struct v4l2_subdev_selection *sel = arg;
326
327 if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
328 sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
329 return -EINVAL;
330
331 if (sel->pad >= sd->entity.num_pads)
332 return -EINVAL;
333
334 return v4l2_subdev_call(
335 sd, pad, get_selection, subdev_fh, sel);
336 }
337
338 case VIDIOC_SUBDEV_S_SELECTION: {
339 struct v4l2_subdev_selection *sel = arg;
340
341 if (sel->which != V4L2_SUBDEV_FORMAT_TRY &&
342 sel->which != V4L2_SUBDEV_FORMAT_ACTIVE)
343 return -EINVAL;
344
345 if (sel->pad >= sd->entity.num_pads)
346 return -EINVAL;
347
348 return v4l2_subdev_call(
349 sd, pad, set_selection, subdev_fh, sel);
350 }
296#endif 351#endif
297 default: 352 default:
298 return v4l2_subdev_call(sd, core, ioctl, cmd, arg); 353 return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
@@ -332,6 +387,70 @@ const struct v4l2_file_operations v4l2_subdev_fops = {
332 .poll = subdev_poll, 387 .poll = subdev_poll,
333}; 388};
334 389
390#ifdef CONFIG_MEDIA_CONTROLLER
391int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
392 struct media_link *link,
393 struct v4l2_subdev_format *source_fmt,
394 struct v4l2_subdev_format *sink_fmt)
395{
396 if (source_fmt->format.width != sink_fmt->format.width
397 || source_fmt->format.height != sink_fmt->format.height
398 || source_fmt->format.code != sink_fmt->format.code)
399 return -EINVAL;
400
401 return 0;
402}
403EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate_default);
404
405static int
406v4l2_subdev_link_validate_get_format(struct media_pad *pad,
407 struct v4l2_subdev_format *fmt)
408{
409 switch (media_entity_type(pad->entity)) {
410 case MEDIA_ENT_T_V4L2_SUBDEV:
411 fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
412 fmt->pad = pad->index;
413 return v4l2_subdev_call(media_entity_to_v4l2_subdev(
414 pad->entity),
415 pad, get_fmt, NULL, fmt);
416 default:
417 WARN(1, "Driver bug! Wrong media entity type %d, entity %s\n",
418 media_entity_type(pad->entity), pad->entity->name);
419 /* Fall through */
420 case MEDIA_ENT_T_DEVNODE_V4L:
421 return -EINVAL;
422 }
423}
424
425int v4l2_subdev_link_validate(struct media_link *link)
426{
427 struct v4l2_subdev *sink;
428 struct v4l2_subdev_format sink_fmt, source_fmt;
429 int rval;
430
431 rval = v4l2_subdev_link_validate_get_format(
432 link->source, &source_fmt);
433 if (rval < 0)
434 return 0;
435
436 rval = v4l2_subdev_link_validate_get_format(
437 link->sink, &sink_fmt);
438 if (rval < 0)
439 return 0;
440
441 sink = media_entity_to_v4l2_subdev(link->sink->entity);
442
443 rval = v4l2_subdev_call(sink, pad, link_validate, link,
444 &source_fmt, &sink_fmt);
445 if (rval != -ENOIOCTLCMD)
446 return rval;
447
448 return v4l2_subdev_link_validate_default(
449 sink, link, &source_fmt, &sink_fmt);
450}
451EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
452#endif /* CONFIG_MEDIA_CONTROLLER */
453
335void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) 454void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops)
336{ 455{
337 INIT_LIST_HEAD(&sd->list); 456 INIT_LIST_HEAD(&sd->list);