diff options
author | Guennadi Liakhovetski <lyakh@axis700.grange> | 2008-12-01 07:44:59 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 06:38:22 -0500 |
commit | 25c4d74ea6f07f2aaa3df537619680ba967043f5 (patch) | |
tree | 58a33458a15e9720adc027ef443828550ba1f0eb /drivers/media/video/soc_camera.c | |
parent | abe4c4710386a4859dae9193bfc9a1f0e3c60db4 (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>
Diffstat (limited to 'drivers/media/video/soc_camera.c')
-rw-r--r-- | drivers/media/video/soc_camera.c | 58 |
1 files changed, 22 insertions, 36 deletions
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); | |||
35 | static DEFINE_MUTEX(list_lock); | 35 | static DEFINE_MUTEX(list_lock); |
36 | static DEFINE_MUTEX(video_lock); | 36 | static DEFINE_MUTEX(video_lock); |
37 | 37 | ||
38 | const static struct soc_camera_data_format *format_by_fourcc( | 38 | const 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 | } |
48 | EXPORT_SYMBOL(soc_camera_format_by_fourcc); | ||
48 | 49 | ||
49 | static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, | 50 | static 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; |