Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 271899
b: refs/heads/master
c: 27b1202
h: refs/heads/master
i:
  271897: bbe15e5
  271895: b9e2329
v: v3
  • Loading branch information
Jean-François Moine authored and Mauro Carvalho Chehab committed Sep 24, 2011
1 parent c5a70cd commit 1eba25b
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 61 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 2d06d5dd2d945780f24169af0ac86e1e03ffee19
refs/heads/master: 27b12023d72207b2d0b38bb9ef4fdb0a3325b682
211 changes: 151 additions & 60 deletions trunk/drivers/media/video/gspca/gspca.c
Original file line number Diff line number Diff line change
Expand Up @@ -629,53 +629,104 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
return NULL;
}

/* compute the minimum bandwidth for the current transfer */
static u32 which_bandwidth(struct gspca_dev *gspca_dev)
{
u32 bandwidth;
int i;

i = gspca_dev->curr_mode;
bandwidth = gspca_dev->cam.cam_mode[i].sizeimage;

/* if the image is compressed, estimate the mean image size */
if (bandwidth < gspca_dev->cam.cam_mode[i].width *
gspca_dev->cam.cam_mode[i].height)
bandwidth /= 3;

/* estimate the frame rate */
if (gspca_dev->sd_desc->get_streamparm) {
struct v4l2_streamparm parm;

parm.parm.capture.timeperframe.denominator = 15;
gspca_dev->sd_desc->get_streamparm(gspca_dev, &parm);
bandwidth *= parm.parm.capture.timeperframe.denominator;
} else {
bandwidth *= 15; /* 15 fps */
}

PDEBUG(D_STREAM, "min bandwidth: %d", bandwidth);
return bandwidth;
}

/* endpoint table */
#define MAX_ALT 16
struct ep_tb_s {
u32 alt;
u32 bandwidth;
};

/*
* look for an input (isoc or bulk) endpoint
*
* The endpoint is defined by the subdriver.
* Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep).
* This routine may be called many times when the bandwidth is too small
* (the bandwidth is checked on urb submit).
* build the table of the endpoints
* and compute the minimum bandwidth for the image transfer
*/
static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
static int build_ep_tb(struct gspca_dev *gspca_dev,
struct usb_interface *intf,
int xfer,
struct ep_tb_s *ep_tb)
{
struct usb_interface *intf;
struct usb_host_endpoint *ep;
int xfer, i, ret;
int i, j, nbalt, psize, found;
u32 bandwidth, last_bw;

intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
ep = NULL;
xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
: USB_ENDPOINT_XFER_ISOC;
i = gspca_dev->alt; /* previous alt setting */
if (gspca_dev->cam.reverse_alts) {
while (++i < gspca_dev->nbalt) {
ep = alt_xfer(&intf->altsetting[i], xfer);
if (ep)
break;
}
} else {
while (--i >= 0) {
ep = alt_xfer(&intf->altsetting[i], xfer);
if (ep)
break;
}
}
if (ep == NULL) {
pr_err("no transfer endpoint found\n");
return NULL;
}
PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
i, ep->desc.bEndpointAddress);
gspca_dev->alt = i; /* memorize the current alt setting */
if (gspca_dev->nbalt > 1) {
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
if (ret < 0) {
pr_err("set alt %d err %d\n", i, ret);
ep = NULL;
nbalt = intf->num_altsetting;
if (nbalt > MAX_ALT)
nbalt = MAX_ALT; /* fixme: should warn */

/* build the endpoint table */
i = 0;
last_bw = 0;
for (;;) {
ep_tb->bandwidth = 2000 * 2000 * 120;
found = 0;
for (j = 0; j < nbalt; j++) {
ep = alt_xfer(&intf->altsetting[j], xfer);
if (ep == NULL)
continue;
psize = le16_to_cpu(ep->desc.wMaxPacketSize);
if (!gspca_dev->cam.bulk) /* isoc */
psize = (psize & 0x07ff) *
(1 + ((psize >> 11) & 3));
bandwidth = psize * ep->desc.bInterval * 1000;
if (gspca_dev->dev->speed == USB_SPEED_HIGH
|| gspca_dev->dev->speed == USB_SPEED_SUPER)
bandwidth *= 8;
if (bandwidth <= last_bw)
continue;
if (bandwidth < ep_tb->bandwidth) {
ep_tb->bandwidth = bandwidth;
ep_tb->alt = j;
found = 1;
}
}
if (!found)
break;
PDEBUG(D_STREAM, "alt %d bandwidth %d",
ep_tb->alt, ep_tb->bandwidth);
last_bw = ep_tb->bandwidth;
i++;
ep_tb++;
}

/* get the requested bandwidth and start at the highest atlsetting */
bandwidth = which_bandwidth(gspca_dev);
ep_tb--;
while (i > 1) {
ep_tb--;
if (ep_tb->bandwidth < bandwidth)
break;
i--;
}
return ep;
return i;
}

/*
Expand Down Expand Up @@ -766,9 +817,11 @@ static int create_urbs(struct gspca_dev *gspca_dev,
*/
static int gspca_init_transfer(struct gspca_dev *gspca_dev)
{
struct usb_interface *intf;
struct usb_host_endpoint *ep;
struct urb *urb;
int n, ret;
struct ep_tb_s ep_tb[MAX_ALT];
int n, ret, xfer, alt, alt_idx;

if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
Expand All @@ -786,30 +839,63 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)

gspca_dev->usb_err = 0;

/* set the higher alternate setting and
* loop until urb submit succeeds */
if (gspca_dev->cam.reverse_alts)
gspca_dev->alt = 0;
else
gspca_dev->alt = gspca_dev->nbalt;

/* do the specific subdriver stuff before endpoint selection */
gspca_dev->alt = 0;
if (gspca_dev->sd_desc->isoc_init) {
ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
if (ret < 0)
goto unlock;
}
intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
: USB_ENDPOINT_XFER_ISOC;

gspca_input_destroy_urb(gspca_dev);
ep = get_ep(gspca_dev);
if (ep == NULL) {
ret = -EIO;
goto out;
/* if the subdriver forced an altsetting, get the endpoint */
if (gspca_dev->alt != 0) {
gspca_dev->alt--; /* (previous version compatibility) */
ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer);
if (ep == NULL) {
pr_err("bad altsetting %d\n", gspca_dev->alt);
ret = -EIO;
goto out;
}
ep_tb[0].alt = gspca_dev->alt;
alt_idx = 1;
} else {

/* else, compute the minimum bandwidth
* and build the endpoint table */
alt_idx = build_ep_tb(gspca_dev, intf, xfer, ep_tb);
if (alt_idx <= 0) {
pr_err("no transfer endpoint found\n");
ret = -EIO;
goto unlock;
}
}

/* set the highest alternate setting and
* loop until urb submit succeeds */
gspca_input_destroy_urb(gspca_dev);

gspca_dev->alt = ep_tb[--alt_idx].alt;
alt = -1;
for (;;) {
if (alt != gspca_dev->alt) {
alt = gspca_dev->alt;
if (gspca_dev->nbalt > 1) {
ret = usb_set_interface(gspca_dev->dev,
gspca_dev->iface,
alt);
if (ret < 0) {
pr_err("set alt %d err %d\n", alt, ret);
goto out;
}
}
}
if (!gspca_dev->cam.no_urb_create) {
PDEBUG(D_STREAM, "init transfer alt %d",
gspca_dev->alt);
ret = create_urbs(gspca_dev, ep);
PDEBUG(D_STREAM, "init transfer alt %d", alt);
ret = create_urbs(gspca_dev,
alt_xfer(&intf->altsetting[alt], xfer));
if (ret < 0) {
destroy_urbs(gspca_dev);
goto out;
Expand Down Expand Up @@ -843,7 +929,10 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
break;
}
if (ret >= 0)
break;
break; /* transfer is started */

/* something when wrong
* stop the webcam and free the transfer resources */
gspca_stream_off(gspca_dev);
if (ret != -ENOSPC) {
pr_err("usb_submit_urb alt %d err %d\n",
Expand All @@ -854,18 +943,20 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* the bandwidth is not wide enough
* negotiate or try a lower alternate setting */
PDEBUG(D_ERR|D_STREAM,
"bandwidth not wide enough - trying again");
"alt %d - bandwidth not wide enough - trying again",
alt);
msleep(20); /* wait for kill complete */
if (gspca_dev->sd_desc->isoc_nego) {
ret = gspca_dev->sd_desc->isoc_nego(gspca_dev);
if (ret < 0)
goto out;
} else {
ep = get_ep(gspca_dev);
if (ep == NULL) {
if (alt_idx <= 0) {
pr_err("no transfer endpoint found\n");
ret = -EIO;
goto out;
}
alt = ep_tb[--alt_idx].alt;
}
}
out:
Expand Down

0 comments on commit 1eba25b

Please sign in to comment.