aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/uvc
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart@ideasonboard.com>2009-12-10 19:19:31 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-01-17 08:31:35 -0500
commit2c4d9de8ab1434336248bbc01ee8e64d7e6b8a4f (patch)
treeda367e3956a35c54636ef2ff3e060fc17ff64a25 /drivers/media/video/uvc
parent385097e08b9c24655626ed760bc67eb7e50115a0 (diff)
V4L/DVB (13829): uvcvideo: Fix alternate setting selection in isochronous mode
Unlike assumed by the driver, alternate settings are not sorted by endpoint max packet size. Iterate over all alternate settings to find the one with the smallest compatible max packet size. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/uvc')
-rw-r--r--drivers/media/video/uvc/uvc_video.c31
1 files changed, 22 insertions, 9 deletions
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 9a9802830d41..e8cc0a9ddadd 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -924,10 +924,8 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
924static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) 924static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
925{ 925{
926 struct usb_interface *intf = stream->intf; 926 struct usb_interface *intf = stream->intf;
927 struct usb_host_interface *alts; 927 struct usb_host_endpoint *ep;
928 struct usb_host_endpoint *ep = NULL; 928 unsigned int i;
929 int intfnum = stream->intfnum;
930 unsigned int bandwidth, psize, i;
931 int ret; 929 int ret;
932 930
933 stream->last_fid = -1; 931 stream->last_fid = -1;
@@ -936,6 +934,12 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
936 stream->bulk.payload_size = 0; 934 stream->bulk.payload_size = 0;
937 935
938 if (intf->num_altsetting > 1) { 936 if (intf->num_altsetting > 1) {
937 struct usb_host_endpoint *best_ep = NULL;
938 unsigned int best_psize = 3 * 1024;
939 unsigned int bandwidth;
940 unsigned int uninitialized_var(altsetting);
941 int intfnum = stream->intfnum;
942
939 /* Isochronous endpoint, select the alternate setting. */ 943 /* Isochronous endpoint, select the alternate setting. */
940 bandwidth = stream->ctrl.dwMaxPayloadTransferSize; 944 bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
941 945
@@ -949,6 +953,9 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
949 } 953 }
950 954
951 for (i = 0; i < intf->num_altsetting; ++i) { 955 for (i = 0; i < intf->num_altsetting; ++i) {
956 struct usb_host_interface *alts;
957 unsigned int psize;
958
952 alts = &intf->altsetting[i]; 959 alts = &intf->altsetting[i];
953 ep = uvc_find_endpoint(alts, 960 ep = uvc_find_endpoint(alts,
954 stream->header.bEndpointAddress); 961 stream->header.bEndpointAddress);
@@ -958,21 +965,27 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
958 /* Check if the bandwidth is high enough. */ 965 /* Check if the bandwidth is high enough. */
959 psize = le16_to_cpu(ep->desc.wMaxPacketSize); 966 psize = le16_to_cpu(ep->desc.wMaxPacketSize);
960 psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); 967 psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
961 if (psize >= bandwidth) 968 if (psize >= bandwidth && psize <= best_psize) {
962 break; 969 altsetting = i;
970 best_psize = psize;
971 best_ep = ep;
972 }
963 } 973 }
964 974
965 if (i >= intf->num_altsetting) { 975 if (best_ep == NULL) {
966 uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting " 976 uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting "
967 "for requested bandwidth.\n"); 977 "for requested bandwidth.\n");
968 return -EIO; 978 return -EIO;
969 } 979 }
970 980
971 ret = usb_set_interface(stream->dev->udev, intfnum, i); 981 uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u "
982 "(%u B/frame bandwidth).\n", altsetting, best_psize);
983
984 ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
972 if (ret < 0) 985 if (ret < 0)
973 return ret; 986 return ret;
974 987
975 ret = uvc_init_video_isoc(stream, ep, gfp_flags); 988 ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);
976 } else { 989 } else {
977 /* Bulk endpoint, proceed to URB initialization. */ 990 /* Bulk endpoint, proceed to URB initialization. */
978 ep = uvc_find_endpoint(&intf->altsetting[0], 991 ep = uvc_find_endpoint(&intf->altsetting[0],