diff options
Diffstat (limited to 'drivers/media/platform/vimc/vimc-capture.c')
-rw-r--r-- | drivers/media/platform/vimc/vimc-capture.c | 99 |
1 files changed, 69 insertions, 30 deletions
diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c index 359f59efb44e..14cb32e21130 100644 --- a/drivers/media/platform/vimc/vimc-capture.c +++ b/drivers/media/platform/vimc/vimc-capture.c | |||
@@ -15,15 +15,21 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/component.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
18 | #include <media/v4l2-ioctl.h> | 21 | #include <media/v4l2-ioctl.h> |
19 | #include <media/videobuf2-core.h> | 22 | #include <media/videobuf2-core.h> |
20 | #include <media/videobuf2-vmalloc.h> | 23 | #include <media/videobuf2-vmalloc.h> |
21 | 24 | ||
22 | #include "vimc-capture.h" | 25 | #include "vimc-common.h" |
26 | |||
27 | #define VIMC_CAP_DRV_NAME "vimc-capture" | ||
23 | 28 | ||
24 | struct vimc_cap_device { | 29 | struct vimc_cap_device { |
25 | struct vimc_ent_device ved; | 30 | struct vimc_ent_device ved; |
26 | struct video_device vdev; | 31 | struct video_device vdev; |
32 | struct device *dev; | ||
27 | struct v4l2_pix_format format; | 33 | struct v4l2_pix_format format; |
28 | struct vb2_queue queue; | 34 | struct vb2_queue queue; |
29 | struct list_head buf_list; | 35 | struct list_head buf_list; |
@@ -131,7 +137,7 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, | |||
131 | 137 | ||
132 | vimc_cap_try_fmt_vid_cap(file, priv, f); | 138 | vimc_cap_try_fmt_vid_cap(file, priv, f); |
133 | 139 | ||
134 | dev_dbg(vcap->vdev.v4l2_dev->dev, "%s: format update: " | 140 | dev_dbg(vcap->dev, "%s: format update: " |
135 | "old:%dx%d (0x%x, %d, %d, %d, %d) " | 141 | "old:%dx%d (0x%x, %d, %d, %d, %d) " |
136 | "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name, | 142 | "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name, |
137 | /* old */ | 143 | /* old */ |
@@ -309,8 +315,7 @@ static int vimc_cap_buffer_prepare(struct vb2_buffer *vb) | |||
309 | unsigned long size = vcap->format.sizeimage; | 315 | unsigned long size = vcap->format.sizeimage; |
310 | 316 | ||
311 | if (vb2_plane_size(vb, 0) < size) { | 317 | if (vb2_plane_size(vb, 0) < size) { |
312 | dev_err(vcap->vdev.v4l2_dev->dev, | 318 | dev_err(vcap->dev, "%s: buffer too small (%lu < %lu)\n", |
313 | "%s: buffer too small (%lu < %lu)\n", | ||
314 | vcap->vdev.name, vb2_plane_size(vb, 0), size); | 319 | vcap->vdev.name, vb2_plane_size(vb, 0), size); |
315 | return -EINVAL; | 320 | return -EINVAL; |
316 | } | 321 | } |
@@ -335,8 +340,10 @@ static const struct media_entity_operations vimc_cap_mops = { | |||
335 | .link_validate = vimc_link_validate, | 340 | .link_validate = vimc_link_validate, |
336 | }; | 341 | }; |
337 | 342 | ||
338 | static void vimc_cap_destroy(struct vimc_ent_device *ved) | 343 | static void vimc_cap_comp_unbind(struct device *comp, struct device *master, |
344 | void *master_data) | ||
339 | { | 345 | { |
346 | struct vimc_ent_device *ved = dev_get_drvdata(comp); | ||
340 | struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, | 347 | struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, |
341 | ved); | 348 | ved); |
342 | 349 | ||
@@ -385,42 +392,35 @@ static void vimc_cap_process_frame(struct vimc_ent_device *ved, | |||
385 | vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); | 392 | vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); |
386 | } | 393 | } |
387 | 394 | ||
388 | struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | 395 | static int vimc_cap_comp_bind(struct device *comp, struct device *master, |
389 | const char *const name, | 396 | void *master_data) |
390 | u16 num_pads, | ||
391 | const unsigned long *pads_flag) | ||
392 | { | 397 | { |
398 | struct v4l2_device *v4l2_dev = master_data; | ||
399 | struct vimc_platform_data *pdata = comp->platform_data; | ||
393 | const struct vimc_pix_map *vpix; | 400 | const struct vimc_pix_map *vpix; |
394 | struct vimc_cap_device *vcap; | 401 | struct vimc_cap_device *vcap; |
395 | struct video_device *vdev; | 402 | struct video_device *vdev; |
396 | struct vb2_queue *q; | 403 | struct vb2_queue *q; |
397 | int ret; | 404 | int ret; |
398 | 405 | ||
399 | /* | ||
400 | * Check entity configuration params | ||
401 | * NOTE: we only support a single sink pad | ||
402 | */ | ||
403 | if (!name || num_pads != 1 || !pads_flag || | ||
404 | !(pads_flag[0] & MEDIA_PAD_FL_SINK)) | ||
405 | return ERR_PTR(-EINVAL); | ||
406 | |||
407 | /* Allocate the vimc_cap_device struct */ | 406 | /* Allocate the vimc_cap_device struct */ |
408 | vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); | 407 | vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); |
409 | if (!vcap) | 408 | if (!vcap) |
410 | return ERR_PTR(-ENOMEM); | 409 | return -ENOMEM; |
411 | 410 | ||
412 | /* Allocate the pads */ | 411 | /* Allocate the pads */ |
413 | vcap->ved.pads = vimc_pads_init(num_pads, pads_flag); | 412 | vcap->ved.pads = |
413 | vimc_pads_init(1, (const unsigned long[1]) {MEDIA_PAD_FL_SINK}); | ||
414 | if (IS_ERR(vcap->ved.pads)) { | 414 | if (IS_ERR(vcap->ved.pads)) { |
415 | ret = PTR_ERR(vcap->ved.pads); | 415 | ret = PTR_ERR(vcap->ved.pads); |
416 | goto err_free_vcap; | 416 | goto err_free_vcap; |
417 | } | 417 | } |
418 | 418 | ||
419 | /* Initialize the media entity */ | 419 | /* Initialize the media entity */ |
420 | vcap->vdev.entity.name = name; | 420 | vcap->vdev.entity.name = pdata->entity_name; |
421 | vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; | 421 | vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; |
422 | ret = media_entity_pads_init(&vcap->vdev.entity, | 422 | ret = media_entity_pads_init(&vcap->vdev.entity, |
423 | num_pads, vcap->ved.pads); | 423 | 1, vcap->ved.pads); |
424 | if (ret) | 424 | if (ret) |
425 | goto err_clean_pads; | 425 | goto err_clean_pads; |
426 | 426 | ||
@@ -441,9 +441,8 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | |||
441 | 441 | ||
442 | ret = vb2_queue_init(q); | 442 | ret = vb2_queue_init(q); |
443 | if (ret) { | 443 | if (ret) { |
444 | dev_err(vcap->vdev.v4l2_dev->dev, | 444 | dev_err(comp, "%s: vb2 queue init failed (err=%d)\n", |
445 | "%s: vb2 queue init failed (err=%d)\n", | 445 | pdata->entity_name, ret); |
446 | vcap->vdev.name, ret); | ||
447 | goto err_clean_m_ent; | 446 | goto err_clean_m_ent; |
448 | } | 447 | } |
449 | 448 | ||
@@ -459,10 +458,11 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | |||
459 | vcap->format.height; | 458 | vcap->format.height; |
460 | 459 | ||
461 | /* Fill the vimc_ent_device struct */ | 460 | /* Fill the vimc_ent_device struct */ |
462 | vcap->ved.destroy = vimc_cap_destroy; | ||
463 | vcap->ved.ent = &vcap->vdev.entity; | 461 | vcap->ved.ent = &vcap->vdev.entity; |
464 | vcap->ved.process_frame = vimc_cap_process_frame; | 462 | vcap->ved.process_frame = vimc_cap_process_frame; |
465 | vcap->ved.vdev_get_format = vimc_cap_get_format; | 463 | vcap->ved.vdev_get_format = vimc_cap_get_format; |
464 | dev_set_drvdata(comp, &vcap->ved); | ||
465 | vcap->dev = comp; | ||
466 | 466 | ||
467 | /* Initialize the video_device struct */ | 467 | /* Initialize the video_device struct */ |
468 | vdev = &vcap->vdev; | 468 | vdev = &vcap->vdev; |
@@ -475,19 +475,18 @@ struct vimc_ent_device *vimc_cap_create(struct v4l2_device *v4l2_dev, | |||
475 | vdev->queue = q; | 475 | vdev->queue = q; |
476 | vdev->v4l2_dev = v4l2_dev; | 476 | vdev->v4l2_dev = v4l2_dev; |
477 | vdev->vfl_dir = VFL_DIR_RX; | 477 | vdev->vfl_dir = VFL_DIR_RX; |
478 | strlcpy(vdev->name, name, sizeof(vdev->name)); | 478 | strlcpy(vdev->name, pdata->entity_name, sizeof(vdev->name)); |
479 | video_set_drvdata(vdev, &vcap->ved); | 479 | video_set_drvdata(vdev, &vcap->ved); |
480 | 480 | ||
481 | /* Register the video_device with the v4l2 and the media framework */ | 481 | /* Register the video_device with the v4l2 and the media framework */ |
482 | ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | 482 | ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); |
483 | if (ret) { | 483 | if (ret) { |
484 | dev_err(vcap->vdev.v4l2_dev->dev, | 484 | dev_err(comp, "%s: video register failed (err=%d)\n", |
485 | "%s: video register failed (err=%d)\n", | ||
486 | vcap->vdev.name, ret); | 485 | vcap->vdev.name, ret); |
487 | goto err_release_queue; | 486 | goto err_release_queue; |
488 | } | 487 | } |
489 | 488 | ||
490 | return &vcap->ved; | 489 | return 0; |
491 | 490 | ||
492 | err_release_queue: | 491 | err_release_queue: |
493 | vb2_queue_release(q); | 492 | vb2_queue_release(q); |
@@ -498,5 +497,45 @@ err_clean_pads: | |||
498 | err_free_vcap: | 497 | err_free_vcap: |
499 | kfree(vcap); | 498 | kfree(vcap); |
500 | 499 | ||
501 | return ERR_PTR(ret); | 500 | return ret; |
502 | } | 501 | } |
502 | |||
503 | static const struct component_ops vimc_cap_comp_ops = { | ||
504 | .bind = vimc_cap_comp_bind, | ||
505 | .unbind = vimc_cap_comp_unbind, | ||
506 | }; | ||
507 | |||
508 | static int vimc_cap_probe(struct platform_device *pdev) | ||
509 | { | ||
510 | return component_add(&pdev->dev, &vimc_cap_comp_ops); | ||
511 | } | ||
512 | |||
513 | static int vimc_cap_remove(struct platform_device *pdev) | ||
514 | { | ||
515 | component_del(&pdev->dev, &vimc_cap_comp_ops); | ||
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static struct platform_driver vimc_cap_pdrv = { | ||
521 | .probe = vimc_cap_probe, | ||
522 | .remove = vimc_cap_remove, | ||
523 | .driver = { | ||
524 | .name = VIMC_CAP_DRV_NAME, | ||
525 | }, | ||
526 | }; | ||
527 | |||
528 | static const struct platform_device_id vimc_cap_driver_ids[] = { | ||
529 | { | ||
530 | .name = VIMC_CAP_DRV_NAME, | ||
531 | }, | ||
532 | { } | ||
533 | }; | ||
534 | |||
535 | module_platform_driver(vimc_cap_pdrv); | ||
536 | |||
537 | MODULE_DEVICE_TABLE(platform, vimc_cap_driver_ids); | ||
538 | |||
539 | MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Capture"); | ||
540 | MODULE_AUTHOR("Helen Mae Koike Fornazier <helen.fornazier@gmail.com>"); | ||
541 | MODULE_LICENSE("GPL"); | ||