提交 3687e1e6 编写于 作者: M Mauro Carvalho Chehab

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: NMauro Carvalho Chehab <mchehab@infradead.org>
上级 92ea42f4
...@@ -72,7 +72,8 @@ u32 em28xx_request_buffers(struct em28xx *dev, u32 count) ...@@ -72,7 +72,8 @@ u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */ const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */
void *buff = NULL; void *buff = NULL;
u32 i; u32 i;
em28xx_coredbg("requested %i buffers with size %zi", count, imagesize); em28xx_coredbg("requested %i buffers with size %zi\n",
count, imagesize);
if (count > EM28XX_NUM_FRAMES) if (count > EM28XX_NUM_FRAMES)
count = EM28XX_NUM_FRAMES; count = EM28XX_NUM_FRAMES;
...@@ -676,7 +677,7 @@ static void em28xx_isocIrq(struct urb *urb) ...@@ -676,7 +677,7 @@ static void em28xx_isocIrq(struct urb *urb)
continue; continue;
} }
if (urb->iso_frame_desc[i].actual_length > if (urb->iso_frame_desc[i].actual_length >
dev->max_pkt_size) { urb->iso_frame_desc[i].length) {
em28xx_isocdbg("packet bigger than packet size"); em28xx_isocdbg("packet bigger than packet size");
continue; continue;
} }
...@@ -722,8 +723,11 @@ void em28xx_uninit_isoc(struct em28xx *dev) ...@@ -722,8 +723,11 @@ void em28xx_uninit_isoc(struct em28xx *dev)
for (i = 0; i < EM28XX_NUM_BUFS; i++) { for (i = 0; i < EM28XX_NUM_BUFS; i++) {
if (dev->urb[i]) { if (dev->urb[i]) {
usb_kill_urb(dev->urb[i]); usb_kill_urb(dev->urb[i]);
if (dev->transfer_buffer[i]){ if (dev->transfer_buffer[i]) {
usb_buffer_free(dev->udev,(EM28XX_NUM_PACKETS*dev->max_pkt_size),dev->transfer_buffer[i],dev->urb[i]->transfer_dma); usb_buffer_free(dev->udev,
dev->urb[i]->transfer_buffer_length,
dev->transfer_buffer[i],
dev->urb[i]->transfer_dma);
} }
usb_free_urb(dev->urb[i]); usb_free_urb(dev->urb[i]);
} }
...@@ -741,7 +745,10 @@ int em28xx_init_isoc(struct em28xx *dev) ...@@ -741,7 +745,10 @@ int em28xx_init_isoc(struct em28xx *dev)
{ {
/* change interface to 3 which allows the biggest packet sizes */ /* change interface to 3 which allows the biggest packet sizes */
int i, errCode; int i, errCode;
const int sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size; int sb_size;
em28xx_set_alternate(dev);
sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
/* reset streaming vars */ /* reset streaming vars */
dev->frame_current = NULL; dev->frame_current = NULL;
...@@ -750,7 +757,7 @@ int em28xx_init_isoc(struct em28xx *dev) ...@@ -750,7 +757,7 @@ int em28xx_init_isoc(struct em28xx *dev)
/* allocate urbs */ /* allocate urbs */
for (i = 0; i < EM28XX_NUM_BUFS; i++) { for (i = 0; i < EM28XX_NUM_BUFS; i++) {
struct urb *urb; struct urb *urb;
int j, k; int j;
/* allocate transfer buffer */ /* allocate transfer buffer */
urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL); urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
if (!urb){ if (!urb){
...@@ -758,7 +765,9 @@ int em28xx_init_isoc(struct em28xx *dev) ...@@ -758,7 +765,9 @@ int em28xx_init_isoc(struct em28xx *dev)
em28xx_uninit_isoc(dev); em28xx_uninit_isoc(dev);
return -ENOMEM; return -ENOMEM;
} }
dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,&urb->transfer_dma); dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size,
GFP_KERNEL,
&urb->transfer_dma);
if (!dev->transfer_buffer[i]) { if (!dev->transfer_buffer[i]) {
em28xx_errdev em28xx_errdev
("unable to allocate %i bytes for transfer buffer %i\n", ("unable to allocate %i bytes for transfer buffer %i\n",
...@@ -777,16 +786,16 @@ int em28xx_init_isoc(struct em28xx *dev) ...@@ -777,16 +786,16 @@ int em28xx_init_isoc(struct em28xx *dev)
urb->complete = em28xx_isocIrq; urb->complete = em28xx_isocIrq;
urb->number_of_packets = EM28XX_NUM_PACKETS; urb->number_of_packets = EM28XX_NUM_PACKETS;
urb->transfer_buffer_length = sb_size; urb->transfer_buffer_length = sb_size;
for (j = k = 0; j < EM28XX_NUM_PACKETS; for (j = 0; j < EM28XX_NUM_PACKETS; j++) {
j++, k += dev->max_pkt_size) { urb->iso_frame_desc[j].offset = j * dev->max_pkt_size;
urb->iso_frame_desc[j].offset = k; urb->iso_frame_desc[j].length = dev->max_pkt_size;
urb->iso_frame_desc[j].length =
dev->max_pkt_size;
} }
dev->urb[i] = urb; dev->urb[i] = urb;
} }
/* submit urbs */ /* submit urbs */
em28xx_coredbg("Submitting %d urbs of %d packets (%d each)\n",
EM28XX_NUM_BUFS, EM28XX_NUM_PACKETS, dev->max_pkt_size);
for (i = 0; i < EM28XX_NUM_BUFS; i++) { for (i = 0; i < EM28XX_NUM_BUFS; i++) {
errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL); errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
if (errCode) { if (errCode) {
...@@ -803,22 +812,31 @@ int em28xx_init_isoc(struct em28xx *dev) ...@@ -803,22 +812,31 @@ int em28xx_init_isoc(struct em28xx *dev)
int em28xx_set_alternate(struct em28xx *dev) int em28xx_set_alternate(struct em28xx *dev)
{ {
int errCode, prev_alt = dev->alt; int errCode, prev_alt = dev->alt;
dev->alt = alt; int i;
if (dev->alt == 0) { unsigned int min_pkt_size = dev->bytesperline+4;
int i;
for(i=0;i< dev->num_alt; i++) /* When image size is bigger than a ceirtain value,
if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt]) the frame size should be increased, otherwise, only
dev->alt=i; green screen will be received.
} */
if (dev->frame_size > 720*240*2)
min_pkt_size *= 2;
for (i = 0; i < dev->num_alt; i++)
if (dev->alt_max_pkt_size[i] >= min_pkt_size)
break;
dev->alt = i;
if (dev->alt != prev_alt) { if (dev->alt != prev_alt) {
em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
min_pkt_size, dev->alt);
dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt]; dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt, em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
dev->max_pkt_size); dev->alt, dev->max_pkt_size);
errCode = usb_set_interface(dev->udev, 0, dev->alt); errCode = usb_set_interface(dev->udev, 0, dev->alt);
if (errCode < 0) { if (errCode < 0) {
em28xx_errdev ("cannot change alternate number to %d (error=%i)\n", em28xx_errdev ("cannot change alternate number to %d (error=%i)\n",
dev->alt, errCode); dev->alt, errCode);
return errCode; return errCode;
} }
} }
......
...@@ -1352,8 +1352,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) ...@@ -1352,8 +1352,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
filp->private_data = fh; filp->private_data = fh;
if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
em28xx_set_alternate(dev);
dev->width = norm_maxw(dev); dev->width = norm_maxw(dev);
dev->height = norm_maxh(dev); dev->height = norm_maxh(dev);
dev->frame_size = dev->width * dev->height * 2; dev->frame_size = dev->width * dev->height * 2;
...@@ -1362,6 +1360,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) ...@@ -1362,6 +1360,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
dev->hscale = 0; dev->hscale = 0;
dev->vscale = 0; dev->vscale = 0;
em28xx_set_alternate(dev);
em28xx_capture_start(dev, 1); em28xx_capture_start(dev, 1);
em28xx_resolution_set(dev); em28xx_resolution_set(dev);
...@@ -2129,6 +2128,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, ...@@ -2129,6 +2128,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
snprintf(dev->name, 29, "em28xx #%d", nr); snprintf(dev->name, 29, "em28xx #%d", nr);
dev->devno = nr; dev->devno = nr;
dev->model = id->driver_info; dev->model = id->driver_info;
dev->alt = -1;
/* Checks if audio is provided by some interface */ /* Checks if audio is provided by some interface */
for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#define UNSET -1 #define UNSET -1
/* maximum number of em28xx boards */ /* maximum number of em28xx boards */
#define EM28XX_MAXBOARDS 1 /*FIXME: should be bigger */ #define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
/* maximum number of frames that can be queued */ /* maximum number of frames that can be queued */
#define EM28XX_NUM_FRAMES 5 #define EM28XX_NUM_FRAMES 5
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册