diff options
Diffstat (limited to 'drivers/media/video/soc_camera.c')
-rw-r--r-- | drivers/media/video/soc_camera.c | 130 |
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 */ |
282 | static int soc_camera_set_fmt(struct soc_camera_file *icf, | 285 | static 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 | ||
738 | static int soc_camera_g_crop(struct file *file, void *fh, | 736 | static 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, ¤t_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 | |||
804 | unlock: | ||
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 | ||
1098 | static 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 | |||
1105 | static 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 | |||
1111 | static 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 | |||
1106 | int soc_camera_host_register(struct soc_camera_host *ici) | 1117 | int 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 | ||
1326 | escdevreg: | 1346 | escdevreg: |