aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <lyakh@axis700.grange>2008-12-01 07:44:59 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:38:22 -0500
commit25c4d74ea6f07f2aaa3df537619680ba967043f5 (patch)
tree58a33458a15e9720adc027ef443828550ba1f0eb
parentabe4c4710386a4859dae9193bfc9a1f0e3c60db4 (diff)
V4L/DVB (9787): soc-camera: let camera host drivers decide upon pixel format
Pixel format requested by the user is not necessarily the same, as what a sensor driver provides. There are situations, when a camera host driver provides the required format, but requires a different format from the sensor. Further, the list of formats, supported by sensors is pretty static and can be pretty good described with a constant list of structures. Whereas decisions, made by camera host drivers to support requested formats can be quite complex, therefore it is better to let the host driver do the work. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/pxa_camera.c32
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c32
-rw-r--r--drivers/media/video/soc_camera.c58
-rw-r--r--include/media/soc_camera.h3
4 files changed, 87 insertions, 38 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 2a811f8584b5..a375872b1342 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -907,17 +907,43 @@ static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
907static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd, 907static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd,
908 __u32 pixfmt, struct v4l2_rect *rect) 908 __u32 pixfmt, struct v4l2_rect *rect)
909{ 909{
910 return icd->ops->set_fmt_cap(icd, pixfmt, rect); 910 const struct soc_camera_data_format *cam_fmt;
911 int ret;
912
913 /*
914 * TODO: find a suitable supported by the SoC output format, check
915 * whether the sensor supports one of acceptable input formats.
916 */
917 if (pixfmt) {
918 cam_fmt = soc_camera_format_by_fourcc(icd, pixfmt);
919 if (!cam_fmt)
920 return -EINVAL;
921 }
922
923 ret = icd->ops->set_fmt_cap(icd, pixfmt, rect);
924 if (pixfmt && !ret)
925 icd->current_fmt = cam_fmt;
926
927 return ret;
911} 928}
912 929
913static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd, 930static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd,
914 struct v4l2_format *f) 931 struct v4l2_format *f)
915{ 932{
933 const struct soc_camera_data_format *cam_fmt;
916 int ret = pxa_camera_try_bus_param(icd, f->fmt.pix.pixelformat); 934 int ret = pxa_camera_try_bus_param(icd, f->fmt.pix.pixelformat);
917 935
918 if (ret < 0) 936 if (ret < 0)
919 return ret; 937 return ret;
920 938
939 /*
940 * TODO: find a suitable supported by the SoC output format, check
941 * whether the sensor supports one of acceptable input formats.
942 */
943 cam_fmt = soc_camera_format_by_fourcc(icd, f->fmt.pix.pixelformat);
944 if (!cam_fmt)
945 return -EINVAL;
946
921 /* limit to pxa hardware capabilities */ 947 /* limit to pxa hardware capabilities */
922 if (f->fmt.pix.height < 32) 948 if (f->fmt.pix.height < 32)
923 f->fmt.pix.height = 32; 949 f->fmt.pix.height = 32;
@@ -929,6 +955,10 @@ static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd,
929 f->fmt.pix.width = 2048; 955 f->fmt.pix.width = 2048;
930 f->fmt.pix.width &= ~0x01; 956 f->fmt.pix.width &= ~0x01;
931 957
958 f->fmt.pix.bytesperline = f->fmt.pix.width *
959 DIV_ROUND_UP(cam_fmt->depth, 8);
960 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
961
932 /* limit to sensor capabilities */ 962 /* limit to sensor capabilities */
933 return icd->ops->try_fmt_cap(icd, f); 963 return icd->ops->try_fmt_cap(icd, f);
934} 964}
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 87d0f3075811..02f846d1908b 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -453,17 +453,43 @@ static int sh_mobile_ceu_try_bus_param(struct soc_camera_device *icd,
453static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd, 453static int sh_mobile_ceu_set_fmt_cap(struct soc_camera_device *icd,
454 __u32 pixfmt, struct v4l2_rect *rect) 454 __u32 pixfmt, struct v4l2_rect *rect)
455{ 455{
456 return icd->ops->set_fmt_cap(icd, pixfmt, rect); 456 const struct soc_camera_data_format *cam_fmt;
457 int ret;
458
459 /*
460 * TODO: find a suitable supported by the SoC output format, check
461 * whether the sensor supports one of acceptable input formats.
462 */
463 if (pixfmt) {
464 cam_fmt = soc_camera_format_by_fourcc(icd, pixfmt);
465 if (!cam_fmt)
466 return -EINVAL;
467 }
468
469 ret = icd->ops->set_fmt_cap(icd, pixfmt, rect);
470 if (pixfmt && !ret)
471 icd->current_fmt = cam_fmt;
472
473 return ret;
457} 474}
458 475
459static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd, 476static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
460 struct v4l2_format *f) 477 struct v4l2_format *f)
461{ 478{
479 const struct soc_camera_data_format *cam_fmt;
462 int ret = sh_mobile_ceu_try_bus_param(icd, f->fmt.pix.pixelformat); 480 int ret = sh_mobile_ceu_try_bus_param(icd, f->fmt.pix.pixelformat);
463 481
464 if (ret < 0) 482 if (ret < 0)
465 return ret; 483 return ret;
466 484
485 /*
486 * TODO: find a suitable supported by the SoC output format, check
487 * whether the sensor supports one of acceptable input formats.
488 */
489 cam_fmt = soc_camera_format_by_fourcc(icd, f->fmt.pix.pixelformat);
490 if (!cam_fmt)
491 return -EINVAL;
492
467 /* FIXME: calculate using depth and bus width */ 493 /* FIXME: calculate using depth and bus width */
468 494
469 if (f->fmt.pix.height < 4) 495 if (f->fmt.pix.height < 4)
@@ -477,6 +503,10 @@ static int sh_mobile_ceu_try_fmt_cap(struct soc_camera_device *icd,
477 f->fmt.pix.width &= ~0x01; 503 f->fmt.pix.width &= ~0x01;
478 f->fmt.pix.height &= ~0x03; 504 f->fmt.pix.height &= ~0x03;
479 505
506 f->fmt.pix.bytesperline = f->fmt.pix.width *
507 DIV_ROUND_UP(cam_fmt->depth, 8);
508 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
509
480 /* limit to sensor capabilities */ 510 /* limit to sensor capabilities */
481 return icd->ops->try_fmt_cap(icd, f); 511 return icd->ops->try_fmt_cap(icd, f);
482} 512}
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index 7217de21e76b..01c33841d1c6 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -35,7 +35,7 @@ static LIST_HEAD(devices);
35static DEFINE_MUTEX(list_lock); 35static DEFINE_MUTEX(list_lock);
36static DEFINE_MUTEX(video_lock); 36static DEFINE_MUTEX(video_lock);
37 37
38const static struct soc_camera_data_format *format_by_fourcc( 38const struct soc_camera_data_format *soc_camera_format_by_fourcc(
39 struct soc_camera_device *icd, unsigned int fourcc) 39 struct soc_camera_device *icd, unsigned int fourcc)
40{ 40{
41 unsigned int i; 41 unsigned int i;
@@ -45,6 +45,7 @@ const static struct soc_camera_data_format *format_by_fourcc(
45 return icd->formats + i; 45 return icd->formats + i;
46 return NULL; 46 return NULL;
47} 47}
48EXPORT_SYMBOL(soc_camera_format_by_fourcc);
48 49
49static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, 50static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
50 struct v4l2_format *f) 51 struct v4l2_format *f)
@@ -54,25 +55,19 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
54 struct soc_camera_host *ici = 55 struct soc_camera_host *ici =
55 to_soc_camera_host(icd->dev.parent); 56 to_soc_camera_host(icd->dev.parent);
56 enum v4l2_field field; 57 enum v4l2_field field;
57 const struct soc_camera_data_format *fmt;
58 int ret; 58 int ret;
59 59
60 WARN_ON(priv != file->private_data); 60 WARN_ON(priv != file->private_data);
61 61
62 fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat); 62 /*
63 if (!fmt) { 63 * TODO: this might also have to migrate to host-drivers, if anyone
64 dev_dbg(&icd->dev, "invalid format 0x%08x\n", 64 * wishes to support other fields
65 f->fmt.pix.pixelformat); 65 */
66 return -EINVAL;
67 }
68
69 dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc);
70
71 field = f->fmt.pix.field; 66 field = f->fmt.pix.field;
72 67
73 if (field == V4L2_FIELD_ANY) { 68 if (field == V4L2_FIELD_ANY) {
74 field = V4L2_FIELD_NONE; 69 f->fmt.pix.field = V4L2_FIELD_NONE;
75 } else if (V4L2_FIELD_NONE != field) { 70 } else if (field != V4L2_FIELD_NONE) {
76 dev_err(&icd->dev, "Field type invalid.\n"); 71 dev_err(&icd->dev, "Field type invalid.\n");
77 return -EINVAL; 72 return -EINVAL;
78 } 73 }
@@ -80,13 +75,6 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
80 /* limit format to hardware capabilities */ 75 /* limit format to hardware capabilities */
81 ret = ici->ops->try_fmt_cap(icd, f); 76 ret = ici->ops->try_fmt_cap(icd, f);
82 77
83 /* calculate missing fields */
84 f->fmt.pix.field = field;
85 f->fmt.pix.bytesperline =
86 (f->fmt.pix.width * fmt->depth) >> 3;
87 f->fmt.pix.sizeimage =
88 f->fmt.pix.height * f->fmt.pix.bytesperline;
89
90 return ret; 78 return ret;
91} 79}
92 80
@@ -325,18 +313,10 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
325 to_soc_camera_host(icd->dev.parent); 313 to_soc_camera_host(icd->dev.parent);
326 int ret; 314 int ret;
327 struct v4l2_rect rect; 315 struct v4l2_rect rect;
328 const static struct soc_camera_data_format *data_fmt;
329 316
330 WARN_ON(priv != file->private_data); 317 WARN_ON(priv != file->private_data);
331 318
332 data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat); 319 ret = soc_camera_try_fmt_vid_cap(file, priv, f);
333 if (!data_fmt)
334 return -EINVAL;
335
336 /* buswidth may be further adjusted by the ici */
337 icd->buswidth = data_fmt->depth;
338
339 ret = soc_camera_try_fmt_vid_cap(file, icf, f);
340 if (ret < 0) 320 if (ret < 0)
341 return ret; 321 return ret;
342 322
@@ -345,14 +325,21 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv,
345 rect.width = f->fmt.pix.width; 325 rect.width = f->fmt.pix.width;
346 rect.height = f->fmt.pix.height; 326 rect.height = f->fmt.pix.height;
347 ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect); 327 ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);
348 if (ret < 0) 328 if (ret < 0) {
349 return ret; 329 return ret;
330 } else if (!icd->current_fmt ||
331 icd->current_fmt->fourcc != f->fmt.pix.pixelformat) {
332 dev_err(&ici->dev, "Host driver hasn't set up current "
333 "format correctly!\n");
334 return -EINVAL;
335 }
350 336
351 icd->current_fmt = data_fmt; 337 /* buswidth may be further adjusted by the ici */
338 icd->buswidth = icd->current_fmt->depth;
352 icd->width = rect.width; 339 icd->width = rect.width;
353 icd->height = rect.height; 340 icd->height = rect.height;
354 icf->vb_vidq.field = f->fmt.pix.field; 341 icf->vb_vidq.field = f->fmt.pix.field;
355 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type) 342 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
356 dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", 343 dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
357 f->type); 344 f->type);
358 345
@@ -394,10 +381,9 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
394 f->fmt.pix.height = icd->height; 381 f->fmt.pix.height = icd->height;
395 f->fmt.pix.field = icf->vb_vidq.field; 382 f->fmt.pix.field = icf->vb_vidq.field;
396 f->fmt.pix.pixelformat = icd->current_fmt->fourcc; 383 f->fmt.pix.pixelformat = icd->current_fmt->fourcc;
397 f->fmt.pix.bytesperline = 384 f->fmt.pix.bytesperline = f->fmt.pix.width *
398 (f->fmt.pix.width * icd->current_fmt->depth) >> 3; 385 DIV_ROUND_UP(icd->current_fmt->depth, 8);
399 f->fmt.pix.sizeimage = 386 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
400 f->fmt.pix.height * f->fmt.pix.bytesperline;
401 dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n", 387 dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
402 icd->current_fmt->fourcc); 388 icd->current_fmt->fourcc);
403 return 0; 389 return 0;
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index ee0e6b4bed33..8e8fcb75dacb 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -105,6 +105,9 @@ extern void soc_camera_device_unregister(struct soc_camera_device *icd);
105extern int soc_camera_video_start(struct soc_camera_device *icd); 105extern int soc_camera_video_start(struct soc_camera_device *icd);
106extern void soc_camera_video_stop(struct soc_camera_device *icd); 106extern void soc_camera_video_stop(struct soc_camera_device *icd);
107 107
108extern const struct soc_camera_data_format *soc_camera_format_by_fourcc(
109 struct soc_camera_device *icd, unsigned int fourcc);
110
108struct soc_camera_data_format { 111struct soc_camera_data_format {
109 const char *name; 112 const char *name;
110 unsigned int depth; 113 unsigned int depth;