diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2009-03-13 05:08:20 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:43:21 -0400 |
commit | 09e231b35173313cd92e27532e5028f2042dcee4 (patch) | |
tree | 3ecda063aa52f954d2f797921bdce131d7f1cc28 /drivers/media/video/mx3_camera.c | |
parent | 1cd3c0fa927084549005fc22e54d99684b314f14 (diff) |
V4L/DVB (11024): soc-camera: separate S_FMT and S_CROP operations
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 <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/mx3_camera.c')
-rw-r--r-- | drivers/media/video/mx3_camera.c | 157 |
1 files changed, 97 insertions, 60 deletions
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c index f525dc48f6ca..70629e172e65 100644 --- a/drivers/media/video/mx3_camera.c +++ b/drivers/media/video/mx3_camera.c | |||
@@ -544,16 +544,14 @@ static void mx3_camera_remove_device(struct soc_camera_device *icd) | |||
544 | } | 544 | } |
545 | 545 | ||
546 | static bool channel_change_requested(struct soc_camera_device *icd, | 546 | static bool channel_change_requested(struct soc_camera_device *icd, |
547 | const struct soc_camera_format_xlate *xlate, | 547 | struct v4l2_rect *rect) |
548 | __u32 pixfmt, struct v4l2_rect *rect) | ||
549 | { | 548 | { |
550 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | 549 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); |
551 | struct mx3_camera_dev *mx3_cam = ici->priv; | 550 | struct mx3_camera_dev *mx3_cam = ici->priv; |
552 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; | 551 | struct idmac_channel *ichan = mx3_cam->idmac_channel[0]; |
553 | 552 | ||
554 | /* So far only one configuration is supported */ | 553 | /* Do buffers have to be re-allocated or channel re-configured? */ |
555 | return pixfmt || (ichan && rect->width * rect->height > | 554 | return ichan && rect->width * rect->height > icd->width * icd->height; |
556 | icd->width * icd->height); | ||
557 | } | 555 | } |
558 | 556 | ||
559 | static int test_platform_param(struct mx3_camera_dev *mx3_cam, | 557 | static int test_platform_param(struct mx3_camera_dev *mx3_cam, |
@@ -733,61 +731,10 @@ passthrough: | |||
733 | return formats; | 731 | return formats; |
734 | } | 732 | } |
735 | 733 | ||
736 | static int mx3_camera_set_fmt(struct soc_camera_device *icd, | 734 | static void configure_geometry(struct mx3_camera_dev *mx3_cam, |
737 | __u32 pixfmt, struct v4l2_rect *rect) | 735 | struct v4l2_rect *rect) |
738 | { | 736 | { |
739 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
740 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
741 | const struct soc_camera_format_xlate *xlate; | ||
742 | u32 ctrl, width_field, height_field; | 737 | u32 ctrl, width_field, height_field; |
743 | int ret; | ||
744 | |||
745 | xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); | ||
746 | if (pixfmt && !xlate) { | ||
747 | dev_warn(&ici->dev, "Format %x not found\n", pixfmt); | ||
748 | return -EINVAL; | ||
749 | } | ||
750 | |||
751 | /* | ||
752 | * We now know pixel formats and can decide upon DMA-channel(s) | ||
753 | * So far only direct camera-to-memory is supported | ||
754 | */ | ||
755 | if (channel_change_requested(icd, xlate, pixfmt, rect)) { | ||
756 | dma_cap_mask_t mask; | ||
757 | struct dma_chan *chan; | ||
758 | struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; | ||
759 | /* We have to use IDMAC_IC_7 for Bayer / generic data */ | ||
760 | struct dma_chan_request rq = {.mx3_cam = mx3_cam, | ||
761 | .id = IDMAC_IC_7}; | ||
762 | |||
763 | if (*ichan) { | ||
764 | struct videobuf_buffer *vb, *_vb; | ||
765 | dma_release_channel(&(*ichan)->dma_chan); | ||
766 | *ichan = NULL; | ||
767 | mx3_cam->active = NULL; | ||
768 | list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) { | ||
769 | list_del_init(&vb->queue); | ||
770 | vb->state = VIDEOBUF_ERROR; | ||
771 | wake_up(&vb->done); | ||
772 | } | ||
773 | } | ||
774 | |||
775 | dma_cap_zero(mask); | ||
776 | dma_cap_set(DMA_SLAVE, mask); | ||
777 | dma_cap_set(DMA_PRIVATE, mask); | ||
778 | chan = dma_request_channel(mask, chan_filter, &rq); | ||
779 | if (!chan) | ||
780 | return -EBUSY; | ||
781 | |||
782 | *ichan = to_idmac_chan(chan); | ||
783 | (*ichan)->client = mx3_cam; | ||
784 | } | ||
785 | |||
786 | /* | ||
787 | * Might have to perform a complete interface initialisation like in | ||
788 | * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider | ||
789 | * mxc_v4l2_s_fmt() | ||
790 | */ | ||
791 | 738 | ||
792 | /* Setup frame size - this cannot be changed on-the-fly... */ | 739 | /* Setup frame size - this cannot be changed on-the-fly... */ |
793 | width_field = rect->width - 1; | 740 | width_field = rect->width - 1; |
@@ -808,9 +755,98 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, | |||
808 | * No need to free resources here if we fail, we'll see if we need to | 755 | * No need to free resources here if we fail, we'll see if we need to |
809 | * do this next time we are called | 756 | * do this next time we are called |
810 | */ | 757 | */ |
758 | } | ||
759 | |||
760 | static int acquire_dma_channel(struct mx3_camera_dev *mx3_cam) | ||
761 | { | ||
762 | dma_cap_mask_t mask; | ||
763 | struct dma_chan *chan; | ||
764 | struct idmac_channel **ichan = &mx3_cam->idmac_channel[0]; | ||
765 | /* We have to use IDMAC_IC_7 for Bayer / generic data */ | ||
766 | struct dma_chan_request rq = {.mx3_cam = mx3_cam, | ||
767 | .id = IDMAC_IC_7}; | ||
768 | |||
769 | if (*ichan) { | ||
770 | struct videobuf_buffer *vb, *_vb; | ||
771 | dma_release_channel(&(*ichan)->dma_chan); | ||
772 | *ichan = NULL; | ||
773 | mx3_cam->active = NULL; | ||
774 | list_for_each_entry_safe(vb, _vb, &mx3_cam->capture, queue) { | ||
775 | list_del_init(&vb->queue); | ||
776 | vb->state = VIDEOBUF_ERROR; | ||
777 | wake_up(&vb->done); | ||
778 | } | ||
779 | } | ||
780 | |||
781 | dma_cap_zero(mask); | ||
782 | dma_cap_set(DMA_SLAVE, mask); | ||
783 | dma_cap_set(DMA_PRIVATE, mask); | ||
784 | chan = dma_request_channel(mask, chan_filter, &rq); | ||
785 | if (!chan) | ||
786 | return -EBUSY; | ||
787 | |||
788 | *ichan = to_idmac_chan(chan); | ||
789 | (*ichan)->client = mx3_cam; | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | static int mx3_camera_set_crop(struct soc_camera_device *icd, | ||
795 | struct v4l2_rect *rect) | ||
796 | { | ||
797 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
798 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
799 | |||
800 | /* | ||
801 | * We now know pixel formats and can decide upon DMA-channel(s) | ||
802 | * So far only direct camera-to-memory is supported | ||
803 | */ | ||
804 | if (channel_change_requested(icd, rect)) { | ||
805 | int ret = acquire_dma_channel(mx3_cam); | ||
806 | if (ret < 0) | ||
807 | return ret; | ||
808 | } | ||
809 | |||
810 | configure_geometry(mx3_cam, rect); | ||
811 | |||
812 | return icd->ops->set_crop(icd, rect); | ||
813 | } | ||
814 | |||
815 | static int mx3_camera_set_fmt(struct soc_camera_device *icd, | ||
816 | struct v4l2_format *f) | ||
817 | { | ||
818 | struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); | ||
819 | struct mx3_camera_dev *mx3_cam = ici->priv; | ||
820 | const struct soc_camera_format_xlate *xlate; | ||
821 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
822 | struct v4l2_rect rect = { | ||
823 | .left = icd->x_current, | ||
824 | .top = icd->y_current, | ||
825 | .width = pix->width, | ||
826 | .height = pix->height, | ||
827 | }; | ||
828 | int ret; | ||
829 | |||
830 | xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); | ||
831 | if (!xlate) { | ||
832 | dev_warn(&ici->dev, "Format %x not found\n", pix->pixelformat); | ||
833 | return -EINVAL; | ||
834 | } | ||
835 | |||
836 | ret = acquire_dma_channel(mx3_cam); | ||
837 | if (ret < 0) | ||
838 | return ret; | ||
839 | |||
840 | /* | ||
841 | * Might have to perform a complete interface initialisation like in | ||
842 | * ipu_csi_init_interface() in mxc_v4l2_s_param(). Also consider | ||
843 | * mxc_v4l2_s_fmt() | ||
844 | */ | ||
845 | |||
846 | configure_geometry(mx3_cam, &rect); | ||
811 | 847 | ||
812 | ret = icd->ops->set_fmt(icd, pixfmt ? xlate->cam_fmt->fourcc : 0, rect); | 848 | ret = icd->ops->set_fmt(icd, f); |
813 | if (pixfmt && !ret) { | 849 | if (!ret) { |
814 | icd->buswidth = xlate->buswidth; | 850 | icd->buswidth = xlate->buswidth; |
815 | icd->current_fmt = xlate->host_fmt; | 851 | icd->current_fmt = xlate->host_fmt; |
816 | } | 852 | } |
@@ -1031,6 +1067,7 @@ static struct soc_camera_host_ops mx3_soc_camera_host_ops = { | |||
1031 | .suspend = mx3_camera_suspend, | 1067 | .suspend = mx3_camera_suspend, |
1032 | .resume = mx3_camera_resume, | 1068 | .resume = mx3_camera_resume, |
1033 | #endif | 1069 | #endif |
1070 | .set_crop = mx3_camera_set_crop, | ||
1034 | .set_fmt = mx3_camera_set_fmt, | 1071 | .set_fmt = mx3_camera_set_fmt, |
1035 | .try_fmt = mx3_camera_try_fmt, | 1072 | .try_fmt = mx3_camera_try_fmt, |
1036 | .get_formats = mx3_camera_get_formats, | 1073 | .get_formats = mx3_camera_get_formats, |