V4L/DVB (12229): gspca - main: Change the ISOC initialization mechanism.
authorJean-Francois Moine <moinejf@free.fr>
Tue, 30 Jun 2009 10:07:01 +0000 (07:07 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Sat, 12 Sep 2009 15:17:37 +0000 (12:17 -0300)
- 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>
drivers/media/video/gspca/gspca.c
drivers/media/video/gspca/gspca.h

index b8561df..1cc67ae 100644 (file)
@@ -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. */
-               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 @@ 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;
+       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 @@ 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) {
-                               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);
index 46c4eff..70b1fd8 100644 (file)
@@ -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,