From ada365c021ff668eae8fa17042a39d33a4cdf4e1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 13 Mar 2009 10:08:20 +0100 Subject: soc-camera: separate S_FMT and S_CROP operations From: Guennadi Liakhovetski As host and camera drivers become more complex, differences between S_FMT and S_CROP functionality grow, this patch separates them. Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/mt9m001.c | 19 +++- drivers/media/video/mt9m111.c | 56 +++++++--- drivers/media/video/mt9t031.c | 84 ++++++++++------ drivers/media/video/mt9v022.c | 62 +++++++---- drivers/media/video/mx3_camera.c | 157 +++++++++++++++++----------- drivers/media/video/ov772x.c | 31 +++++- drivers/media/video/pxa_camera.c | 67 +++++++++--- drivers/media/video/sh_mobile_ceu_camera.c | 17 ++- drivers/media/video/soc_camera.c | 20 ++-- drivers/media/video/soc_camera_platform.c | 9 ++- drivers/media/video/tw9910.c | 45 +++++--- include/media/soc_camera.h | 6 +- 12 files changed, 381 insertions(+), 192 deletions(-) --- linux/drivers/media/video/soc_camera.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 356b77e10..4c2a784fb 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -418,9 +418,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, struct soc_camera_device *icd = icf->icd; struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); struct v4l2_pix_format *pix = &f->fmt.pix; - __u32 pixfmt = pix->pixelformat; int ret; - struct v4l2_rect rect; WARN_ON(priv != file->private_data); @@ -436,23 +434,19 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, goto unlock; } - rect.left = icd->x_current; - rect.top = icd->y_current; - rect.width = pix->width; - rect.height = pix->height; - ret = ici->ops->set_fmt(icd, pix->pixelformat, &rect); + ret = ici->ops->set_fmt(icd, f); if (ret < 0) { goto unlock; } else if (!icd->current_fmt || - icd->current_fmt->fourcc != pixfmt) { + icd->current_fmt->fourcc != pix->pixelformat) { dev_err(&ici->dev, "Host driver hasn't set up current format correctly!\n"); ret = -EINVAL; goto unlock; } - icd->width = rect.width; - icd->height = rect.height; + icd->width = f->fmt.pix.width; + icd->height = f->fmt.pix.height; icf->vb_vidq.field = pix->field; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", @@ -462,7 +456,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, icd->width, icd->height); /* set physical bus parameters */ - ret = ici->ops->set_bus_param(icd, pixfmt); + ret = ici->ops->set_bus_param(icd, pix->pixelformat); unlock: mutex_unlock(&icf->vb_vidq.vb_lock); @@ -686,7 +680,7 @@ static int soc_camera_s_crop(struct file *file, void *fh, /* Cropping is allowed during a running capture, guard consistency */ mutex_lock(&icf->vb_vidq.vb_lock); - ret = ici->ops->set_fmt(icd, 0, &a->c); + ret = ici->ops->set_crop(icd, &a->c); if (!ret) { icd->width = a->c.width; icd->height = a->c.height; @@ -919,6 +913,7 @@ int soc_camera_host_register(struct soc_camera_host *ici) if (!ici || !ici->ops || !ici->ops->try_fmt || !ici->ops->set_fmt || + !ici->ops->set_crop || !ici->ops->set_bus_param || !ici->ops->querycap || !ici->ops->init_videobuf || @@ -999,6 +994,7 @@ int soc_camera_device_register(struct soc_camera_device *icd) !icd->ops->release || !icd->ops->start_capture || !icd->ops->stop_capture || + !icd->ops->set_crop || !icd->ops->set_fmt || !icd->ops->try_fmt || !icd->ops->query_bus_param || -- cgit v1.2.3 From 7bc0a7a6ccbab2bff6c1ed73297765e4855db4be Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 13 Mar 2009 10:08:20 +0100 Subject: soc-camera: configure drivers with a default format on open From: Guennadi Liakhovetski Currently soc-camera doesn't set up any image format without an explicit S_FMT. It seems this should be supported, since, for example, capture-example.c from v4l2-apps by default doesn't issue an S_FMT. This patch configures a default image format on open(). Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/soc_camera.c | 100 ++++++++++++++++++++++++++------------ 1 files changed, 68 insertions(+), 32 deletions(-) --- linux/drivers/media/video/soc_camera.c | 100 ++++++++++++++++++++++----------- 1 file changed, 68 insertions(+), 32 deletions(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 4c2a784fb..10d8ecad1 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -31,6 +31,10 @@ #include #include "compat.h" +/* Default to VGA resolution */ +#define DEFAULT_WIDTH 640 +#define DEFAULT_HEIGHT 480 + static LIST_HEAD(hosts); static LIST_HEAD(devices); static DEFINE_MUTEX(list_lock); @@ -257,6 +261,44 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd) vfree(icd->user_formats); } +/* Called with .vb_lock held */ +static int soc_camera_set_fmt(struct soc_camera_file *icf, + struct v4l2_format *f) +{ + struct soc_camera_device *icd = icf->icd; + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + struct v4l2_pix_format *pix = &f->fmt.pix; + int ret; + + /* We always call try_fmt() before set_fmt() or set_crop() */ + ret = ici->ops->try_fmt(icd, f); + if (ret < 0) + return ret; + + ret = ici->ops->set_fmt(icd, f); + if (ret < 0) { + return ret; + } else if (!icd->current_fmt || + icd->current_fmt->fourcc != pix->pixelformat) { + dev_err(&ici->dev, + "Host driver hasn't set up current format correctly!\n"); + return -EINVAL; + } + + icd->width = pix->width; + icd->height = pix->height; + icf->vb_vidq.field = pix->field; + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", + f->type); + + dev_dbg(&icd->dev, "set width: %d height: %d\n", + icd->width, icd->height); + + /* set physical bus parameters */ + return ici->ops->set_bus_param(icd, pix->pixelformat); +} + static int soc_camera_open(struct file *file) { struct video_device *vdev; @@ -298,6 +340,15 @@ static int soc_camera_open(struct file *file) /* Now we really have to activate the camera */ if (icd->use_count == 1) { + struct v4l2_format f = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .fmt.pix = { + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + .field = V4L2_FIELD_ANY, + }, + }; + ret = soc_camera_init_user_formats(icd); if (ret < 0) goto eiufmt; @@ -306,6 +357,14 @@ static int soc_camera_open(struct file *file) dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); goto eiciadd; } + + f.fmt.pix.pixelformat = icd->current_fmt->fourcc; + f.fmt.pix.colorspace = icd->current_fmt->colorspace; + + /* Try to configure with default parameters */ + ret = soc_camera_set_fmt(icf, &f); + if (ret < 0) + goto esfmt; } mutex_unlock(&icd->video_lock); @@ -317,7 +376,12 @@ static int soc_camera_open(struct file *file) return 0; - /* First two errors are entered with the .video_lock held */ + /* + * First three errors are entered with the .video_lock held + * and use_count == 1 + */ +esfmt: + ici->ops->remove(icd); eiciadd: soc_camera_free_user_formats(icd); eiufmt: @@ -416,16 +480,10 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, { struct soc_camera_file *icf = file->private_data; struct soc_camera_device *icd = icf->icd; - struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); - struct v4l2_pix_format *pix = &f->fmt.pix; int ret; WARN_ON(priv != file->private_data); - ret = soc_camera_try_fmt_vid_cap(file, priv, f); - if (ret < 0) - return ret; - mutex_lock(&icf->vb_vidq.vb_lock); if (videobuf_queue_is_busy(&icf->vb_vidq)) { @@ -434,29 +492,7 @@ static int soc_camera_s_fmt_vid_cap(struct file *file, void *priv, goto unlock; } - ret = ici->ops->set_fmt(icd, f); - if (ret < 0) { - goto unlock; - } else if (!icd->current_fmt || - icd->current_fmt->fourcc != pix->pixelformat) { - dev_err(&ici->dev, - "Host driver hasn't set up current format correctly!\n"); - ret = -EINVAL; - goto unlock; - } - - icd->width = f->fmt.pix.width; - icd->height = f->fmt.pix.height; - icf->vb_vidq.field = pix->field; - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", - f->type); - - dev_dbg(&icd->dev, "set width: %d height: %d\n", - icd->width, icd->height); - - /* set physical bus parameters */ - ret = ici->ops->set_bus_param(icd, pix->pixelformat); + ret = soc_camera_set_fmt(icf, f); unlock: mutex_unlock(&icf->vb_vidq.vb_lock); @@ -643,8 +679,8 @@ static int soc_camera_cropcap(struct file *file, void *fh, a->bounds.height = icd->height_max; a->defrect.left = icd->x_min; a->defrect.top = icd->y_min; - a->defrect.width = 640; - a->defrect.height = 480; + a->defrect.width = DEFAULT_WIDTH; + a->defrect.height = DEFAULT_HEIGHT; a->pixelaspect.numerator = 1; a->pixelaspect.denominator = 1; -- cgit v1.2.3 From a00a0b74b7fe24e815f70f49ac8b8cc073cdad80 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 13 Mar 2009 10:08:20 +0100 Subject: soc-camera: configure drivers with a default format at probe time From: Guennadi Liakhovetski Currently soc-camera doesn't set up any image format without an explicit S_FMT. According to the API this should be supported, for example, capture-example.c from v4l2-apps by default doesn't issue an S_FMT. This patch moves negotiating of available host-camera format translations to probe() time, and restores the state from the last close() on the next open(). This is needed for some drivers, which power down or reset hardware after the last user closes the interface. This patch also has a nice side-effect of avoiding multiple allocation anf freeing of format translation tables. Signed-off-by: Guennadi Liakhovetski --- drivers/media/video/soc_camera.c | 39 ++++++++++++++++++++++--------------- include/media/soc_camera.h | 1 + 2 files changed, 24 insertions(+), 16 deletions(-) --- linux/drivers/media/video/soc_camera.c | 39 ++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'linux/drivers/media/video/soc_camera.c') diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index 10d8ecad1..da6d224eb 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -287,7 +287,9 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf, icd->width = pix->width; icd->height = pix->height; - icf->vb_vidq.field = pix->field; + icf->vb_vidq.field = + icd->field = pix->field; + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", f->type); @@ -340,27 +342,24 @@ static int soc_camera_open(struct file *file) /* Now we really have to activate the camera */ if (icd->use_count == 1) { + /* Restore parameters before the last close() per V4L2 API */ struct v4l2_format f = { .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, .fmt.pix = { - .width = DEFAULT_WIDTH, - .height = DEFAULT_HEIGHT, - .field = V4L2_FIELD_ANY, + .width = icd->width, + .height = icd->height, + .field = icd->field, + .pixelformat = icd->current_fmt->fourcc, + .colorspace = icd->current_fmt->colorspace, }, }; - ret = soc_camera_init_user_formats(icd); - if (ret < 0) - goto eiufmt; ret = ici->ops->add(icd); if (ret < 0) { dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret); goto eiciadd; } - f.fmt.pix.pixelformat = icd->current_fmt->fourcc; - f.fmt.pix.colorspace = icd->current_fmt->colorspace; - /* Try to configure with default parameters */ ret = soc_camera_set_fmt(icf, &f); if (ret < 0) @@ -383,8 +382,6 @@ static int soc_camera_open(struct file *file) esfmt: ici->ops->remove(icd); eiciadd: - soc_camera_free_user_formats(icd); -eiufmt: icd->use_count--; mutex_unlock(&icd->video_lock); module_put(ici->ops->owner); @@ -404,10 +401,9 @@ static int soc_camera_close(struct file *file) mutex_lock(&icd->video_lock); icd->use_count--; - if (!icd->use_count) { + if (!icd->use_count) ici->ops->remove(icd); - soc_camera_free_user_formats(icd); - } + mutex_unlock(&icd->video_lock); module_put(icd->ops->owner); @@ -875,9 +871,18 @@ static int soc_camera_probe(struct device *dev) qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); icd->exposure = qctrl ? qctrl->default_value : (unsigned short)~0; + + ret = soc_camera_init_user_formats(icd); + if (ret < 0) + goto eiufmt; + + icd->height = DEFAULT_HEIGHT; + icd->width = DEFAULT_WIDTH; + icd->field = V4L2_FIELD_ANY; } - ici->ops->remove(icd); +eiufmt: + ici->ops->remove(icd); eiadd: mutex_unlock(&icd->video_lock); module_put(ici->ops->owner); @@ -896,6 +901,8 @@ static int soc_camera_remove(struct device *dev) if (icd->ops->remove) icd->ops->remove(icd); + soc_camera_free_user_formats(icd); + return 0; } -- cgit v1.2.3