Skip to content

Commit

Permalink
V4L/DVB (7179): Allow more than one em28xx board
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mauro Carvalho Chehab committed Feb 18, 2008
1 parent 92ea42f commit 3687e1e
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 25 deletions.
62 changes: 40 additions & 22 deletions drivers/media/video/em28xx/em28xx-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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! */
void *buff = NULL;
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)
count = EM28XX_NUM_FRAMES;

Expand Down Expand Up @@ -676,7 +677,7 @@ static void em28xx_isocIrq(struct urb *urb)
continue;
}
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");
continue;
}
Expand Down Expand Up @@ -722,8 +723,11 @@ void em28xx_uninit_isoc(struct em28xx *dev)
for (i = 0; i < EM28XX_NUM_BUFS; i++) {
if (dev->urb[i]) {
usb_kill_urb(dev->urb[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);
if (dev->transfer_buffer[i]) {
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]);
}
Expand All @@ -741,7 +745,10 @@ int em28xx_init_isoc(struct em28xx *dev)
{
/* change interface to 3 which allows the biggest packet sizes */
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 */
dev->frame_current = NULL;
Expand All @@ -750,15 +757,17 @@ int em28xx_init_isoc(struct em28xx *dev)
/* allocate urbs */
for (i = 0; i < EM28XX_NUM_BUFS; i++) {
struct urb *urb;
int j, k;
int j;
/* allocate transfer buffer */
urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
if (!urb){
em28xx_errdev("cannot alloc urb %i\n", i);
em28xx_uninit_isoc(dev);
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]) {
em28xx_errdev
("unable to allocate %i bytes for transfer buffer %i\n",
Expand All @@ -777,16 +786,16 @@ int em28xx_init_isoc(struct em28xx *dev)
urb->complete = em28xx_isocIrq;
urb->number_of_packets = EM28XX_NUM_PACKETS;
urb->transfer_buffer_length = sb_size;
for (j = k = 0; j < EM28XX_NUM_PACKETS;
j++, k += dev->max_pkt_size) {
urb->iso_frame_desc[j].offset = k;
urb->iso_frame_desc[j].length =
dev->max_pkt_size;
for (j = 0; j < EM28XX_NUM_PACKETS; j++) {
urb->iso_frame_desc[j].offset = j * dev->max_pkt_size;
urb->iso_frame_desc[j].length = dev->max_pkt_size;
}
dev->urb[i] = urb;
}

/* 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++) {
errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
if (errCode) {
Expand All @@ -803,22 +812,31 @@ int em28xx_init_isoc(struct em28xx *dev)
int em28xx_set_alternate(struct em28xx *dev)
{
int errCode, prev_alt = dev->alt;
dev->alt = alt;
if (dev->alt == 0) {
int i;
for(i=0;i< dev->num_alt; i++)
if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt])
dev->alt=i;
}
int i;
unsigned int min_pkt_size = dev->bytesperline+4;

/* When image size is bigger than a ceirtain value,
the frame size should be increased, otherwise, only
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) {
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];
em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt,
dev->max_pkt_size);
em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
dev->alt, dev->max_pkt_size);
errCode = usb_set_interface(dev->udev, 0, dev->alt);
if (errCode < 0) {
em28xx_errdev ("cannot change alternate number to %d (error=%i)\n",
dev->alt, errCode);
dev->alt, errCode);
return errCode;
}
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/media/video/em28xx/em28xx-video.c
Original file line number Diff line number Diff line change
Expand Up @@ -1352,8 +1352,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
filp->private_data = fh;

if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
em28xx_set_alternate(dev);

dev->width = norm_maxw(dev);
dev->height = norm_maxh(dev);
dev->frame_size = dev->width * dev->height * 2;
Expand All @@ -1362,6 +1360,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
dev->hscale = 0;
dev->vscale = 0;

em28xx_set_alternate(dev);
em28xx_capture_start(dev, 1);
em28xx_resolution_set(dev);

Expand Down Expand Up @@ -2129,6 +2128,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
snprintf(dev->name, 29, "em28xx #%d", nr);
dev->devno = nr;
dev->model = id->driver_info;
dev->alt = -1;

/* Checks if audio is provided by some interface */
for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/media/video/em28xx/em28xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
#define UNSET -1

/* 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 */
#define EM28XX_NUM_FRAMES 5
Expand Down

0 comments on commit 3687e1e

Please sign in to comment.