aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/soc_camera.c
diff options
context:
space:
mode:
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 c6cccdf8daf5..86e0648f65a0 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: