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: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index b8561df..1cc67ae 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -512,7 +512,10 @@
 	if (!gspca_dev->cam.bulk) {		/* isoc */
 
 		/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
-		psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+		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 @@
 	/* set the higher alternate setting and
 	 * loop until urb submit succeeds */
 	gspca_dev->alt = gspca_dev->nbalt;
+	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);
-		ep = get_ep(gspca_dev);
-		if (ep == NULL) {
-			ret = -EIO;
-			goto out;
-		}
 		ret = create_urbs(gspca_dev, ep);
 		if (ret < 0)
 			goto out;
@@ -628,21 +636,32 @@
 		/* submit the URBs */
 		for (n = 0; n < gspca_dev->nurbs; n++) {
 			ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL);
-			if (ret < 0) {
-				PDEBUG(D_ERR|D_STREAM,
-					"usb_submit_urb [%d] err %d", n, ret);
-				gspca_dev->streaming = 0;
-				destroy_urbs(gspca_dev);
-				if (ret == -ENOSPC) {
-					msleep(20);	/* wait for kill
-							 * complete */
-					break;	/* try the previous alt */
-				}
-				goto out;
-			}
+			if (ret < 0)
+				break;
 		}
 		if (ret >= 0)
 			break;
+		PDEBUG(D_ERR|D_STREAM,
+			"usb_submit_urb alt %d err %d", gspca_dev->alt, ret);
+		gspca_dev->streaming = 0;
+		destroy_urbs(gspca_dev);
+		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;
+			}
+		}
 	}
 out:
 	mutex_unlock(&gspca_dev->usb_lock);