diff options
author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2010-01-23 04:30:20 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-02-26 13:11:04 -0500 |
commit | 59529081e092506edb81a42d914e2d0522f65ca7 (patch) | |
tree | 237632dbcf3c1da3443b316a3b66969c9db8514a | |
parent | 8a4e76c14cbe0609fdb5c558f867fe7c556bb1c7 (diff) |
V4L/DVB: uvcvideo: Cache control min, max, res and def query results
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/media/video/uvc/uvc_ctrl.c | 120 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvcvideo.h | 3 |
2 files changed, 74 insertions, 49 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index f4e5ba260968..5ff501390842 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c | |||
@@ -23,9 +23,13 @@ | |||
23 | 23 | ||
24 | #include "uvcvideo.h" | 24 | #include "uvcvideo.h" |
25 | 25 | ||
26 | #define UVC_CTRL_NDATA 2 | ||
27 | #define UVC_CTRL_DATA_CURRENT 0 | 26 | #define UVC_CTRL_DATA_CURRENT 0 |
28 | #define UVC_CTRL_DATA_BACKUP 1 | 27 | #define UVC_CTRL_DATA_BACKUP 1 |
28 | #define UVC_CTRL_DATA_MIN 2 | ||
29 | #define UVC_CTRL_DATA_MAX 3 | ||
30 | #define UVC_CTRL_DATA_RES 4 | ||
31 | #define UVC_CTRL_DATA_DEF 5 | ||
32 | #define UVC_CTRL_DATA_LAST 6 | ||
29 | 33 | ||
30 | /* ------------------------------------------------------------------------ | 34 | /* ------------------------------------------------------------------------ |
31 | * Controls | 35 | * Controls |
@@ -755,6 +759,49 @@ struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, | |||
755 | return ctrl; | 759 | return ctrl; |
756 | } | 760 | } |
757 | 761 | ||
762 | static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain, | ||
763 | struct uvc_control *ctrl) | ||
764 | { | ||
765 | int ret; | ||
766 | |||
767 | if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { | ||
768 | ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id, | ||
769 | chain->dev->intfnum, ctrl->info->selector, | ||
770 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF), | ||
771 | ctrl->info->size); | ||
772 | if (ret < 0) | ||
773 | return ret; | ||
774 | } | ||
775 | |||
776 | if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { | ||
777 | ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id, | ||
778 | chain->dev->intfnum, ctrl->info->selector, | ||
779 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN), | ||
780 | ctrl->info->size); | ||
781 | if (ret < 0) | ||
782 | return ret; | ||
783 | } | ||
784 | if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { | ||
785 | ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id, | ||
786 | chain->dev->intfnum, ctrl->info->selector, | ||
787 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX), | ||
788 | ctrl->info->size); | ||
789 | if (ret < 0) | ||
790 | return ret; | ||
791 | } | ||
792 | if (ctrl->info->flags & UVC_CONTROL_GET_RES) { | ||
793 | ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id, | ||
794 | chain->dev->intfnum, ctrl->info->selector, | ||
795 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), | ||
796 | ctrl->info->size); | ||
797 | if (ret < 0) | ||
798 | return ret; | ||
799 | } | ||
800 | |||
801 | ctrl->cached = 1; | ||
802 | return 0; | ||
803 | } | ||
804 | |||
758 | int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, | 805 | int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, |
759 | struct v4l2_queryctrl *v4l2_ctrl) | 806 | struct v4l2_queryctrl *v4l2_ctrl) |
760 | { | 807 | { |
@@ -762,17 +809,12 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, | |||
762 | struct uvc_control_mapping *mapping; | 809 | struct uvc_control_mapping *mapping; |
763 | struct uvc_menu_info *menu; | 810 | struct uvc_menu_info *menu; |
764 | unsigned int i; | 811 | unsigned int i; |
765 | __u8 *data; | ||
766 | int ret; | 812 | int ret; |
767 | 813 | ||
768 | ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping); | 814 | ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping); |
769 | if (ctrl == NULL) | 815 | if (ctrl == NULL) |
770 | return -EINVAL; | 816 | return -EINVAL; |
771 | 817 | ||
772 | data = kmalloc(ctrl->info->size, GFP_KERNEL); | ||
773 | if (data == NULL) | ||
774 | return -ENOMEM; | ||
775 | |||
776 | memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); | 818 | memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); |
777 | v4l2_ctrl->id = mapping->id; | 819 | v4l2_ctrl->id = mapping->id; |
778 | v4l2_ctrl->type = mapping->v4l2_type; | 820 | v4l2_ctrl->type = mapping->v4l2_type; |
@@ -782,14 +824,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, | |||
782 | if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR)) | 824 | if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR)) |
783 | v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; | 825 | v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
784 | 826 | ||
785 | if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { | 827 | if (!ctrl->cached) { |
786 | ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id, | 828 | ret = uvc_ctrl_populate_cache(chain, ctrl); |
787 | chain->dev->intfnum, ctrl->info->selector, | ||
788 | data, ctrl->info->size); | ||
789 | if (ret < 0) | 829 | if (ret < 0) |
790 | goto out; | 830 | return ret; |
791 | v4l2_ctrl->default_value = | 831 | } |
792 | mapping->get(mapping, UVC_GET_DEF, data); | 832 | |
833 | if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { | ||
834 | v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF, | ||
835 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF)); | ||
793 | } | 836 | } |
794 | 837 | ||
795 | switch (mapping->v4l2_type) { | 838 | switch (mapping->v4l2_type) { |
@@ -806,56 +849,37 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, | |||
806 | } | 849 | } |
807 | } | 850 | } |
808 | 851 | ||
809 | ret = 0; | 852 | return 0; |
810 | goto out; | ||
811 | 853 | ||
812 | case V4L2_CTRL_TYPE_BOOLEAN: | 854 | case V4L2_CTRL_TYPE_BOOLEAN: |
813 | v4l2_ctrl->minimum = 0; | 855 | v4l2_ctrl->minimum = 0; |
814 | v4l2_ctrl->maximum = 1; | 856 | v4l2_ctrl->maximum = 1; |
815 | v4l2_ctrl->step = 1; | 857 | v4l2_ctrl->step = 1; |
816 | ret = 0; | 858 | return 0; |
817 | goto out; | ||
818 | 859 | ||
819 | case V4L2_CTRL_TYPE_BUTTON: | 860 | case V4L2_CTRL_TYPE_BUTTON: |
820 | v4l2_ctrl->minimum = 0; | 861 | v4l2_ctrl->minimum = 0; |
821 | v4l2_ctrl->maximum = 0; | 862 | v4l2_ctrl->maximum = 0; |
822 | v4l2_ctrl->step = 0; | 863 | v4l2_ctrl->step = 0; |
823 | ret = 0; | 864 | return 0; |
824 | goto out; | ||
825 | 865 | ||
826 | default: | 866 | default: |
827 | break; | 867 | break; |
828 | } | 868 | } |
829 | 869 | ||
830 | if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { | 870 | if (ctrl->info->flags & UVC_CONTROL_GET_MIN) |
831 | ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id, | 871 | v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, |
832 | chain->dev->intfnum, ctrl->info->selector, | 872 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN)); |
833 | data, ctrl->info->size); | ||
834 | if (ret < 0) | ||
835 | goto out; | ||
836 | v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data); | ||
837 | } | ||
838 | if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { | ||
839 | ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id, | ||
840 | chain->dev->intfnum, ctrl->info->selector, | ||
841 | data, ctrl->info->size); | ||
842 | if (ret < 0) | ||
843 | goto out; | ||
844 | v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data); | ||
845 | } | ||
846 | if (ctrl->info->flags & UVC_CONTROL_GET_RES) { | ||
847 | ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id, | ||
848 | chain->dev->intfnum, ctrl->info->selector, | ||
849 | data, ctrl->info->size); | ||
850 | if (ret < 0) | ||
851 | goto out; | ||
852 | v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data); | ||
853 | } | ||
854 | 873 | ||
855 | ret = 0; | 874 | if (ctrl->info->flags & UVC_CONTROL_GET_MAX) |
856 | out: | 875 | v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, |
857 | kfree(data); | 876 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX)); |
858 | return ret; | 877 | |
878 | if (ctrl->info->flags & UVC_CONTROL_GET_RES) | ||
879 | v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, | ||
880 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES)); | ||
881 | |||
882 | return 0; | ||
859 | } | 883 | } |
860 | 884 | ||
861 | 885 | ||
@@ -1246,7 +1270,7 @@ static void uvc_ctrl_add_ctrl(struct uvc_device *dev, | |||
1246 | } | 1270 | } |
1247 | 1271 | ||
1248 | ctrl->info = info; | 1272 | ctrl->info = info; |
1249 | ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_NDATA, GFP_KERNEL); | 1273 | ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_DATA_LAST, GFP_KERNEL); |
1250 | uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s " | 1274 | uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s " |
1251 | "entity %u\n", ctrl->info->entity, ctrl->info->selector, | 1275 | "entity %u\n", ctrl->info->entity, ctrl->info->selector, |
1252 | dev->udev->devpath, entity->id); | 1276 | dev->udev->devpath, entity->id); |
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 0c7966fdb83d..2bba059259e6 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h | |||
@@ -245,7 +245,8 @@ struct uvc_control { | |||
245 | uvc_control_info. */ | 245 | uvc_control_info. */ |
246 | __u8 dirty : 1, | 246 | __u8 dirty : 1, |
247 | loaded : 1, | 247 | loaded : 1, |
248 | modified : 1; | 248 | modified : 1, |
249 | cached : 1; | ||
249 | 250 | ||
250 | __u8 *data; | 251 | __u8 *data; |
251 | }; | 252 | }; |