diff options
author | Laurent Pinchart <laurent.pinchart@skynet.be> | 2009-07-01 19:24:47 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-12 11:18:33 -0400 |
commit | 8e113595edf0741b45ba10ba88cb5d077787c155 (patch) | |
tree | 3b2d7b940445989586ad198d2c5c974432d97618 /drivers/media | |
parent | 35f02a681b72ece756cf005e17f305a72329c140 (diff) |
V4L/DVB (12379): uvcvideo: Multiple streaming interfaces support
Restructure the UVC descriptors parsing code to handle multiple streaming
interfaces. The driver now creates a uvc_video_chain instance for each chain
detected in the UVC control interface descriptors, and tries to register one
video device per streaming endpoint.
Signed-off-by: Laurent Pinchart <laurent.pinchart@skynet.be>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/uvc/uvc_ctrl.c | 82 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_driver.c | 466 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_v4l2.c | 80 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_video.c | 2 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvcvideo.h | 59 |
5 files changed, 411 insertions, 278 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index 70043b1704fb..c3225a561748 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c | |||
@@ -729,7 +729,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, | |||
729 | } | 729 | } |
730 | } | 730 | } |
731 | 731 | ||
732 | struct uvc_control *uvc_find_control(struct uvc_video_device *video, | 732 | struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, |
733 | __u32 v4l2_id, struct uvc_control_mapping **mapping) | 733 | __u32 v4l2_id, struct uvc_control_mapping **mapping) |
734 | { | 734 | { |
735 | struct uvc_control *ctrl = NULL; | 735 | struct uvc_control *ctrl = NULL; |
@@ -742,17 +742,17 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video, | |||
742 | v4l2_id &= V4L2_CTRL_ID_MASK; | 742 | v4l2_id &= V4L2_CTRL_ID_MASK; |
743 | 743 | ||
744 | /* Find the control. */ | 744 | /* Find the control. */ |
745 | __uvc_find_control(video->processing, v4l2_id, mapping, &ctrl, next); | 745 | __uvc_find_control(chain->processing, v4l2_id, mapping, &ctrl, next); |
746 | if (ctrl && !next) | 746 | if (ctrl && !next) |
747 | return ctrl; | 747 | return ctrl; |
748 | 748 | ||
749 | list_for_each_entry(entity, &video->iterms, chain) { | 749 | list_for_each_entry(entity, &chain->iterms, chain) { |
750 | __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); | 750 | __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); |
751 | if (ctrl && !next) | 751 | if (ctrl && !next) |
752 | return ctrl; | 752 | return ctrl; |
753 | } | 753 | } |
754 | 754 | ||
755 | list_for_each_entry(entity, &video->extensions, chain) { | 755 | list_for_each_entry(entity, &chain->extensions, chain) { |
756 | __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); | 756 | __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next); |
757 | if (ctrl && !next) | 757 | if (ctrl && !next) |
758 | return ctrl; | 758 | return ctrl; |
@@ -765,7 +765,7 @@ struct uvc_control *uvc_find_control(struct uvc_video_device *video, | |||
765 | return ctrl; | 765 | return ctrl; |
766 | } | 766 | } |
767 | 767 | ||
768 | int uvc_query_v4l2_ctrl(struct uvc_video_device *video, | 768 | int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, |
769 | struct v4l2_queryctrl *v4l2_ctrl) | 769 | struct v4l2_queryctrl *v4l2_ctrl) |
770 | { | 770 | { |
771 | struct uvc_control *ctrl; | 771 | struct uvc_control *ctrl; |
@@ -775,7 +775,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, | |||
775 | __u8 *data; | 775 | __u8 *data; |
776 | int ret; | 776 | int ret; |
777 | 777 | ||
778 | ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping); | 778 | ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping); |
779 | if (ctrl == NULL) | 779 | if (ctrl == NULL) |
780 | return -EINVAL; | 780 | return -EINVAL; |
781 | 781 | ||
@@ -793,9 +793,9 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, | |||
793 | v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; | 793 | v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
794 | 794 | ||
795 | if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { | 795 | if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { |
796 | ret = uvc_query_ctrl(video->dev, UVC_GET_DEF, ctrl->entity->id, | 796 | ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id, |
797 | video->dev->intfnum, ctrl->info->selector, data, | 797 | chain->dev->intfnum, ctrl->info->selector, |
798 | ctrl->info->size); | 798 | data, ctrl->info->size); |
799 | if (ret < 0) | 799 | if (ret < 0) |
800 | goto out; | 800 | goto out; |
801 | v4l2_ctrl->default_value = | 801 | v4l2_ctrl->default_value = |
@@ -831,25 +831,25 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, | |||
831 | } | 831 | } |
832 | 832 | ||
833 | if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { | 833 | if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { |
834 | ret = uvc_query_ctrl(video->dev, UVC_GET_MIN, ctrl->entity->id, | 834 | ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id, |
835 | video->dev->intfnum, ctrl->info->selector, data, | 835 | chain->dev->intfnum, ctrl->info->selector, |
836 | ctrl->info->size); | 836 | data, ctrl->info->size); |
837 | if (ret < 0) | 837 | if (ret < 0) |
838 | goto out; | 838 | goto out; |
839 | v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data); | 839 | v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN, data); |
840 | } | 840 | } |
841 | if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { | 841 | if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { |
842 | ret = uvc_query_ctrl(video->dev, UVC_GET_MAX, ctrl->entity->id, | 842 | ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id, |
843 | video->dev->intfnum, ctrl->info->selector, data, | 843 | chain->dev->intfnum, ctrl->info->selector, |
844 | ctrl->info->size); | 844 | data, ctrl->info->size); |
845 | if (ret < 0) | 845 | if (ret < 0) |
846 | goto out; | 846 | goto out; |
847 | v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data); | 847 | v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX, data); |
848 | } | 848 | } |
849 | if (ctrl->info->flags & UVC_CONTROL_GET_RES) { | 849 | if (ctrl->info->flags & UVC_CONTROL_GET_RES) { |
850 | ret = uvc_query_ctrl(video->dev, UVC_GET_RES, ctrl->entity->id, | 850 | ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id, |
851 | video->dev->intfnum, ctrl->info->selector, data, | 851 | chain->dev->intfnum, ctrl->info->selector, |
852 | ctrl->info->size); | 852 | data, ctrl->info->size); |
853 | if (ret < 0) | 853 | if (ret < 0) |
854 | goto out; | 854 | goto out; |
855 | v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data); | 855 | v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES, data); |
@@ -886,9 +886,9 @@ out: | |||
886 | * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the | 886 | * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the |
887 | * control lock. | 887 | * control lock. |
888 | */ | 888 | */ |
889 | int uvc_ctrl_begin(struct uvc_video_device *video) | 889 | int uvc_ctrl_begin(struct uvc_video_chain *chain) |
890 | { | 890 | { |
891 | return mutex_lock_interruptible(&video->ctrl_mutex) ? -ERESTARTSYS : 0; | 891 | return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0; |
892 | } | 892 | } |
893 | 893 | ||
894 | static int uvc_ctrl_commit_entity(struct uvc_device *dev, | 894 | static int uvc_ctrl_commit_entity(struct uvc_device *dev, |
@@ -938,34 +938,34 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev, | |||
938 | return 0; | 938 | return 0; |
939 | } | 939 | } |
940 | 940 | ||
941 | int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback) | 941 | int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback) |
942 | { | 942 | { |
943 | struct uvc_entity *entity; | 943 | struct uvc_entity *entity; |
944 | int ret = 0; | 944 | int ret = 0; |
945 | 945 | ||
946 | /* Find the control. */ | 946 | /* Find the control. */ |
947 | ret = uvc_ctrl_commit_entity(video->dev, video->processing, rollback); | 947 | ret = uvc_ctrl_commit_entity(chain->dev, chain->processing, rollback); |
948 | if (ret < 0) | 948 | if (ret < 0) |
949 | goto done; | 949 | goto done; |
950 | 950 | ||
951 | list_for_each_entry(entity, &video->iterms, chain) { | 951 | list_for_each_entry(entity, &chain->iterms, chain) { |
952 | ret = uvc_ctrl_commit_entity(video->dev, entity, rollback); | 952 | ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback); |
953 | if (ret < 0) | 953 | if (ret < 0) |
954 | goto done; | 954 | goto done; |
955 | } | 955 | } |
956 | 956 | ||
957 | list_for_each_entry(entity, &video->extensions, chain) { | 957 | list_for_each_entry(entity, &chain->extensions, chain) { |
958 | ret = uvc_ctrl_commit_entity(video->dev, entity, rollback); | 958 | ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback); |
959 | if (ret < 0) | 959 | if (ret < 0) |
960 | goto done; | 960 | goto done; |
961 | } | 961 | } |
962 | 962 | ||
963 | done: | 963 | done: |
964 | mutex_unlock(&video->ctrl_mutex); | 964 | mutex_unlock(&chain->ctrl_mutex); |
965 | return ret; | 965 | return ret; |
966 | } | 966 | } |
967 | 967 | ||
968 | int uvc_ctrl_get(struct uvc_video_device *video, | 968 | int uvc_ctrl_get(struct uvc_video_chain *chain, |
969 | struct v4l2_ext_control *xctrl) | 969 | struct v4l2_ext_control *xctrl) |
970 | { | 970 | { |
971 | struct uvc_control *ctrl; | 971 | struct uvc_control *ctrl; |
@@ -974,13 +974,13 @@ int uvc_ctrl_get(struct uvc_video_device *video, | |||
974 | unsigned int i; | 974 | unsigned int i; |
975 | int ret; | 975 | int ret; |
976 | 976 | ||
977 | ctrl = uvc_find_control(video, xctrl->id, &mapping); | 977 | ctrl = uvc_find_control(chain, xctrl->id, &mapping); |
978 | if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) | 978 | if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) |
979 | return -EINVAL; | 979 | return -EINVAL; |
980 | 980 | ||
981 | if (!ctrl->loaded) { | 981 | if (!ctrl->loaded) { |
982 | ret = uvc_query_ctrl(video->dev, UVC_GET_CUR, ctrl->entity->id, | 982 | ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id, |
983 | video->dev->intfnum, ctrl->info->selector, | 983 | chain->dev->intfnum, ctrl->info->selector, |
984 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), | 984 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), |
985 | ctrl->info->size); | 985 | ctrl->info->size); |
986 | if (ret < 0) | 986 | if (ret < 0) |
@@ -1005,7 +1005,7 @@ int uvc_ctrl_get(struct uvc_video_device *video, | |||
1005 | return 0; | 1005 | return 0; |
1006 | } | 1006 | } |
1007 | 1007 | ||
1008 | int uvc_ctrl_set(struct uvc_video_device *video, | 1008 | int uvc_ctrl_set(struct uvc_video_chain *chain, |
1009 | struct v4l2_ext_control *xctrl) | 1009 | struct v4l2_ext_control *xctrl) |
1010 | { | 1010 | { |
1011 | struct uvc_control *ctrl; | 1011 | struct uvc_control *ctrl; |
@@ -1013,7 +1013,7 @@ int uvc_ctrl_set(struct uvc_video_device *video, | |||
1013 | s32 value = xctrl->value; | 1013 | s32 value = xctrl->value; |
1014 | int ret; | 1014 | int ret; |
1015 | 1015 | ||
1016 | ctrl = uvc_find_control(video, xctrl->id, &mapping); | 1016 | ctrl = uvc_find_control(chain, xctrl->id, &mapping); |
1017 | if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0) | 1017 | if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0) |
1018 | return -EINVAL; | 1018 | return -EINVAL; |
1019 | 1019 | ||
@@ -1028,8 +1028,8 @@ int uvc_ctrl_set(struct uvc_video_device *video, | |||
1028 | memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), | 1028 | memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), |
1029 | 0, ctrl->info->size); | 1029 | 0, ctrl->info->size); |
1030 | } else { | 1030 | } else { |
1031 | ret = uvc_query_ctrl(video->dev, UVC_GET_CUR, | 1031 | ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, |
1032 | ctrl->entity->id, video->dev->intfnum, | 1032 | ctrl->entity->id, chain->dev->intfnum, |
1033 | ctrl->info->selector, | 1033 | ctrl->info->selector, |
1034 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), | 1034 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT), |
1035 | ctrl->info->size); | 1035 | ctrl->info->size); |
@@ -1058,7 +1058,7 @@ int uvc_ctrl_set(struct uvc_video_device *video, | |||
1058 | * Dynamic controls | 1058 | * Dynamic controls |
1059 | */ | 1059 | */ |
1060 | 1060 | ||
1061 | int uvc_xu_ctrl_query(struct uvc_video_device *video, | 1061 | int uvc_xu_ctrl_query(struct uvc_video_chain *chain, |
1062 | struct uvc_xu_control *xctrl, int set) | 1062 | struct uvc_xu_control *xctrl, int set) |
1063 | { | 1063 | { |
1064 | struct uvc_entity *entity; | 1064 | struct uvc_entity *entity; |
@@ -1068,7 +1068,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video, | |||
1068 | int ret; | 1068 | int ret; |
1069 | 1069 | ||
1070 | /* Find the extension unit. */ | 1070 | /* Find the extension unit. */ |
1071 | list_for_each_entry(entity, &video->extensions, chain) { | 1071 | list_for_each_entry(entity, &chain->extensions, chain) { |
1072 | if (entity->id == xctrl->unit) | 1072 | if (entity->id == xctrl->unit) |
1073 | break; | 1073 | break; |
1074 | } | 1074 | } |
@@ -1107,7 +1107,7 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video, | |||
1107 | (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR))) | 1107 | (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR))) |
1108 | return -EINVAL; | 1108 | return -EINVAL; |
1109 | 1109 | ||
1110 | if (mutex_lock_interruptible(&video->ctrl_mutex)) | 1110 | if (mutex_lock_interruptible(&chain->ctrl_mutex)) |
1111 | return -ERESTARTSYS; | 1111 | return -ERESTARTSYS; |
1112 | 1112 | ||
1113 | memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), | 1113 | memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), |
@@ -1120,8 +1120,8 @@ int uvc_xu_ctrl_query(struct uvc_video_device *video, | |||
1120 | goto out; | 1120 | goto out; |
1121 | } | 1121 | } |
1122 | 1122 | ||
1123 | ret = uvc_query_ctrl(video->dev, set ? UVC_SET_CUR : UVC_GET_CUR, | 1123 | ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR, |
1124 | xctrl->unit, video->dev->intfnum, xctrl->selector, | 1124 | xctrl->unit, chain->dev->intfnum, xctrl->selector, |
1125 | data, xctrl->size); | 1125 | data, xctrl->size); |
1126 | if (ret < 0) | 1126 | if (ret < 0) |
1127 | goto out; | 1127 | goto out; |
@@ -1137,7 +1137,7 @@ out: | |||
1137 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), | 1137 | uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP), |
1138 | xctrl->size); | 1138 | xctrl->size); |
1139 | 1139 | ||
1140 | mutex_unlock(&video->ctrl_mutex); | 1140 | mutex_unlock(&chain->ctrl_mutex); |
1141 | return ret; | 1141 | return ret; |
1142 | } | 1142 | } |
1143 | 1143 | ||
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 81bf67126abf..8756be569154 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c | |||
@@ -276,8 +276,20 @@ static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev, | |||
276 | return NULL; | 276 | return NULL; |
277 | } | 277 | } |
278 | 278 | ||
279 | static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id) | ||
280 | { | ||
281 | struct uvc_streaming *stream; | ||
282 | |||
283 | list_for_each_entry(stream, &dev->streams, list) { | ||
284 | if (stream->header.bTerminalLink == id) | ||
285 | return stream; | ||
286 | } | ||
287 | |||
288 | return NULL; | ||
289 | } | ||
290 | |||
279 | /* ------------------------------------------------------------------------ | 291 | /* ------------------------------------------------------------------------ |
280 | * Descriptors handling | 292 | * Descriptors parsing |
281 | */ | 293 | */ |
282 | 294 | ||
283 | static int uvc_parse_format(struct uvc_device *dev, | 295 | static int uvc_parse_format(struct uvc_device *dev, |
@@ -1160,101 +1172,36 @@ next_descriptor: | |||
1160 | } | 1172 | } |
1161 | 1173 | ||
1162 | /* ------------------------------------------------------------------------ | 1174 | /* ------------------------------------------------------------------------ |
1163 | * USB probe and disconnect | 1175 | * UVC device scan |
1164 | */ | 1176 | */ |
1165 | 1177 | ||
1166 | /* | 1178 | /* |
1167 | * Unregister the video devices. | ||
1168 | */ | ||
1169 | static void uvc_unregister_video(struct uvc_device *dev) | ||
1170 | { | ||
1171 | struct uvc_streaming *streaming; | ||
1172 | |||
1173 | list_for_each_entry(streaming, &dev->streams, list) { | ||
1174 | if (streaming->vdev == NULL) | ||
1175 | continue; | ||
1176 | |||
1177 | if (streaming->vdev->minor == -1) | ||
1178 | video_device_release(streaming->vdev); | ||
1179 | else | ||
1180 | video_unregister_device(streaming->vdev); | ||
1181 | streaming->vdev = NULL; | ||
1182 | } | ||
1183 | } | ||
1184 | |||
1185 | static int uvc_register_video(struct uvc_device *dev, | ||
1186 | struct uvc_streaming *stream) | ||
1187 | { | ||
1188 | struct video_device *vdev; | ||
1189 | struct uvc_entity *term; | ||
1190 | int ret; | ||
1191 | |||
1192 | if (uvc_trace_param & UVC_TRACE_PROBE) { | ||
1193 | uvc_printk(KERN_INFO, "Found a valid video chain ("); | ||
1194 | list_for_each_entry(term, &dev->video.iterms, chain) { | ||
1195 | printk("%d", term->id); | ||
1196 | if (term->chain.next != &dev->video.iterms) | ||
1197 | printk(","); | ||
1198 | } | ||
1199 | printk(" -> %d).\n", dev->video.oterm->id); | ||
1200 | } | ||
1201 | |||
1202 | /* Initialize the streaming interface with default streaming | ||
1203 | * parameters. | ||
1204 | */ | ||
1205 | ret = uvc_video_init(stream); | ||
1206 | if (ret < 0) { | ||
1207 | uvc_printk(KERN_ERR, "Failed to initialize the device " | ||
1208 | "(%d).\n", ret); | ||
1209 | return ret; | ||
1210 | } | ||
1211 | |||
1212 | /* Register the device with V4L. */ | ||
1213 | vdev = video_device_alloc(); | ||
1214 | if (vdev == NULL) | ||
1215 | return -1; | ||
1216 | |||
1217 | /* We already hold a reference to dev->udev. The video device will be | ||
1218 | * unregistered before the reference is released, so we don't need to | ||
1219 | * get another one. | ||
1220 | */ | ||
1221 | vdev->parent = &dev->intf->dev; | ||
1222 | vdev->minor = -1; | ||
1223 | vdev->fops = &uvc_fops; | ||
1224 | vdev->release = video_device_release; | ||
1225 | strlcpy(vdev->name, dev->name, sizeof vdev->name); | ||
1226 | |||
1227 | /* Set the driver data before calling video_register_device, otherwise | ||
1228 | * uvc_v4l2_open might race us. | ||
1229 | */ | ||
1230 | stream->vdev = vdev; | ||
1231 | video_set_drvdata(vdev, stream); | ||
1232 | |||
1233 | if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) < 0) { | ||
1234 | stream->vdev = NULL; | ||
1235 | video_device_release(vdev); | ||
1236 | return -1; | ||
1237 | } | ||
1238 | |||
1239 | return 0; | ||
1240 | } | ||
1241 | |||
1242 | /* | ||
1243 | * Scan the UVC descriptors to locate a chain starting at an Output Terminal | 1179 | * Scan the UVC descriptors to locate a chain starting at an Output Terminal |
1244 | * and containing the following units: | 1180 | * and containing the following units: |
1245 | * | 1181 | * |
1246 | * - one Output Terminal (USB Streaming or Display) | 1182 | * - one or more Output Terminals (USB Streaming or Display) |
1247 | * - zero or one Processing Unit | 1183 | * - zero or one Processing Unit |
1248 | * - zero, one or mode single-input Selector Units | 1184 | * - zero, one or more single-input Selector Units |
1249 | * - zero or one multiple-input Selector Units, provided all inputs are | 1185 | * - zero or one multiple-input Selector Units, provided all inputs are |
1250 | * connected to input terminals | 1186 | * connected to input terminals |
1251 | * - zero, one or mode single-input Extension Units | 1187 | * - zero, one or mode single-input Extension Units |
1252 | * - one or more Input Terminals (Camera, External or USB Streaming) | 1188 | * - one or more Input Terminals (Camera, External or USB Streaming) |
1253 | * | 1189 | * |
1254 | * A side forward scan is made on each detected entity to check for additional | 1190 | * The terminal and units must match on of the following structures: |
1255 | * extension units. | 1191 | * |
1192 | * ITT_*(0) -> +---------+ +---------+ +---------+ -> TT_STREAMING(0) | ||
1193 | * ... | SU{0,1} | -> | PU{0,1} | -> | XU{0,n} | ... | ||
1194 | * ITT_*(n) -> +---------+ +---------+ +---------+ -> TT_STREAMING(n) | ||
1195 | * | ||
1196 | * +---------+ +---------+ -> OTT_*(0) | ||
1197 | * TT_STREAMING -> | PU{0,1} | -> | XU{0,n} | ... | ||
1198 | * +---------+ +---------+ -> OTT_*(n) | ||
1199 | * | ||
1200 | * The Processing Unit and Extension Units can be in any order. Additional | ||
1201 | * Extension Units connected to the main chain as single-unit branches are | ||
1202 | * also supported. Single-input Selector Units are ignored. | ||
1256 | */ | 1203 | */ |
1257 | static int uvc_scan_chain_entity(struct uvc_video_device *video, | 1204 | static int uvc_scan_chain_entity(struct uvc_video_chain *chain, |
1258 | struct uvc_entity *entity) | 1205 | struct uvc_entity *entity) |
1259 | { | 1206 | { |
1260 | switch (UVC_ENTITY_TYPE(entity)) { | 1207 | switch (UVC_ENTITY_TYPE(entity)) { |
@@ -1268,20 +1215,20 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, | |||
1268 | return -1; | 1215 | return -1; |
1269 | } | 1216 | } |
1270 | 1217 | ||
1271 | list_add_tail(&entity->chain, &video->extensions); | 1218 | list_add_tail(&entity->chain, &chain->extensions); |
1272 | break; | 1219 | break; |
1273 | 1220 | ||
1274 | case UVC_VC_PROCESSING_UNIT: | 1221 | case UVC_VC_PROCESSING_UNIT: |
1275 | if (uvc_trace_param & UVC_TRACE_PROBE) | 1222 | if (uvc_trace_param & UVC_TRACE_PROBE) |
1276 | printk(" <- PU %d", entity->id); | 1223 | printk(" <- PU %d", entity->id); |
1277 | 1224 | ||
1278 | if (video->processing != NULL) { | 1225 | if (chain->processing != NULL) { |
1279 | uvc_trace(UVC_TRACE_DESCR, "Found multiple " | 1226 | uvc_trace(UVC_TRACE_DESCR, "Found multiple " |
1280 | "Processing Units in chain.\n"); | 1227 | "Processing Units in chain.\n"); |
1281 | return -1; | 1228 | return -1; |
1282 | } | 1229 | } |
1283 | 1230 | ||
1284 | video->processing = entity; | 1231 | chain->processing = entity; |
1285 | break; | 1232 | break; |
1286 | 1233 | ||
1287 | case UVC_VC_SELECTOR_UNIT: | 1234 | case UVC_VC_SELECTOR_UNIT: |
@@ -1292,13 +1239,13 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, | |||
1292 | if (entity->selector.bNrInPins == 1) | 1239 | if (entity->selector.bNrInPins == 1) |
1293 | break; | 1240 | break; |
1294 | 1241 | ||
1295 | if (video->selector != NULL) { | 1242 | if (chain->selector != NULL) { |
1296 | uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector " | 1243 | uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector " |
1297 | "Units in chain.\n"); | 1244 | "Units in chain.\n"); |
1298 | return -1; | 1245 | return -1; |
1299 | } | 1246 | } |
1300 | 1247 | ||
1301 | video->selector = entity; | 1248 | chain->selector = entity; |
1302 | break; | 1249 | break; |
1303 | 1250 | ||
1304 | case UVC_ITT_VENDOR_SPECIFIC: | 1251 | case UVC_ITT_VENDOR_SPECIFIC: |
@@ -1307,7 +1254,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, | |||
1307 | if (uvc_trace_param & UVC_TRACE_PROBE) | 1254 | if (uvc_trace_param & UVC_TRACE_PROBE) |
1308 | printk(" <- IT %d\n", entity->id); | 1255 | printk(" <- IT %d\n", entity->id); |
1309 | 1256 | ||
1310 | list_add_tail(&entity->chain, &video->iterms); | 1257 | list_add_tail(&entity->chain, &chain->iterms); |
1311 | break; | 1258 | break; |
1312 | 1259 | ||
1313 | case UVC_TT_STREAMING: | 1260 | case UVC_TT_STREAMING: |
@@ -1320,14 +1267,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, | |||
1320 | return -1; | 1267 | return -1; |
1321 | } | 1268 | } |
1322 | 1269 | ||
1323 | if (video->sterm != NULL) { | 1270 | list_add_tail(&entity->chain, &chain->iterms); |
1324 | uvc_trace(UVC_TRACE_DESCR, "Found multiple streaming " | ||
1325 | "entities in chain.\n"); | ||
1326 | return -1; | ||
1327 | } | ||
1328 | |||
1329 | list_add_tail(&entity->chain, &video->iterms); | ||
1330 | video->sterm = entity; | ||
1331 | break; | 1271 | break; |
1332 | 1272 | ||
1333 | default: | 1273 | default: |
@@ -1339,7 +1279,7 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, | |||
1339 | return 0; | 1279 | return 0; |
1340 | } | 1280 | } |
1341 | 1281 | ||
1342 | static int uvc_scan_chain_forward(struct uvc_video_device *video, | 1282 | static int uvc_scan_chain_forward(struct uvc_video_chain *chain, |
1343 | struct uvc_entity *entity, struct uvc_entity *prev) | 1283 | struct uvc_entity *entity, struct uvc_entity *prev) |
1344 | { | 1284 | { |
1345 | struct uvc_entity *forward; | 1285 | struct uvc_entity *forward; |
@@ -1350,28 +1290,51 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video, | |||
1350 | found = 0; | 1290 | found = 0; |
1351 | 1291 | ||
1352 | while (1) { | 1292 | while (1) { |
1353 | forward = uvc_entity_by_reference(video->dev, entity->id, | 1293 | forward = uvc_entity_by_reference(chain->dev, entity->id, |
1354 | forward); | 1294 | forward); |
1355 | if (forward == NULL) | 1295 | if (forward == NULL) |
1356 | break; | 1296 | break; |
1357 | 1297 | if (forward == prev) | |
1358 | if (UVC_ENTITY_TYPE(forward) != UVC_VC_EXTENSION_UNIT || | ||
1359 | forward == prev) | ||
1360 | continue; | 1298 | continue; |
1361 | 1299 | ||
1362 | if (forward->extension.bNrInPins != 1) { | 1300 | switch (UVC_ENTITY_TYPE(forward)) { |
1363 | uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has " | 1301 | case UVC_VC_EXTENSION_UNIT: |
1364 | "more than 1 input pin.\n", entity->id); | 1302 | if (forward->extension.bNrInPins != 1) { |
1365 | return -1; | 1303 | uvc_trace(UVC_TRACE_DESCR, "Extension unit %d " |
1366 | } | 1304 | "has more than 1 input pin.\n", |
1305 | entity->id); | ||
1306 | return -EINVAL; | ||
1307 | } | ||
1308 | |||
1309 | list_add_tail(&forward->chain, &chain->extensions); | ||
1310 | if (uvc_trace_param & UVC_TRACE_PROBE) { | ||
1311 | if (!found) | ||
1312 | printk(" (->"); | ||
1313 | |||
1314 | printk(" XU %d", forward->id); | ||
1315 | found = 1; | ||
1316 | } | ||
1317 | break; | ||
1318 | |||
1319 | case UVC_OTT_VENDOR_SPECIFIC: | ||
1320 | case UVC_OTT_DISPLAY: | ||
1321 | case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: | ||
1322 | case UVC_TT_STREAMING: | ||
1323 | if (UVC_ENTITY_IS_ITERM(forward)) { | ||
1324 | uvc_trace(UVC_TRACE_DESCR, "Unsupported input " | ||
1325 | "terminal %u.\n", forward->id); | ||
1326 | return -EINVAL; | ||
1327 | } | ||
1367 | 1328 | ||
1368 | list_add_tail(&forward->chain, &video->extensions); | 1329 | list_add_tail(&forward->chain, &chain->oterms); |
1369 | if (uvc_trace_param & UVC_TRACE_PROBE) { | 1330 | if (uvc_trace_param & UVC_TRACE_PROBE) { |
1370 | if (!found) | 1331 | if (!found) |
1371 | printk(" (-> XU"); | 1332 | printk(" (->"); |
1372 | 1333 | ||
1373 | printk(" %d", forward->id); | 1334 | printk(" OT %d", forward->id); |
1374 | found = 1; | 1335 | found = 1; |
1336 | } | ||
1337 | break; | ||
1375 | } | 1338 | } |
1376 | } | 1339 | } |
1377 | if (found) | 1340 | if (found) |
@@ -1380,7 +1343,7 @@ static int uvc_scan_chain_forward(struct uvc_video_device *video, | |||
1380 | return 0; | 1343 | return 0; |
1381 | } | 1344 | } |
1382 | 1345 | ||
1383 | static int uvc_scan_chain_backward(struct uvc_video_device *video, | 1346 | static int uvc_scan_chain_backward(struct uvc_video_chain *chain, |
1384 | struct uvc_entity *entity) | 1347 | struct uvc_entity *entity) |
1385 | { | 1348 | { |
1386 | struct uvc_entity *term; | 1349 | struct uvc_entity *term; |
@@ -1405,10 +1368,10 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video, | |||
1405 | if (uvc_trace_param & UVC_TRACE_PROBE) | 1368 | if (uvc_trace_param & UVC_TRACE_PROBE) |
1406 | printk(" <- IT"); | 1369 | printk(" <- IT"); |
1407 | 1370 | ||
1408 | video->selector = entity; | 1371 | chain->selector = entity; |
1409 | for (i = 0; i < entity->selector.bNrInPins; ++i) { | 1372 | for (i = 0; i < entity->selector.bNrInPins; ++i) { |
1410 | id = entity->selector.baSourceID[i]; | 1373 | id = entity->selector.baSourceID[i]; |
1411 | term = uvc_entity_by_id(video->dev, id); | 1374 | term = uvc_entity_by_id(chain->dev, id); |
1412 | if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) { | 1375 | if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) { |
1413 | uvc_trace(UVC_TRACE_DESCR, "Selector unit %d " | 1376 | uvc_trace(UVC_TRACE_DESCR, "Selector unit %d " |
1414 | "input %d isn't connected to an " | 1377 | "input %d isn't connected to an " |
@@ -1419,8 +1382,8 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video, | |||
1419 | if (uvc_trace_param & UVC_TRACE_PROBE) | 1382 | if (uvc_trace_param & UVC_TRACE_PROBE) |
1420 | printk(" %d", term->id); | 1383 | printk(" %d", term->id); |
1421 | 1384 | ||
1422 | list_add_tail(&term->chain, &video->iterms); | 1385 | list_add_tail(&term->chain, &chain->iterms); |
1423 | uvc_scan_chain_forward(video, term, entity); | 1386 | uvc_scan_chain_forward(chain, term, entity); |
1424 | } | 1387 | } |
1425 | 1388 | ||
1426 | if (uvc_trace_param & UVC_TRACE_PROBE) | 1389 | if (uvc_trace_param & UVC_TRACE_PROBE) |
@@ -1433,100 +1396,129 @@ static int uvc_scan_chain_backward(struct uvc_video_device *video, | |||
1433 | return id; | 1396 | return id; |
1434 | } | 1397 | } |
1435 | 1398 | ||
1436 | static int uvc_scan_chain(struct uvc_video_device *video) | 1399 | static int uvc_scan_chain(struct uvc_video_chain *chain, |
1400 | struct uvc_entity *oterm) | ||
1437 | { | 1401 | { |
1438 | struct uvc_entity *entity, *prev; | 1402 | struct uvc_entity *entity, *prev; |
1439 | int id; | 1403 | int id; |
1440 | 1404 | ||
1441 | entity = video->oterm; | 1405 | entity = oterm; |
1406 | list_add_tail(&entity->chain, &chain->oterms); | ||
1442 | uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id); | 1407 | uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id); |
1443 | 1408 | ||
1444 | if (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING) | ||
1445 | video->sterm = entity; | ||
1446 | |||
1447 | id = entity->output.bSourceID; | 1409 | id = entity->output.bSourceID; |
1448 | while (id != 0) { | 1410 | while (id != 0) { |
1449 | prev = entity; | 1411 | prev = entity; |
1450 | entity = uvc_entity_by_id(video->dev, id); | 1412 | entity = uvc_entity_by_id(chain->dev, id); |
1451 | if (entity == NULL) { | 1413 | if (entity == NULL) { |
1452 | uvc_trace(UVC_TRACE_DESCR, "Found reference to " | 1414 | uvc_trace(UVC_TRACE_DESCR, "Found reference to " |
1453 | "unknown entity %d.\n", id); | 1415 | "unknown entity %d.\n", id); |
1454 | return -1; | 1416 | return -EINVAL; |
1417 | } | ||
1418 | |||
1419 | if (entity->chain.next || entity->chain.prev) { | ||
1420 | uvc_trace(UVC_TRACE_DESCR, "Found reference to " | ||
1421 | "entity %d already in chain.\n", id); | ||
1422 | return -EINVAL; | ||
1455 | } | 1423 | } |
1456 | 1424 | ||
1457 | /* Process entity */ | 1425 | /* Process entity */ |
1458 | if (uvc_scan_chain_entity(video, entity) < 0) | 1426 | if (uvc_scan_chain_entity(chain, entity) < 0) |
1459 | return -1; | 1427 | return -EINVAL; |
1460 | 1428 | ||
1461 | /* Forward scan */ | 1429 | /* Forward scan */ |
1462 | if (uvc_scan_chain_forward(video, entity, prev) < 0) | 1430 | if (uvc_scan_chain_forward(chain, entity, prev) < 0) |
1463 | return -1; | 1431 | return -EINVAL; |
1464 | 1432 | ||
1465 | /* Stop when a terminal is found. */ | 1433 | /* Stop when a terminal is found. */ |
1466 | if (!UVC_ENTITY_IS_UNIT(entity)) | 1434 | if (UVC_ENTITY_IS_TERM(entity)) |
1467 | break; | 1435 | break; |
1468 | 1436 | ||
1469 | /* Backward scan */ | 1437 | /* Backward scan */ |
1470 | id = uvc_scan_chain_backward(video, entity); | 1438 | id = uvc_scan_chain_backward(chain, entity); |
1471 | if (id < 0) | 1439 | if (id < 0) |
1472 | return id; | 1440 | return id; |
1473 | } | 1441 | } |
1474 | 1442 | ||
1475 | if (video->sterm == NULL) { | 1443 | return 0; |
1476 | uvc_trace(UVC_TRACE_DESCR, "No streaming entity found in " | 1444 | } |
1477 | "chain.\n"); | 1445 | |
1478 | return -1; | 1446 | static unsigned int uvc_print_terms(struct list_head *terms, char *buffer) |
1447 | { | ||
1448 | struct uvc_entity *term; | ||
1449 | unsigned int nterms = 0; | ||
1450 | char *p = buffer; | ||
1451 | |||
1452 | list_for_each_entry(term, terms, chain) { | ||
1453 | p += sprintf(p, "%u", term->id); | ||
1454 | if (term->chain.next != terms) { | ||
1455 | p += sprintf(p, ","); | ||
1456 | if (++nterms >= 4) { | ||
1457 | p += sprintf(p, "..."); | ||
1458 | break; | ||
1459 | } | ||
1460 | } | ||
1479 | } | 1461 | } |
1480 | 1462 | ||
1481 | return 0; | 1463 | return p - buffer; |
1464 | } | ||
1465 | |||
1466 | static const char *uvc_print_chain(struct uvc_video_chain *chain) | ||
1467 | { | ||
1468 | static char buffer[43]; | ||
1469 | char *p = buffer; | ||
1470 | |||
1471 | p += uvc_print_terms(&chain->iterms, p); | ||
1472 | p += sprintf(p, " -> "); | ||
1473 | uvc_print_terms(&chain->oterms, p); | ||
1474 | |||
1475 | return buffer; | ||
1482 | } | 1476 | } |
1483 | 1477 | ||
1484 | /* | 1478 | /* |
1485 | * Scan the device for video chains and register video devices. | 1479 | * Scan the device for video chains and register video devices. |
1486 | * | 1480 | * |
1487 | * The driver currently supports a single video device per control interface | 1481 | * Chains are scanned starting at their output terminals and walked backwards. |
1488 | * only. The terminal and units must match the following structure: | ||
1489 | * | ||
1490 | * ITT_* -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING | ||
1491 | * TT_STREAMING -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> OTT_* | ||
1492 | * | ||
1493 | * The Extension Units, if present, must have a single input pin. The | ||
1494 | * Processing Unit and Extension Units can be in any order. Additional | ||
1495 | * Extension Units connected to the main chain as single-unit branches are | ||
1496 | * also supported. | ||
1497 | */ | 1482 | */ |
1498 | static int uvc_scan_device(struct uvc_device *dev) | 1483 | static int uvc_scan_device(struct uvc_device *dev) |
1499 | { | 1484 | { |
1485 | struct uvc_video_chain *chain; | ||
1500 | struct uvc_entity *term; | 1486 | struct uvc_entity *term; |
1501 | int found = 0; | ||
1502 | 1487 | ||
1503 | /* Check if the control interface matches the structure we expect. */ | ||
1504 | list_for_each_entry(term, &dev->entities, list) { | 1488 | list_for_each_entry(term, &dev->entities, list) { |
1505 | struct uvc_streaming *stream; | 1489 | if (!UVC_ENTITY_IS_OTERM(term)) |
1506 | |||
1507 | if (!UVC_ENTITY_IS_TERM(term) || !UVC_ENTITY_IS_OTERM(term)) | ||
1508 | continue; | 1490 | continue; |
1509 | 1491 | ||
1510 | memset(&dev->video, 0, sizeof dev->video); | 1492 | /* If the terminal is already included in a chain, skip it. |
1511 | mutex_init(&dev->video.ctrl_mutex); | 1493 | * This can happen for chains that have multiple output |
1512 | INIT_LIST_HEAD(&dev->video.iterms); | 1494 | * terminals, where all output terminals beside the first one |
1513 | INIT_LIST_HEAD(&dev->video.extensions); | 1495 | * will be inserted in the chain in forward scans. |
1514 | dev->video.oterm = term; | 1496 | */ |
1515 | dev->video.dev = dev; | 1497 | if (term->chain.next || term->chain.prev) |
1516 | if (uvc_scan_chain(&dev->video) < 0) | ||
1517 | continue; | 1498 | continue; |
1518 | 1499 | ||
1519 | list_for_each_entry(stream, &dev->streams, list) { | 1500 | chain = kzalloc(sizeof(*chain), GFP_KERNEL); |
1520 | if (stream->header.bTerminalLink == | 1501 | if (chain == NULL) |
1521 | dev->video.sterm->id) { | 1502 | return -ENOMEM; |
1522 | uvc_register_video(dev, stream); | 1503 | |
1523 | found = 1; | 1504 | INIT_LIST_HEAD(&chain->iterms); |
1524 | break; | 1505 | INIT_LIST_HEAD(&chain->oterms); |
1525 | } | 1506 | INIT_LIST_HEAD(&chain->extensions); |
1507 | mutex_init(&chain->ctrl_mutex); | ||
1508 | chain->dev = dev; | ||
1509 | |||
1510 | if (uvc_scan_chain(chain, term) < 0) { | ||
1511 | kfree(chain); | ||
1512 | continue; | ||
1526 | } | 1513 | } |
1514 | |||
1515 | uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n", | ||
1516 | uvc_print_chain(chain)); | ||
1517 | |||
1518 | list_add_tail(&chain->list, &dev->chains); | ||
1527 | } | 1519 | } |
1528 | 1520 | ||
1529 | if (!found) { | 1521 | if (list_empty(&dev->chains)) { |
1530 | uvc_printk(KERN_INFO, "No valid video chain found.\n"); | 1522 | uvc_printk(KERN_INFO, "No valid video chain found.\n"); |
1531 | return -1; | 1523 | return -1; |
1532 | } | 1524 | } |
@@ -1534,6 +1526,133 @@ static int uvc_scan_device(struct uvc_device *dev) | |||
1534 | return 0; | 1526 | return 0; |
1535 | } | 1527 | } |
1536 | 1528 | ||
1529 | /* ------------------------------------------------------------------------ | ||
1530 | * Video device registration and unregistration | ||
1531 | */ | ||
1532 | |||
1533 | /* | ||
1534 | * Unregister the video devices. | ||
1535 | */ | ||
1536 | static void uvc_unregister_video(struct uvc_device *dev) | ||
1537 | { | ||
1538 | struct uvc_streaming *stream; | ||
1539 | |||
1540 | list_for_each_entry(stream, &dev->streams, list) { | ||
1541 | if (stream->vdev == NULL) | ||
1542 | continue; | ||
1543 | |||
1544 | if (stream->vdev->minor == -1) | ||
1545 | video_device_release(stream->vdev); | ||
1546 | else | ||
1547 | video_unregister_device(stream->vdev); | ||
1548 | stream->vdev = NULL; | ||
1549 | } | ||
1550 | } | ||
1551 | |||
1552 | static int uvc_register_video(struct uvc_device *dev, | ||
1553 | struct uvc_streaming *stream) | ||
1554 | { | ||
1555 | struct video_device *vdev; | ||
1556 | int ret; | ||
1557 | |||
1558 | /* Initialize the streaming interface with default streaming | ||
1559 | * parameters. | ||
1560 | */ | ||
1561 | ret = uvc_video_init(stream); | ||
1562 | if (ret < 0) { | ||
1563 | uvc_printk(KERN_ERR, "Failed to initialize the device " | ||
1564 | "(%d).\n", ret); | ||
1565 | return ret; | ||
1566 | } | ||
1567 | |||
1568 | /* Register the device with V4L. */ | ||
1569 | vdev = video_device_alloc(); | ||
1570 | if (vdev == NULL) { | ||
1571 | uvc_printk(KERN_ERR, "Failed to allocate video device (%d).\n", | ||
1572 | ret); | ||
1573 | return -ENOMEM; | ||
1574 | } | ||
1575 | |||
1576 | /* We already hold a reference to dev->udev. The video device will be | ||
1577 | * unregistered before the reference is released, so we don't need to | ||
1578 | * get another one. | ||
1579 | */ | ||
1580 | vdev->parent = &dev->intf->dev; | ||
1581 | vdev->minor = -1; | ||
1582 | vdev->fops = &uvc_fops; | ||
1583 | vdev->release = video_device_release; | ||
1584 | strlcpy(vdev->name, dev->name, sizeof vdev->name); | ||
1585 | |||
1586 | /* Set the driver data before calling video_register_device, otherwise | ||
1587 | * uvc_v4l2_open might race us. | ||
1588 | */ | ||
1589 | stream->vdev = vdev; | ||
1590 | video_set_drvdata(vdev, stream); | ||
1591 | |||
1592 | ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); | ||
1593 | if (ret < 0) { | ||
1594 | uvc_printk(KERN_ERR, "Failed to register video device (%d).\n", | ||
1595 | ret); | ||
1596 | stream->vdev = NULL; | ||
1597 | video_device_release(vdev); | ||
1598 | return ret; | ||
1599 | } | ||
1600 | |||
1601 | return 0; | ||
1602 | } | ||
1603 | |||
1604 | /* | ||
1605 | * Register all video devices in all chains. | ||
1606 | */ | ||
1607 | static int uvc_register_terms(struct uvc_device *dev, | ||
1608 | struct uvc_video_chain *chain, struct list_head *terms) | ||
1609 | { | ||
1610 | struct uvc_streaming *stream; | ||
1611 | struct uvc_entity *term; | ||
1612 | int ret; | ||
1613 | |||
1614 | list_for_each_entry(term, terms, chain) { | ||
1615 | if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING) | ||
1616 | continue; | ||
1617 | |||
1618 | stream = uvc_stream_by_id(dev, term->id); | ||
1619 | if (stream == NULL) { | ||
1620 | uvc_printk(KERN_INFO, "No streaming interface found " | ||
1621 | "for terminal %u.", term->id); | ||
1622 | continue; | ||
1623 | } | ||
1624 | |||
1625 | stream->chain = chain; | ||
1626 | ret = uvc_register_video(dev, stream); | ||
1627 | if (ret < 0) | ||
1628 | return ret; | ||
1629 | } | ||
1630 | |||
1631 | return 0; | ||
1632 | } | ||
1633 | |||
1634 | static int uvc_register_chains(struct uvc_device *dev) | ||
1635 | { | ||
1636 | struct uvc_video_chain *chain; | ||
1637 | int ret; | ||
1638 | |||
1639 | list_for_each_entry(chain, &dev->chains, list) { | ||
1640 | ret = uvc_register_terms(dev, chain, &chain->iterms); | ||
1641 | if (ret < 0) | ||
1642 | return ret; | ||
1643 | |||
1644 | ret = uvc_register_terms(dev, chain, &chain->oterms); | ||
1645 | if (ret < 0) | ||
1646 | return ret; | ||
1647 | } | ||
1648 | |||
1649 | return 0; | ||
1650 | } | ||
1651 | |||
1652 | /* ------------------------------------------------------------------------ | ||
1653 | * USB probe, disconnect, suspend and resume | ||
1654 | */ | ||
1655 | |||
1537 | /* | 1656 | /* |
1538 | * Delete the UVC device. | 1657 | * Delete the UVC device. |
1539 | * | 1658 | * |
@@ -1555,7 +1674,7 @@ void uvc_delete(struct kref *kref) | |||
1555 | struct uvc_device *dev = container_of(kref, struct uvc_device, kref); | 1674 | struct uvc_device *dev = container_of(kref, struct uvc_device, kref); |
1556 | struct list_head *p, *n; | 1675 | struct list_head *p, *n; |
1557 | 1676 | ||
1558 | /* Unregister the video device. */ | 1677 | /* Unregister the video devices. */ |
1559 | uvc_unregister_video(dev); | 1678 | uvc_unregister_video(dev); |
1560 | usb_put_intf(dev->intf); | 1679 | usb_put_intf(dev->intf); |
1561 | usb_put_dev(dev->udev); | 1680 | usb_put_dev(dev->udev); |
@@ -1563,6 +1682,12 @@ void uvc_delete(struct kref *kref) | |||
1563 | uvc_status_cleanup(dev); | 1682 | uvc_status_cleanup(dev); |
1564 | uvc_ctrl_cleanup_device(dev); | 1683 | uvc_ctrl_cleanup_device(dev); |
1565 | 1684 | ||
1685 | list_for_each_safe(p, n, &dev->chains) { | ||
1686 | struct uvc_video_chain *chain; | ||
1687 | chain = list_entry(p, struct uvc_video_chain, list); | ||
1688 | kfree(chain); | ||
1689 | } | ||
1690 | |||
1566 | list_for_each_safe(p, n, &dev->entities) { | 1691 | list_for_each_safe(p, n, &dev->entities) { |
1567 | struct uvc_entity *entity; | 1692 | struct uvc_entity *entity; |
1568 | entity = list_entry(p, struct uvc_entity, list); | 1693 | entity = list_entry(p, struct uvc_entity, list); |
@@ -1603,6 +1728,7 @@ static int uvc_probe(struct usb_interface *intf, | |||
1603 | return -ENOMEM; | 1728 | return -ENOMEM; |
1604 | 1729 | ||
1605 | INIT_LIST_HEAD(&dev->entities); | 1730 | INIT_LIST_HEAD(&dev->entities); |
1731 | INIT_LIST_HEAD(&dev->chains); | ||
1606 | INIT_LIST_HEAD(&dev->streams); | 1732 | INIT_LIST_HEAD(&dev->streams); |
1607 | kref_init(&dev->kref); | 1733 | kref_init(&dev->kref); |
1608 | atomic_set(&dev->users, 0); | 1734 | atomic_set(&dev->users, 0); |
@@ -1644,10 +1770,14 @@ static int uvc_probe(struct usb_interface *intf, | |||
1644 | if (uvc_ctrl_init_device(dev) < 0) | 1770 | if (uvc_ctrl_init_device(dev) < 0) |
1645 | goto error; | 1771 | goto error; |
1646 | 1772 | ||
1647 | /* Scan the device for video chains and register video devices. */ | 1773 | /* Scan the device for video chains. */ |
1648 | if (uvc_scan_device(dev) < 0) | 1774 | if (uvc_scan_device(dev) < 0) |
1649 | goto error; | 1775 | goto error; |
1650 | 1776 | ||
1777 | /* Register video devices. */ | ||
1778 | if (uvc_register_chains(dev) < 0) | ||
1779 | goto error; | ||
1780 | |||
1651 | /* Save our data pointer in the interface data. */ | 1781 | /* Save our data pointer in the interface data. */ |
1652 | usb_set_intfdata(intf, dev); | 1782 | usb_set_intfdata(intf, dev); |
1653 | 1783 | ||
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 7e847bbaf2a4..9e7351569b5d 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c | |||
@@ -40,7 +40,7 @@ | |||
40 | * table for the controls that can be mapped directly, and handle the others | 40 | * table for the controls that can be mapped directly, and handle the others |
41 | * manually. | 41 | * manually. |
42 | */ | 42 | */ |
43 | static int uvc_v4l2_query_menu(struct uvc_video_device *video, | 43 | static int uvc_v4l2_query_menu(struct uvc_video_chain *chain, |
44 | struct v4l2_querymenu *query_menu) | 44 | struct v4l2_querymenu *query_menu) |
45 | { | 45 | { |
46 | struct uvc_menu_info *menu_info; | 46 | struct uvc_menu_info *menu_info; |
@@ -49,7 +49,7 @@ static int uvc_v4l2_query_menu(struct uvc_video_device *video, | |||
49 | u32 index = query_menu->index; | 49 | u32 index = query_menu->index; |
50 | u32 id = query_menu->id; | 50 | u32 id = query_menu->id; |
51 | 51 | ||
52 | ctrl = uvc_find_control(video, query_menu->id, &mapping); | 52 | ctrl = uvc_find_control(chain, query_menu->id, &mapping); |
53 | if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) | 53 | if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) |
54 | return -EINVAL; | 54 | return -EINVAL; |
55 | 55 | ||
@@ -451,7 +451,7 @@ static int uvc_v4l2_open(struct file *file) | |||
451 | } | 451 | } |
452 | } | 452 | } |
453 | 453 | ||
454 | handle->video = &stream->dev->video; | 454 | handle->chain = stream->chain; |
455 | handle->stream = stream; | 455 | handle->stream = stream; |
456 | handle->state = UVC_HANDLE_PASSIVE; | 456 | handle->state = UVC_HANDLE_PASSIVE; |
457 | file->private_data = handle; | 457 | file->private_data = handle; |
@@ -498,7 +498,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
498 | { | 498 | { |
499 | struct video_device *vdev = video_devdata(file); | 499 | struct video_device *vdev = video_devdata(file); |
500 | struct uvc_fh *handle = (struct uvc_fh *)file->private_data; | 500 | struct uvc_fh *handle = (struct uvc_fh *)file->private_data; |
501 | struct uvc_video_device *video = handle->video; | 501 | struct uvc_video_chain *chain = handle->chain; |
502 | struct uvc_streaming *stream = handle->stream; | 502 | struct uvc_streaming *stream = handle->stream; |
503 | long ret = 0; | 503 | long ret = 0; |
504 | 504 | ||
@@ -525,7 +525,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
525 | 525 | ||
526 | /* Get, Set & Query control */ | 526 | /* Get, Set & Query control */ |
527 | case VIDIOC_QUERYCTRL: | 527 | case VIDIOC_QUERYCTRL: |
528 | return uvc_query_v4l2_ctrl(video, arg); | 528 | return uvc_query_v4l2_ctrl(chain, arg); |
529 | 529 | ||
530 | case VIDIOC_G_CTRL: | 530 | case VIDIOC_G_CTRL: |
531 | { | 531 | { |
@@ -535,12 +535,12 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
535 | memset(&xctrl, 0, sizeof xctrl); | 535 | memset(&xctrl, 0, sizeof xctrl); |
536 | xctrl.id = ctrl->id; | 536 | xctrl.id = ctrl->id; |
537 | 537 | ||
538 | ret = uvc_ctrl_begin(video); | 538 | ret = uvc_ctrl_begin(chain); |
539 | if (ret < 0) | 539 | if (ret < 0) |
540 | return ret; | 540 | return ret; |
541 | 541 | ||
542 | ret = uvc_ctrl_get(video, &xctrl); | 542 | ret = uvc_ctrl_get(chain, &xctrl); |
543 | uvc_ctrl_rollback(video); | 543 | uvc_ctrl_rollback(chain); |
544 | if (ret >= 0) | 544 | if (ret >= 0) |
545 | ctrl->value = xctrl.value; | 545 | ctrl->value = xctrl.value; |
546 | break; | 546 | break; |
@@ -555,21 +555,21 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
555 | xctrl.id = ctrl->id; | 555 | xctrl.id = ctrl->id; |
556 | xctrl.value = ctrl->value; | 556 | xctrl.value = ctrl->value; |
557 | 557 | ||
558 | ret = uvc_ctrl_begin(video); | 558 | uvc_ctrl_begin(chain); |
559 | if (ret < 0) | 559 | if (ret < 0) |
560 | return ret; | 560 | return ret; |
561 | 561 | ||
562 | ret = uvc_ctrl_set(video, &xctrl); | 562 | ret = uvc_ctrl_set(chain, &xctrl); |
563 | if (ret < 0) { | 563 | if (ret < 0) { |
564 | uvc_ctrl_rollback(video); | 564 | uvc_ctrl_rollback(chain); |
565 | return ret; | 565 | return ret; |
566 | } | 566 | } |
567 | ret = uvc_ctrl_commit(video); | 567 | ret = uvc_ctrl_commit(chain); |
568 | break; | 568 | break; |
569 | } | 569 | } |
570 | 570 | ||
571 | case VIDIOC_QUERYMENU: | 571 | case VIDIOC_QUERYMENU: |
572 | return uvc_v4l2_query_menu(video, arg); | 572 | return uvc_v4l2_query_menu(chain, arg); |
573 | 573 | ||
574 | case VIDIOC_G_EXT_CTRLS: | 574 | case VIDIOC_G_EXT_CTRLS: |
575 | { | 575 | { |
@@ -577,20 +577,20 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
577 | struct v4l2_ext_control *ctrl = ctrls->controls; | 577 | struct v4l2_ext_control *ctrl = ctrls->controls; |
578 | unsigned int i; | 578 | unsigned int i; |
579 | 579 | ||
580 | ret = uvc_ctrl_begin(video); | 580 | ret = uvc_ctrl_begin(chain); |
581 | if (ret < 0) | 581 | if (ret < 0) |
582 | return ret; | 582 | return ret; |
583 | 583 | ||
584 | for (i = 0; i < ctrls->count; ++ctrl, ++i) { | 584 | for (i = 0; i < ctrls->count; ++ctrl, ++i) { |
585 | ret = uvc_ctrl_get(video, ctrl); | 585 | ret = uvc_ctrl_get(chain, ctrl); |
586 | if (ret < 0) { | 586 | if (ret < 0) { |
587 | uvc_ctrl_rollback(video); | 587 | uvc_ctrl_rollback(chain); |
588 | ctrls->error_idx = i; | 588 | ctrls->error_idx = i; |
589 | return ret; | 589 | return ret; |
590 | } | 590 | } |
591 | } | 591 | } |
592 | ctrls->error_idx = 0; | 592 | ctrls->error_idx = 0; |
593 | ret = uvc_ctrl_rollback(video); | 593 | ret = uvc_ctrl_rollback(chain); |
594 | break; | 594 | break; |
595 | } | 595 | } |
596 | 596 | ||
@@ -601,14 +601,14 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
601 | struct v4l2_ext_control *ctrl = ctrls->controls; | 601 | struct v4l2_ext_control *ctrl = ctrls->controls; |
602 | unsigned int i; | 602 | unsigned int i; |
603 | 603 | ||
604 | ret = uvc_ctrl_begin(video); | 604 | ret = uvc_ctrl_begin(chain); |
605 | if (ret < 0) | 605 | if (ret < 0) |
606 | return ret; | 606 | return ret; |
607 | 607 | ||
608 | for (i = 0; i < ctrls->count; ++ctrl, ++i) { | 608 | for (i = 0; i < ctrls->count; ++ctrl, ++i) { |
609 | ret = uvc_ctrl_set(video, ctrl); | 609 | ret = uvc_ctrl_set(chain, ctrl); |
610 | if (ret < 0) { | 610 | if (ret < 0) { |
611 | uvc_ctrl_rollback(video); | 611 | uvc_ctrl_rollback(chain); |
612 | ctrls->error_idx = i; | 612 | ctrls->error_idx = i; |
613 | return ret; | 613 | return ret; |
614 | } | 614 | } |
@@ -617,31 +617,31 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
617 | ctrls->error_idx = 0; | 617 | ctrls->error_idx = 0; |
618 | 618 | ||
619 | if (cmd == VIDIOC_S_EXT_CTRLS) | 619 | if (cmd == VIDIOC_S_EXT_CTRLS) |
620 | ret = uvc_ctrl_commit(video); | 620 | ret = uvc_ctrl_commit(chain); |
621 | else | 621 | else |
622 | ret = uvc_ctrl_rollback(video); | 622 | ret = uvc_ctrl_rollback(chain); |
623 | break; | 623 | break; |
624 | } | 624 | } |
625 | 625 | ||
626 | /* Get, Set & Enum input */ | 626 | /* Get, Set & Enum input */ |
627 | case VIDIOC_ENUMINPUT: | 627 | case VIDIOC_ENUMINPUT: |
628 | { | 628 | { |
629 | const struct uvc_entity *selector = video->selector; | 629 | const struct uvc_entity *selector = chain->selector; |
630 | struct v4l2_input *input = arg; | 630 | struct v4l2_input *input = arg; |
631 | struct uvc_entity *iterm = NULL; | 631 | struct uvc_entity *iterm = NULL; |
632 | u32 index = input->index; | 632 | u32 index = input->index; |
633 | int pin = 0; | 633 | int pin = 0; |
634 | 634 | ||
635 | if (selector == NULL || | 635 | if (selector == NULL || |
636 | (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { | 636 | (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { |
637 | if (index != 0) | 637 | if (index != 0) |
638 | return -EINVAL; | 638 | return -EINVAL; |
639 | iterm = list_first_entry(&video->iterms, | 639 | iterm = list_first_entry(&chain->iterms, |
640 | struct uvc_entity, chain); | 640 | struct uvc_entity, chain); |
641 | pin = iterm->id; | 641 | pin = iterm->id; |
642 | } else if (pin < selector->selector.bNrInPins) { | 642 | } else if (pin < selector->selector.bNrInPins) { |
643 | pin = selector->selector.baSourceID[index]; | 643 | pin = selector->selector.baSourceID[index]; |
644 | list_for_each_entry(iterm, video->iterms.next, chain) { | 644 | list_for_each_entry(iterm, chain->iterms.next, chain) { |
645 | if (iterm->id == pin) | 645 | if (iterm->id == pin) |
646 | break; | 646 | break; |
647 | } | 647 | } |
@@ -662,14 +662,14 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
662 | { | 662 | { |
663 | u8 input; | 663 | u8 input; |
664 | 664 | ||
665 | if (video->selector == NULL || | 665 | if (chain->selector == NULL || |
666 | (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { | 666 | (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { |
667 | *(int *)arg = 0; | 667 | *(int *)arg = 0; |
668 | break; | 668 | break; |
669 | } | 669 | } |
670 | 670 | ||
671 | ret = uvc_query_ctrl(video->dev, UVC_GET_CUR, | 671 | ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, |
672 | video->selector->id, video->dev->intfnum, | 672 | chain->selector->id, chain->dev->intfnum, |
673 | UVC_SU_INPUT_SELECT_CONTROL, &input, 1); | 673 | UVC_SU_INPUT_SELECT_CONTROL, &input, 1); |
674 | if (ret < 0) | 674 | if (ret < 0) |
675 | return ret; | 675 | return ret; |
@@ -685,18 +685,18 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
685 | if ((ret = uvc_acquire_privileges(handle)) < 0) | 685 | if ((ret = uvc_acquire_privileges(handle)) < 0) |
686 | return ret; | 686 | return ret; |
687 | 687 | ||
688 | if (video->selector == NULL || | 688 | if (chain->selector == NULL || |
689 | (video->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { | 689 | (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) { |
690 | if (input != 1) | 690 | if (input != 1) |
691 | return -EINVAL; | 691 | return -EINVAL; |
692 | break; | 692 | break; |
693 | } | 693 | } |
694 | 694 | ||
695 | if (input == 0 || input > video->selector->selector.bNrInPins) | 695 | if (input == 0 || input > chain->selector->selector.bNrInPins) |
696 | return -EINVAL; | 696 | return -EINVAL; |
697 | 697 | ||
698 | return uvc_query_ctrl(video->dev, UVC_SET_CUR, | 698 | return uvc_query_ctrl(chain->dev, UVC_SET_CUR, |
699 | video->selector->id, video->dev->intfnum, | 699 | chain->selector->id, chain->dev->intfnum, |
700 | UVC_SU_INPUT_SELECT_CONTROL, &input, 1); | 700 | UVC_SU_INPUT_SELECT_CONTROL, &input, 1); |
701 | } | 701 | } |
702 | 702 | ||
@@ -1019,10 +1019,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
1019 | } | 1019 | } |
1020 | 1020 | ||
1021 | case UVCIOC_CTRL_GET: | 1021 | case UVCIOC_CTRL_GET: |
1022 | return uvc_xu_ctrl_query(video, arg, 0); | 1022 | return uvc_xu_ctrl_query(chain, arg, 0); |
1023 | 1023 | ||
1024 | case UVCIOC_CTRL_SET: | 1024 | case UVCIOC_CTRL_SET: |
1025 | return uvc_xu_ctrl_query(video, arg, 1); | 1025 | return uvc_xu_ctrl_query(chain, arg, 1); |
1026 | 1026 | ||
1027 | default: | 1027 | default: |
1028 | if ((ret = v4l_compat_translate_ioctl(file, cmd, arg, | 1028 | if ((ret = v4l_compat_translate_ioctl(file, cmd, arg, |
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index acbd73ac6bf4..5b757f32d997 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c | |||
@@ -128,7 +128,7 @@ static int uvc_get_video_ctrl(struct uvc_streaming *stream, | |||
128 | if (data == NULL) | 128 | if (data == NULL) |
129 | return -ENOMEM; | 129 | return -ENOMEM; |
130 | 130 | ||
131 | if ((video->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF) | 131 | if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) && query == UVC_GET_DEF) |
132 | return -EIO; | 132 | return -EIO; |
133 | 133 | ||
134 | ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum, | 134 | ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum, |
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 3cd9041e22a1..e7958aa454ce 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h | |||
@@ -80,9 +80,11 @@ struct uvc_xu_control { | |||
80 | #define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0) | 80 | #define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0) |
81 | #define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0) | 81 | #define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0) |
82 | #define UVC_ENTITY_IS_ITERM(entity) \ | 82 | #define UVC_ENTITY_IS_ITERM(entity) \ |
83 | (((entity)->type & 0x8000) == UVC_TERM_INPUT) | 83 | (UVC_ENTITY_IS_TERM(entity) && \ |
84 | ((entity)->type & 0x8000) == UVC_TERM_INPUT) | ||
84 | #define UVC_ENTITY_IS_OTERM(entity) \ | 85 | #define UVC_ENTITY_IS_OTERM(entity) \ |
85 | (((entity)->type & 0x8000) == UVC_TERM_OUTPUT) | 86 | (UVC_ENTITY_IS_TERM(entity) && \ |
87 | ((entity)->type & 0x8000) == UVC_TERM_OUTPUT) | ||
86 | 88 | ||
87 | 89 | ||
88 | /* ------------------------------------------------------------------------ | 90 | /* ------------------------------------------------------------------------ |
@@ -402,10 +404,24 @@ struct uvc_video_queue { | |||
402 | struct list_head irqqueue; | 404 | struct list_head irqqueue; |
403 | }; | 405 | }; |
404 | 406 | ||
407 | struct uvc_video_chain { | ||
408 | struct uvc_device *dev; | ||
409 | struct list_head list; | ||
410 | |||
411 | struct list_head iterms; /* Input terminals */ | ||
412 | struct list_head oterms; /* Output terminals */ | ||
413 | struct uvc_entity *processing; /* Processing unit */ | ||
414 | struct uvc_entity *selector; /* Selector unit */ | ||
415 | struct list_head extensions; /* Extension units */ | ||
416 | |||
417 | struct mutex ctrl_mutex; | ||
418 | }; | ||
419 | |||
405 | struct uvc_streaming { | 420 | struct uvc_streaming { |
406 | struct list_head list; | 421 | struct list_head list; |
407 | struct uvc_device *dev; | 422 | struct uvc_device *dev; |
408 | struct video_device *vdev; | 423 | struct video_device *vdev; |
424 | struct uvc_video_chain *chain; | ||
409 | atomic_t active; | 425 | atomic_t active; |
410 | 426 | ||
411 | struct usb_interface *intf; | 427 | struct usb_interface *intf; |
@@ -446,18 +462,6 @@ struct uvc_streaming { | |||
446 | __u8 last_fid; | 462 | __u8 last_fid; |
447 | }; | 463 | }; |
448 | 464 | ||
449 | struct uvc_video_device { | ||
450 | struct uvc_device *dev; | ||
451 | |||
452 | struct list_head iterms; /* Input terminals */ | ||
453 | struct uvc_entity *oterm; /* Output terminal */ | ||
454 | struct uvc_entity *sterm; /* USB streaming terminal */ | ||
455 | struct uvc_entity *processing; | ||
456 | struct uvc_entity *selector; | ||
457 | struct list_head extensions; | ||
458 | struct mutex ctrl_mutex; | ||
459 | }; | ||
460 | |||
461 | enum uvc_device_state { | 465 | enum uvc_device_state { |
462 | UVC_DEV_DISCONNECTED = 1, | 466 | UVC_DEV_DISCONNECTED = 1, |
463 | }; | 467 | }; |
@@ -480,8 +484,7 @@ struct uvc_device { | |||
480 | __u32 clock_frequency; | 484 | __u32 clock_frequency; |
481 | 485 | ||
482 | struct list_head entities; | 486 | struct list_head entities; |
483 | 487 | struct list_head chains; | |
484 | struct uvc_video_device video; | ||
485 | 488 | ||
486 | /* Video Streaming interfaces */ | 489 | /* Video Streaming interfaces */ |
487 | struct list_head streams; | 490 | struct list_head streams; |
@@ -500,7 +503,7 @@ enum uvc_handle_state { | |||
500 | }; | 503 | }; |
501 | 504 | ||
502 | struct uvc_fh { | 505 | struct uvc_fh { |
503 | struct uvc_video_device *video; | 506 | struct uvc_video_chain *chain; |
504 | struct uvc_streaming *stream; | 507 | struct uvc_streaming *stream; |
505 | enum uvc_handle_state state; | 508 | enum uvc_handle_state state; |
506 | }; | 509 | }; |
@@ -618,9 +621,9 @@ extern int uvc_status_suspend(struct uvc_device *dev); | |||
618 | extern int uvc_status_resume(struct uvc_device *dev); | 621 | extern int uvc_status_resume(struct uvc_device *dev); |
619 | 622 | ||
620 | /* Controls */ | 623 | /* Controls */ |
621 | extern struct uvc_control *uvc_find_control(struct uvc_video_device *video, | 624 | extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain, |
622 | __u32 v4l2_id, struct uvc_control_mapping **mapping); | 625 | __u32 v4l2_id, struct uvc_control_mapping **mapping); |
623 | extern int uvc_query_v4l2_ctrl(struct uvc_video_device *video, | 626 | extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, |
624 | struct v4l2_queryctrl *v4l2_ctrl); | 627 | struct v4l2_queryctrl *v4l2_ctrl); |
625 | 628 | ||
626 | extern int uvc_ctrl_add_info(struct uvc_control_info *info); | 629 | extern int uvc_ctrl_add_info(struct uvc_control_info *info); |
@@ -630,23 +633,23 @@ extern void uvc_ctrl_cleanup_device(struct uvc_device *dev); | |||
630 | extern int uvc_ctrl_resume_device(struct uvc_device *dev); | 633 | extern int uvc_ctrl_resume_device(struct uvc_device *dev); |
631 | extern void uvc_ctrl_init(void); | 634 | extern void uvc_ctrl_init(void); |
632 | 635 | ||
633 | extern int uvc_ctrl_begin(struct uvc_video_device *video); | 636 | extern int uvc_ctrl_begin(struct uvc_video_chain *chain); |
634 | extern int __uvc_ctrl_commit(struct uvc_video_device *video, int rollback); | 637 | extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback); |
635 | static inline int uvc_ctrl_commit(struct uvc_video_device *video) | 638 | static inline int uvc_ctrl_commit(struct uvc_video_chain *chain) |
636 | { | 639 | { |
637 | return __uvc_ctrl_commit(video, 0); | 640 | return __uvc_ctrl_commit(chain, 0); |
638 | } | 641 | } |
639 | static inline int uvc_ctrl_rollback(struct uvc_video_device *video) | 642 | static inline int uvc_ctrl_rollback(struct uvc_video_chain *chain) |
640 | { | 643 | { |
641 | return __uvc_ctrl_commit(video, 1); | 644 | return __uvc_ctrl_commit(chain, 1); |
642 | } | 645 | } |
643 | 646 | ||
644 | extern int uvc_ctrl_get(struct uvc_video_device *video, | 647 | extern int uvc_ctrl_get(struct uvc_video_chain *chain, |
645 | struct v4l2_ext_control *xctrl); | 648 | struct v4l2_ext_control *xctrl); |
646 | extern int uvc_ctrl_set(struct uvc_video_device *video, | 649 | extern int uvc_ctrl_set(struct uvc_video_chain *chain, |
647 | struct v4l2_ext_control *xctrl); | 650 | struct v4l2_ext_control *xctrl); |
648 | 651 | ||
649 | extern int uvc_xu_ctrl_query(struct uvc_video_device *video, | 652 | extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain, |
650 | struct uvc_xu_control *ctrl, int set); | 653 | struct uvc_xu_control *ctrl, int set); |
651 | 654 | ||
652 | /* Utility functions */ | 655 | /* Utility functions */ |