aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/soc_camera.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2009-08-25 10:50:46 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-18 23:19:17 -0400
commit6a6c8786725c0b3d143674effa8b772f47b1c189 (patch)
tree8bb76c5dcbd579f13e876bd1a0bb56bee4bcebdd /drivers/media/video/soc_camera.c
parent0166b74374cae3fa8bff0caef726a3d960a9a50a (diff)
V4L/DVB (12534): soc-camera: V4L2 API compliant scaling (S_FMT) and cropping (S_CROP)
The initial soc-camera scaling and cropping implementation turned out to be incompliant with the V4L2 API, e.g., it expected the user to specify cropping in output window pixels, instead of input window pixels. This patch converts the soc-camera core and all drivers to comply with the standard. 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.c130
1 files changed, 75 insertions, 55 deletions
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index c6cccdf8daf..86e0648f65a 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -278,6 +278,9 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
278 icd->user_formats = NULL; 278 icd->user_formats = NULL;
279} 279}
280 280
281#define pixfmtstr(x) (x) & 0xff, ((x) >> 8) & 0xff, ((x) >> 16) & 0xff, \
282 ((x) >> 24) & 0xff
283
281/* Called with .vb_lock held */ 284/* Called with .vb_lock held */
282static int soc_camera_set_fmt(struct soc_camera_file *icf, 285static int soc_camera_set_fmt(struct soc_camera_file *icf,
283 struct v4l2_format *f) 286 struct v4l2_format *f)
@@ -287,6 +290,9 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
287 struct v4l2_pix_format *pix = &f->fmt.pix; 290 struct v4l2_pix_format *pix = &f->fmt.pix;
288 int ret; 291 int ret;
289 292
293 dev_dbg(&icd->dev, "S_FMT(%c%c%c%c, %ux%u)\n",
294 pixfmtstr(pix->pixelformat), pix->width, pix->height);
295
290 /* We always call try_fmt() before set_fmt() or set_crop() */ 296 /* We always call try_fmt() before set_fmt() or set_crop() */
291 ret = ici->ops->try_fmt(icd, f); 297 ret = ici->ops->try_fmt(icd, f);
292 if (ret < 0) 298 if (ret < 0)
@@ -302,17 +308,17 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
302 return -EINVAL; 308 return -EINVAL;
303 } 309 }
304 310
305 icd->rect_current.width = pix->width; 311 icd->user_width = pix->width;
306 icd->rect_current.height = pix->height; 312 icd->user_height = pix->height;
307 icf->vb_vidq.field = 313 icf->vb_vidq.field =
308 icd->field = pix->field; 314 icd->field = pix->field;
309 315
310 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 316 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
311 dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n", 317 dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
312 f->type); 318 f->type);
313 319
314 dev_dbg(&icd->dev, "set width: %d height: %d\n", 320 dev_dbg(&icd->dev, "set width: %d height: %d\n",
315 icd->rect_current.width, icd->rect_current.height); 321 icd->user_width, icd->user_height);
316 322
317 /* set physical bus parameters */ 323 /* set physical bus parameters */
318 return ici->ops->set_bus_param(icd, pix->pixelformat); 324 return ici->ops->set_bus_param(icd, pix->pixelformat);
@@ -355,8 +361,8 @@ static int soc_camera_open(struct file *file)
355 struct v4l2_format f = { 361 struct v4l2_format f = {
356 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, 362 .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
357 .fmt.pix = { 363 .fmt.pix = {
358 .width = icd->rect_current.width, 364 .width = icd->user_width,
359 .height = icd->rect_current.height, 365 .height = icd->user_height,
360 .field = icd->field, 366 .field = icd->field,
361 .pixelformat = icd->current_fmt->fourcc, 367 .pixelformat = icd->current_fmt->fourcc,
362 .colorspace = icd->current_fmt->colorspace, 368 .colorspace = icd->current_fmt->colorspace,
@@ -557,8 +563,8 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
557 563
558 WARN_ON(priv != file->private_data); 564 WARN_ON(priv != file->private_data);
559 565
560 pix->width = icd->rect_current.width; 566 pix->width = icd->user_width;
561 pix->height = icd->rect_current.height; 567 pix->height = icd->user_height;
562 pix->field = icf->vb_vidq.field; 568 pix->field = icf->vb_vidq.field;
563 pix->pixelformat = icd->current_fmt->fourcc; 569 pix->pixelformat = icd->current_fmt->fourcc;
564 pix->bytesperline = pix->width * 570 pix->bytesperline = pix->width *
@@ -722,17 +728,9 @@ static int soc_camera_cropcap(struct file *file, void *fh,
722{ 728{
723 struct soc_camera_file *icf = file->private_data; 729 struct soc_camera_file *icf = file->private_data;
724 struct soc_camera_device *icd = icf->icd; 730 struct soc_camera_device *icd = icf->icd;
731 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
725 732
726 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 733 return ici->ops->cropcap(icd, a);
727 a->bounds = icd->rect_max;
728 a->defrect.left = icd->rect_max.left;
729 a->defrect.top = icd->rect_max.top;
730 a->defrect.width = DEFAULT_WIDTH;
731 a->defrect.height = DEFAULT_HEIGHT;
732 a->pixelaspect.numerator = 1;
733 a->pixelaspect.denominator = 1;
734
735 return 0;
736} 734}
737 735
738static int soc_camera_g_crop(struct file *file, void *fh, 736static int soc_camera_g_crop(struct file *file, void *fh,
@@ -740,11 +738,14 @@ static int soc_camera_g_crop(struct file *file, void *fh,
740{ 738{
741 struct soc_camera_file *icf = file->private_data; 739 struct soc_camera_file *icf = file->private_data;
742 struct soc_camera_device *icd = icf->icd; 740 struct soc_camera_device *icd = icf->icd;
741 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
742 int ret;
743 743
744 a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 744 mutex_lock(&icf->vb_vidq.vb_lock);
745 a->c = icd->rect_current; 745 ret = ici->ops->get_crop(icd, a);
746 mutex_unlock(&icf->vb_vidq.vb_lock);
746 747
747 return 0; 748 return ret;
748} 749}
749 750
750/* 751/*
@@ -759,49 +760,33 @@ static int soc_camera_s_crop(struct file *file, void *fh,
759 struct soc_camera_file *icf = file->private_data; 760 struct soc_camera_file *icf = file->private_data;
760 struct soc_camera_device *icd = icf->icd; 761 struct soc_camera_device *icd = icf->icd;
761 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); 762 struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
762 struct v4l2_rect rect = a->c; 763 struct v4l2_rect *rect = &a->c;
764 struct v4l2_crop current_crop;
763 int ret; 765 int ret;
764 766
765 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 767 if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
766 return -EINVAL; 768 return -EINVAL;
767 769
770 dev_dbg(&icd->dev, "S_CROP(%ux%u@%u:%u)\n",
771 rect->width, rect->height, rect->left, rect->top);
772
768 /* Cropping is allowed during a running capture, guard consistency */ 773 /* Cropping is allowed during a running capture, guard consistency */
769 mutex_lock(&icf->vb_vidq.vb_lock); 774 mutex_lock(&icf->vb_vidq.vb_lock);
770 775
776 /* If get_crop fails, we'll let host and / or client drivers decide */
777 ret = ici->ops->get_crop(icd, &current_crop);
778
771 /* Prohibit window size change with initialised buffers */ 779 /* Prohibit window size change with initialised buffers */
772 if (icf->vb_vidq.bufs[0] && (rect.width != icd->rect_current.width || 780 if (icf->vb_vidq.bufs[0] && !ret &&
773 rect.height != icd->rect_current.height)) { 781 (a->c.width != current_crop.c.width ||
782 a->c.height != current_crop.c.height)) {
774 dev_err(&icd->dev, 783 dev_err(&icd->dev,
775 "S_CROP denied: queue initialised and sizes differ\n"); 784 "S_CROP denied: queue initialised and sizes differ\n");
776 ret = -EBUSY; 785 ret = -EBUSY;
777 goto unlock; 786 } else {
787 ret = ici->ops->set_crop(icd, a);
778 } 788 }
779 789
780 if (rect.width > icd->rect_max.width)
781 rect.width = icd->rect_max.width;
782
783 if (rect.width < icd->width_min)
784 rect.width = icd->width_min;
785
786 if (rect.height > icd->rect_max.height)
787 rect.height = icd->rect_max.height;
788
789 if (rect.height < icd->height_min)
790 rect.height = icd->height_min;
791
792 if (rect.width + rect.left > icd->rect_max.width + icd->rect_max.left)
793 rect.left = icd->rect_max.width + icd->rect_max.left -
794 rect.width;
795
796 if (rect.height + rect.top > icd->rect_max.height + icd->rect_max.top)
797 rect.top = icd->rect_max.height + icd->rect_max.top -
798 rect.height;
799
800 ret = ici->ops->set_crop(icd, a);
801 if (!ret)
802 icd->rect_current = rect;
803
804unlock:
805 mutex_unlock(&icf->vb_vidq.vb_lock); 790 mutex_unlock(&icf->vb_vidq.vb_lock);
806 791
807 return ret; 792 return ret;
@@ -926,6 +911,8 @@ static int soc_camera_probe(struct device *dev)
926 struct soc_camera_host *ici = to_soc_camera_host(dev->parent); 911 struct soc_camera_host *ici = to_soc_camera_host(dev->parent);
927 struct soc_camera_link *icl = to_soc_camera_link(icd); 912 struct soc_camera_link *icl = to_soc_camera_link(icd);
928 struct device *control = NULL; 913 struct device *control = NULL;
914 struct v4l2_subdev *sd;
915 struct v4l2_format f = {.type = V4L2_BUF_TYPE_VIDEO_CAPTURE};
929 int ret; 916 int ret;
930 917
931 dev_info(dev, "Probing %s\n", dev_name(dev)); 918 dev_info(dev, "Probing %s\n", dev_name(dev));
@@ -982,7 +969,6 @@ static int soc_camera_probe(struct device *dev)
982 if (ret < 0) 969 if (ret < 0)
983 goto eiufmt; 970 goto eiufmt;
984 971
985 icd->rect_current = icd->rect_max;
986 icd->field = V4L2_FIELD_ANY; 972 icd->field = V4L2_FIELD_ANY;
987 973
988 /* ..._video_start() will create a device node, so we have to protect */ 974 /* ..._video_start() will create a device node, so we have to protect */
@@ -992,9 +978,15 @@ static int soc_camera_probe(struct device *dev)
992 if (ret < 0) 978 if (ret < 0)
993 goto evidstart; 979 goto evidstart;
994 980
981 /* Try to improve our guess of a reasonable window format */
982 sd = soc_camera_to_subdev(icd);
983 if (!v4l2_subdev_call(sd, video, g_fmt, &f)) {
984 icd->user_width = f.fmt.pix.width;
985 icd->user_height = f.fmt.pix.height;
986 }
987
995 /* Do we have to sysfs_remove_link() before device_unregister()? */ 988 /* Do we have to sysfs_remove_link() before device_unregister()? */
996 if (to_soc_camera_control(icd) && 989 if (sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj,
997 sysfs_create_link(&icd->dev.kobj, &to_soc_camera_control(icd)->kobj,
998 "control")) 990 "control"))
999 dev_warn(&icd->dev, "Failed creating the control symlink\n"); 991 dev_warn(&icd->dev, "Failed creating the control symlink\n");
1000 992
@@ -1103,6 +1095,25 @@ static void dummy_release(struct device *dev)
1103{ 1095{
1104} 1096}
1105 1097
1098static int default_cropcap(struct soc_camera_device *icd,
1099 struct v4l2_cropcap *a)
1100{
1101 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
1102 return v4l2_subdev_call(sd, video, cropcap, a);
1103}
1104
1105static int default_g_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
1106{
1107 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
1108 return v4l2_subdev_call(sd, video, g_crop, a);
1109}
1110
1111static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
1112{
1113 struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
1114 return v4l2_subdev_call(sd, video, s_crop, a);
1115}
1116
1106int soc_camera_host_register(struct soc_camera_host *ici) 1117int soc_camera_host_register(struct soc_camera_host *ici)
1107{ 1118{
1108 struct soc_camera_host *ix; 1119 struct soc_camera_host *ix;
@@ -1111,7 +1122,6 @@ int soc_camera_host_register(struct soc_camera_host *ici)
1111 if (!ici || !ici->ops || 1122 if (!ici || !ici->ops ||
1112 !ici->ops->try_fmt || 1123 !ici->ops->try_fmt ||
1113 !ici->ops->set_fmt || 1124 !ici->ops->set_fmt ||
1114 !ici->ops->set_crop ||
1115 !ici->ops->set_bus_param || 1125 !ici->ops->set_bus_param ||
1116 !ici->ops->querycap || 1126 !ici->ops->querycap ||
1117 !ici->ops->init_videobuf || 1127 !ici->ops->init_videobuf ||
@@ -1122,6 +1132,13 @@ int soc_camera_host_register(struct soc_camera_host *ici)
1122 !ici->v4l2_dev.dev) 1132 !ici->v4l2_dev.dev)
1123 return -EINVAL; 1133 return -EINVAL;
1124 1134
1135 if (!ici->ops->set_crop)
1136 ici->ops->set_crop = default_s_crop;
1137 if (!ici->ops->get_crop)
1138 ici->ops->get_crop = default_g_crop;
1139 if (!ici->ops->cropcap)
1140 ici->ops->cropcap = default_cropcap;
1141
1125 mutex_lock(&list_lock); 1142 mutex_lock(&list_lock);
1126 list_for_each_entry(ix, &hosts, list) { 1143 list_for_each_entry(ix, &hosts, list) {
1127 if (ix->nr == ici->nr) { 1144 if (ix->nr == ici->nr) {
@@ -1321,6 +1338,9 @@ static int __devinit soc_camera_pdrv_probe(struct platform_device *pdev)
1321 if (ret < 0) 1338 if (ret < 0)
1322 goto escdevreg; 1339 goto escdevreg;
1323 1340
1341 icd->user_width = DEFAULT_WIDTH;
1342 icd->user_height = DEFAULT_HEIGHT;
1343
1324 return 0; 1344 return 0;
1325 1345
1326escdevreg: 1346escdevreg: