Commit 1f53b0b0 authored by Jean-Francois Moine's avatar Jean-Francois Moine Committed by 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: default avatarJean-Francois Moine <moinejf@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 1852e75a
...@@ -512,7 +512,10 @@ static int create_urbs(struct gspca_dev *gspca_dev, ...@@ -512,7 +512,10 @@ static int create_urbs(struct gspca_dev *gspca_dev,
if (!gspca_dev->cam.bulk) { /* isoc */ if (!gspca_dev->cam.bulk) { /* isoc */
/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */ /* 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)); psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
else
psize = gspca_dev->pkt_size;
npkt = gspca_dev->cam.npkt; npkt = gspca_dev->cam.npkt;
if (npkt == 0) if (npkt == 0)
npkt = 32; /* default value */ npkt = 32; /* default value */
...@@ -597,13 +600,18 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) ...@@ -597,13 +600,18 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* set the higher alternate setting and /* set the higher alternate setting and
* loop until urb submit succeeds */ * loop until urb submit succeeds */
gspca_dev->alt = gspca_dev->nbalt; gspca_dev->alt = gspca_dev->nbalt;
for (;;) { if (gspca_dev->sd_desc->isoc_init) {
PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt); ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
if (ret < 0)
goto out;
}
ep = get_ep(gspca_dev); ep = get_ep(gspca_dev);
if (ep == NULL) { if (ep == NULL) {
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
for (;;) {
PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
ret = create_urbs(gspca_dev, ep); ret = create_urbs(gspca_dev, ep);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -628,21 +636,32 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) ...@@ -628,21 +636,32 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* submit the URBs */ /* submit the URBs */
for (n = 0; n < gspca_dev->nurbs; n++) { for (n = 0; n < gspca_dev->nurbs; n++) {
ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL); 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, 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; gspca_dev->streaming = 0;
destroy_urbs(gspca_dev); destroy_urbs(gspca_dev);
if (ret == -ENOSPC) { if (ret != -ENOSPC)
msleep(20); /* wait for kill goto out;
* complete */
break; /* try the previous alt */ /* 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; goto out;
} }
} }
if (ret >= 0)
break;
} }
out: out:
mutex_unlock(&gspca_dev->usb_lock); mutex_unlock(&gspca_dev->usb_lock);
......
...@@ -98,9 +98,11 @@ struct sd_desc { ...@@ -98,9 +98,11 @@ struct sd_desc {
/* mandatory operations */ /* mandatory operations */
cam_cf_op config; /* called on probe */ cam_cf_op config; /* called on probe */
cam_op init; /* called on probe and resume */ 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; cam_pkt_op pkt_scan;
/* optional operations */ /* 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 stopN; /* called on stream off - main alt */
cam_v_op stop0; /* called on stream off & disconnect - alt 0 */ cam_v_op stop0; /* called on stream off & disconnect - alt 0 */
cam_v_op dq_callback; /* called when a frame has been dequeued */ cam_v_op dq_callback; /* called when a frame has been dequeued */
...@@ -178,6 +180,7 @@ struct gspca_dev { ...@@ -178,6 +180,7 @@ struct gspca_dev {
__u8 iface; /* USB interface number */ __u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */ __u8 alt; /* USB alternate setting */
__u8 nbalt; /* number of USB alternate settings */ __u8 nbalt; /* number of USB alternate settings */
u16 pkt_size; /* ISOC packet size */
}; };
int gspca_dev_probe(struct usb_interface *intf, int gspca_dev_probe(struct usb_interface *intf,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment