diff options
author | Frank Schaefer <fschaefer.oss@googlemail.com> | 2013-02-07 11:32:46 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-02-11 15:17:44 -0500 |
commit | 33f6984ecefb9b84f1b4d1d3b9022731bb8b62d0 (patch) | |
tree | 52b7d2df6ef5ea77c927aa6c3379ac5ebd63f491 /drivers/media | |
parent | 4880f56438ef56457edd5548b257382761591998 (diff) |
[media] em28xx: fix analog streaming with USB bulk transfers
With the conversion to videobuf2, some unnecessary calls of
em28xx_set_alternate() have been removed. It is now called at analog streaming
start only.
This has unveiled a bug that causes USB bulk transfers to fail with all urbs
having status -EVOERFLOW.
The reason is, that for bulk transfers usb_set_interface() needs to be called
even if the previous alt setting was the same (side note: bulk transfers seem
to work only with alt=0).
While it seems to be NOT necessary for isoc transfers, it's reasonable to just
call usb_set_interface() unconditionally in em28xx_set_alternate().
Also add a comment that explains the issue to prevent regressions in the future.
Cc: stable@vger.kernel.org # for 3.8
Signed-off-by: Frank Schäfer <fschaefer.oss@googlemail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/usb/em28xx/em28xx-core.c | 43 |
1 files changed, 22 insertions, 21 deletions
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index ee00f9e23420..aaedd11791f2 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c | |||
@@ -813,12 +813,12 @@ int em28xx_resolution_set(struct em28xx *dev) | |||
813 | /* Set USB alternate setting for analog video */ | 813 | /* Set USB alternate setting for analog video */ |
814 | int em28xx_set_alternate(struct em28xx *dev) | 814 | int em28xx_set_alternate(struct em28xx *dev) |
815 | { | 815 | { |
816 | int errCode, prev_alt = dev->alt; | 816 | int errCode; |
817 | int i; | 817 | int i; |
818 | unsigned int min_pkt_size = dev->width * 2 + 4; | 818 | unsigned int min_pkt_size = dev->width * 2 + 4; |
819 | 819 | ||
820 | /* NOTE: for isoc transfers, only alt settings > 0 are allowed | 820 | /* NOTE: for isoc transfers, only alt settings > 0 are allowed |
821 | for bulk transfers, use alt=0 as default value */ | 821 | bulk transfers seem to work only with alt=0 ! */ |
822 | dev->alt = 0; | 822 | dev->alt = 0; |
823 | if ((alt > 0) && (alt < dev->num_alt)) { | 823 | if ((alt > 0) && (alt < dev->num_alt)) { |
824 | em28xx_coredbg("alternate forced to %d\n", dev->alt); | 824 | em28xx_coredbg("alternate forced to %d\n", dev->alt); |
@@ -849,25 +849,26 @@ int em28xx_set_alternate(struct em28xx *dev) | |||
849 | } | 849 | } |
850 | 850 | ||
851 | set_alt: | 851 | set_alt: |
852 | if (dev->alt != prev_alt) { | 852 | /* NOTE: for bulk transfers, we need to call usb_set_interface() |
853 | if (dev->analog_xfer_bulk) { | 853 | * even if the previous settings were the same. Otherwise streaming |
854 | dev->max_pkt_size = 512; /* USB 2.0 spec */ | 854 | * fails with all urbs having status = -EOVERFLOW ! */ |
855 | dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER; | 855 | if (dev->analog_xfer_bulk) { |
856 | } else { /* isoc */ | 856 | dev->max_pkt_size = 512; /* USB 2.0 spec */ |
857 | em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n", | 857 | dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER; |
858 | min_pkt_size, dev->alt); | 858 | } else { /* isoc */ |
859 | dev->max_pkt_size = | 859 | em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n", |
860 | dev->alt_max_pkt_size_isoc[dev->alt]; | 860 | min_pkt_size, dev->alt); |
861 | dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS; | 861 | dev->max_pkt_size = |
862 | } | 862 | dev->alt_max_pkt_size_isoc[dev->alt]; |
863 | em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", | 863 | dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS; |
864 | dev->alt, dev->max_pkt_size); | 864 | } |
865 | errCode = usb_set_interface(dev->udev, 0, dev->alt); | 865 | em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", |
866 | if (errCode < 0) { | 866 | dev->alt, dev->max_pkt_size); |
867 | em28xx_errdev("cannot change alternate number to %d (error=%i)\n", | 867 | errCode = usb_set_interface(dev->udev, 0, dev->alt); |
868 | dev->alt, errCode); | 868 | if (errCode < 0) { |
869 | return errCode; | 869 | em28xx_errdev("cannot change alternate number to %d (error=%i)\n", |
870 | } | 870 | dev->alt, errCode); |
871 | return errCode; | ||
871 | } | 872 | } |
872 | return 0; | 873 | return 0; |
873 | } | 874 | } |