提交 1f53b0b0 编写于 作者: J Jean-Francois Moine 提交者: Mauro Carvalho Chehab

V4L/DVB (12229): gspca - main: Change the ISOC initialization mechanism.

- call a new subdriver function 'isoc_init' before chosing the first
  alternate setting.
- call a new subdriver function 'isoc_nego' when submitting the URBs failed.
Signed-off-by: NJean-Francois Moine <moinejf@free.fr>
Signed-off-by: NMauro Carvalho Chehab <mchehab@redhat.com>
上级 1852e75a
......@@ -512,7 +512,10 @@ static int create_urbs(struct gspca_dev *gspca_dev,
if (!gspca_dev->cam.bulk) { /* isoc */
/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
if (gspca_dev->pkt_size == 0)
psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
else
psize = gspca_dev->pkt_size;
npkt = gspca_dev->cam.npkt;
if (npkt == 0)
npkt = 32; /* default value */
......@@ -597,13 +600,18 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* set the higher alternate setting and
* loop until urb submit succeeds */
gspca_dev->alt = gspca_dev->nbalt;
for (;;) {
PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
if (gspca_dev->sd_desc->isoc_init) {
ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
if (ret < 0)
goto out;
}
ep = get_ep(gspca_dev);
if (ep == NULL) {
ret = -EIO;
goto out;
}
for (;;) {
PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
ret = create_urbs(gspca_dev, ep);
if (ret < 0)
goto out;
......@@ -628,21 +636,32 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* submit the URBs */
for (n = 0; n < gspca_dev->nurbs; n++) {
ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
if (ret < 0) {
if (ret < 0)
break;
}
if (ret >= 0)
break;
PDEBUG(D_ERR|D_STREAM,
"usb_submit_urb [%d] err %d", n, ret);
"usb_submit_urb alt %d err %d", gspca_dev->alt, ret);
gspca_dev->streaming = 0;
destroy_urbs(gspca_dev);
if (ret == -ENOSPC) {
msleep(20); /* wait for kill
* complete */
break; /* try the previous alt */
}
if (ret != -ENOSPC)
goto out;
/* the bandwidth is not wide enough
* negociate or try a lower alternate setting */
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) {
ret = -EIO;
goto out;
}
}
if (ret >= 0)
break;
}
out:
mutex_unlock(&gspca_dev->usb_lock);
......
......@@ -98,9 +98,11 @@ struct sd_desc {
/* mandatory operations */
cam_cf_op config; /* called on probe */
cam_op init; /* called on probe and resume */
cam_op start; /* called on stream on */
cam_op start; /* called on stream on after URBs creation */
cam_pkt_op pkt_scan;
/* optional operations */
cam_op isoc_init; /* called on stream on before getting the EP */
cam_op isoc_nego; /* called when URB submit failed with NOSPC */
cam_v_op stopN; /* called on stream off - main alt */
cam_v_op stop0; /* called on stream off & disconnect - alt 0 */
cam_v_op dq_callback; /* called when a frame has been dequeued */
......@@ -178,6 +180,7 @@ struct gspca_dev {
__u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */
__u8 nbalt; /* number of USB alternate settings */
u16 pkt_size; /* ISOC packet size */
};
int gspca_dev_probe(struct usb_interface *intf,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册