diff options
Diffstat (limited to 'drivers/media/video/gspca')
-rw-r--r-- | drivers/media/video/gspca/gspca.c | 55 | ||||
-rw-r--r-- | drivers/media/video/gspca/gspca.h | 5 |
2 files changed, 41 insertions, 19 deletions
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index b8561dfb6c8..1cc67ae3bfa 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c | |||
@@ -512,7 +512,10 @@ static int create_urbs(struct gspca_dev *gspca_dev, | |||
512 | if (!gspca_dev->cam.bulk) { /* isoc */ | 512 | if (!gspca_dev->cam.bulk) { /* isoc */ |
513 | 513 | ||
514 | /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */ | 514 | /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */ |
515 | psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); | 515 | if (gspca_dev->pkt_size == 0) |
516 | psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); | ||
517 | else | ||
518 | psize = gspca_dev->pkt_size; | ||
516 | npkt = gspca_dev->cam.npkt; | 519 | npkt = gspca_dev->cam.npkt; |
517 | if (npkt == 0) | 520 | if (npkt == 0) |
518 | npkt = 32; /* default value */ | 521 | npkt = 32; /* default value */ |
@@ -597,13 +600,18 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) | |||
597 | /* set the higher alternate setting and | 600 | /* set the higher alternate setting and |
598 | * loop until urb submit succeeds */ | 601 | * loop until urb submit succeeds */ |
599 | gspca_dev->alt = gspca_dev->nbalt; | 602 | gspca_dev->alt = gspca_dev->nbalt; |
603 | if (gspca_dev->sd_desc->isoc_init) { | ||
604 | ret = gspca_dev->sd_desc->isoc_init(gspca_dev); | ||
605 | if (ret < 0) | ||
606 | goto out; | ||
607 | } | ||
608 | ep = get_ep(gspca_dev); | ||
609 | if (ep == NULL) { | ||
610 | ret = -EIO; | ||
611 | goto out; | ||
612 | } | ||
600 | for (;;) { | 613 | for (;;) { |
601 | PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt); | 614 | PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt); |
602 | ep = get_ep(gspca_dev); | ||
603 | if (ep == NULL) { | ||
604 | ret = -EIO; | ||
605 | goto out; | ||
606 | } | ||
607 | ret = create_urbs(gspca_dev, ep); | 615 | ret = create_urbs(gspca_dev, ep); |
608 | if (ret < 0) | 616 | if (ret < 0) |
609 | goto out; | 617 | goto out; |
@@ -628,21 +636,32 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) | |||
628 | /* submit the URBs */ | 636 | /* submit the URBs */ |
629 | for (n = 0; n < gspca_dev->nurbs; n++) { | 637 | for (n = 0; n < gspca_dev->nurbs; n++) { |
630 | ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL); | 638 | ret = usb_submit_urb(gspca_dev->urb[n], GFP_KERNEL); |
631 | if (ret < 0) { | 639 | if (ret < 0) |
632 | PDEBUG(D_ERR|D_STREAM, | 640 | break; |
633 | "usb_submit_urb [%d] err %d", n, ret); | ||
634 | gspca_dev->streaming = 0; | ||
635 | destroy_urbs(gspca_dev); | ||
636 | if (ret == -ENOSPC) { | ||
637 | msleep(20); /* wait for kill | ||
638 | * complete */ | ||
639 | break; /* try the previous alt */ | ||
640 | } | ||
641 | goto out; | ||
642 | } | ||
643 | } | 641 | } |
644 | if (ret >= 0) | 642 | if (ret >= 0) |
645 | break; | 643 | break; |
644 | PDEBUG(D_ERR|D_STREAM, | ||
645 | "usb_submit_urb alt %d err %d", gspca_dev->alt, ret); | ||
646 | gspca_dev->streaming = 0; | ||
647 | destroy_urbs(gspca_dev); | ||
648 | if (ret != -ENOSPC) | ||
649 | goto out; | ||
650 | |||
651 | /* the bandwidth is not wide enough | ||
652 | * negociate or try a lower alternate setting */ | ||
653 | msleep(20); /* wait for kill complete */ | ||
654 | if (gspca_dev->sd_desc->isoc_nego) { | ||
655 | ret = gspca_dev->sd_desc->isoc_nego(gspca_dev); | ||
656 | if (ret < 0) | ||
657 | goto out; | ||
658 | } else { | ||
659 | ep = get_ep(gspca_dev); | ||
660 | if (ep == NULL) { | ||
661 | ret = -EIO; | ||
662 | goto out; | ||
663 | } | ||
664 | } | ||
646 | } | 665 | } |
647 | out: | 666 | out: |
648 | mutex_unlock(&gspca_dev->usb_lock); | 667 | mutex_unlock(&gspca_dev->usb_lock); |
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 46c4effdfcd..70b1fd83087 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h | |||
@@ -98,9 +98,11 @@ struct sd_desc { | |||
98 | /* mandatory operations */ | 98 | /* mandatory operations */ |
99 | cam_cf_op config; /* called on probe */ | 99 | cam_cf_op config; /* called on probe */ |
100 | cam_op init; /* called on probe and resume */ | 100 | cam_op init; /* called on probe and resume */ |
101 | cam_op start; /* called on stream on */ | 101 | cam_op start; /* called on stream on after URBs creation */ |
102 | cam_pkt_op pkt_scan; | 102 | cam_pkt_op pkt_scan; |
103 | /* optional operations */ | 103 | /* optional operations */ |
104 | cam_op isoc_init; /* called on stream on before getting the EP */ | ||
105 | cam_op isoc_nego; /* called when URB submit failed with NOSPC */ | ||
104 | cam_v_op stopN; /* called on stream off - main alt */ | 106 | cam_v_op stopN; /* called on stream off - main alt */ |
105 | cam_v_op stop0; /* called on stream off & disconnect - alt 0 */ | 107 | cam_v_op stop0; /* called on stream off & disconnect - alt 0 */ |
106 | cam_v_op dq_callback; /* called when a frame has been dequeued */ | 108 | cam_v_op dq_callback; /* called when a frame has been dequeued */ |
@@ -178,6 +180,7 @@ struct gspca_dev { | |||
178 | __u8 iface; /* USB interface number */ | 180 | __u8 iface; /* USB interface number */ |
179 | __u8 alt; /* USB alternate setting */ | 181 | __u8 alt; /* USB alternate setting */ |
180 | __u8 nbalt; /* number of USB alternate settings */ | 182 | __u8 nbalt; /* number of USB alternate settings */ |
183 | u16 pkt_size; /* ISOC packet size */ | ||
181 | }; | 184 | }; |
182 | 185 | ||
183 | int gspca_dev_probe(struct usb_interface *intf, | 186 | int gspca_dev_probe(struct usb_interface *intf, |