Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

V4L/DVB (7179): Allow more than one em28xx board

em28xx driver is capable of handling more than one usb device. However, isoc
transfers require a large amount of data to be transfered.

Before this patch, just one em28xx board were enough to allocate more than 50%
URBs:

T: Bus=02 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=480 MxCh= 8
B: Alloc=480/800 us (60%), #Int= 0, #Iso= 2
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=01 MxPS=64 #Cfgs= 1

So, only one board could use an USB host at the same time. After the patch, it
is possible to use more than one em28xx at the same time, on the same usb host,
if the image size is slower or equal to 345600, since those images will
require about 30% of the URBs:

T: Bus=02 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=480 MxCh= 8
B: Alloc=232/800 us (29%), #Int= 0, #Iso= 2
D: Ver= 2.00 Cls=09(hub ) Sub=00 Prot=01 MxPS=64 #Cfgs= 1

So, in thesis, after the patch, it would be possible to use up to 3 boards by
each usb host, if the devices are generating small images.

Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>

+43 -25
+40 -22
drivers/media/video/em28xx/em28xx-core.c
··· 72 72 const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */ 73 73 void *buff = NULL; 74 74 u32 i; 75 - em28xx_coredbg("requested %i buffers with size %zi", count, imagesize); 75 + em28xx_coredbg("requested %i buffers with size %zi\n", 76 + count, imagesize); 76 77 if (count > EM28XX_NUM_FRAMES) 77 78 count = EM28XX_NUM_FRAMES; 78 79 ··· 677 676 continue; 678 677 } 679 678 if (urb->iso_frame_desc[i].actual_length > 680 - dev->max_pkt_size) { 679 + urb->iso_frame_desc[i].length) { 681 680 em28xx_isocdbg("packet bigger than packet size"); 682 681 continue; 683 682 } ··· 723 722 for (i = 0; i < EM28XX_NUM_BUFS; i++) { 724 723 if (dev->urb[i]) { 725 724 usb_kill_urb(dev->urb[i]); 726 - if (dev->transfer_buffer[i]){ 727 - usb_buffer_free(dev->udev,(EM28XX_NUM_PACKETS*dev->max_pkt_size),dev->transfer_buffer[i],dev->urb[i]->transfer_dma); 725 + if (dev->transfer_buffer[i]) { 726 + usb_buffer_free(dev->udev, 727 + dev->urb[i]->transfer_buffer_length, 728 + dev->transfer_buffer[i], 729 + dev->urb[i]->transfer_dma); 728 730 } 729 731 usb_free_urb(dev->urb[i]); 730 732 } ··· 745 741 { 746 742 /* change interface to 3 which allows the biggest packet sizes */ 747 743 int i, errCode; 748 - const int sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size; 744 + int sb_size; 745 + 746 + em28xx_set_alternate(dev); 747 + sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size; 749 748 750 749 /* reset streaming vars */ 751 750 dev->frame_current = NULL; ··· 757 750 /* allocate urbs */ 758 751 for (i = 0; i < EM28XX_NUM_BUFS; i++) { 759 752 struct urb *urb; 760 - int j, k; 753 + int j; 761 754 /* allocate transfer buffer */ 762 755 urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL); 763 756 if (!urb){ ··· 765 758 em28xx_uninit_isoc(dev); 766 759 return -ENOMEM; 767 760 } 768 - dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,&urb->transfer_dma); 761 + dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, 762 + GFP_KERNEL, 763 + &urb->transfer_dma); 769 764 if (!dev->transfer_buffer[i]) { 770 765 em28xx_errdev 771 766 ("unable to allocate %i bytes for transfer buffer %i\n", ··· 786 777 urb->complete = em28xx_isocIrq; 787 778 urb->number_of_packets = EM28XX_NUM_PACKETS; 788 779 urb->transfer_buffer_length = sb_size; 789 - for (j = k = 0; j < EM28XX_NUM_PACKETS; 790 - j++, k += dev->max_pkt_size) { 791 - urb->iso_frame_desc[j].offset = k; 792 - urb->iso_frame_desc[j].length = 793 - dev->max_pkt_size; 780 + for (j = 0; j < EM28XX_NUM_PACKETS; j++) { 781 + urb->iso_frame_desc[j].offset = j * dev->max_pkt_size; 782 + urb->iso_frame_desc[j].length = dev->max_pkt_size; 794 783 } 795 784 dev->urb[i] = urb; 796 785 } 797 786 798 787 /* submit urbs */ 788 + em28xx_coredbg("Submitting %d urbs of %d packets (%d each)\n", 789 + EM28XX_NUM_BUFS, EM28XX_NUM_PACKETS, dev->max_pkt_size); 799 790 for (i = 0; i < EM28XX_NUM_BUFS; i++) { 800 791 errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL); 801 792 if (errCode) { ··· 812 803 int em28xx_set_alternate(struct em28xx *dev) 813 804 { 814 805 int errCode, prev_alt = dev->alt; 815 - dev->alt = alt; 816 - if (dev->alt == 0) { 817 - int i; 818 - for(i=0;i< dev->num_alt; i++) 819 - if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt]) 820 - dev->alt=i; 821 - } 806 + int i; 807 + unsigned int min_pkt_size = dev->bytesperline+4; 808 + 809 + /* When image size is bigger than a ceirtain value, 810 + the frame size should be increased, otherwise, only 811 + green screen will be received. 812 + */ 813 + if (dev->frame_size > 720*240*2) 814 + min_pkt_size *= 2; 815 + 816 + for (i = 0; i < dev->num_alt; i++) 817 + if (dev->alt_max_pkt_size[i] >= min_pkt_size) 818 + break; 819 + dev->alt = i; 822 820 823 821 if (dev->alt != prev_alt) { 822 + em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n", 823 + min_pkt_size, dev->alt); 824 824 dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt]; 825 - em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt, 826 - dev->max_pkt_size); 825 + em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", 826 + dev->alt, dev->max_pkt_size); 827 827 errCode = usb_set_interface(dev->udev, 0, dev->alt); 828 828 if (errCode < 0) { 829 829 em28xx_errdev ("cannot change alternate number to %d (error=%i)\n", 830 - dev->alt, errCode); 830 + dev->alt, errCode); 831 831 return errCode; 832 832 } 833 833 }
+2 -2
drivers/media/video/em28xx/em28xx-video.c
··· 1352 1352 filp->private_data = fh; 1353 1353 1354 1354 if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { 1355 - em28xx_set_alternate(dev); 1356 - 1357 1355 dev->width = norm_maxw(dev); 1358 1356 dev->height = norm_maxh(dev); 1359 1357 dev->frame_size = dev->width * dev->height * 2; ··· 1360 1362 dev->hscale = 0; 1361 1363 dev->vscale = 0; 1362 1364 1365 + em28xx_set_alternate(dev); 1363 1366 em28xx_capture_start(dev, 1); 1364 1367 em28xx_resolution_set(dev); 1365 1368 ··· 2128 2129 snprintf(dev->name, 29, "em28xx #%d", nr); 2129 2130 dev->devno = nr; 2130 2131 dev->model = id->driver_info; 2132 + dev->alt = -1; 2131 2133 2132 2134 /* Checks if audio is provided by some interface */ 2133 2135 for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
+1 -1
drivers/media/video/em28xx/em28xx.h
··· 33 33 #define UNSET -1 34 34 35 35 /* maximum number of em28xx boards */ 36 - #define EM28XX_MAXBOARDS 1 /*FIXME: should be bigger */ 36 + #define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */ 37 37 38 38 /* maximum number of frames that can be queued */ 39 39 #define EM28XX_NUM_FRAMES 5