diff mbox

PULL request - http://linuxtv.org/hg/~hgoede/gspca

Message ID 4A3DEDB7.3010400@redhat.com (mailing list archive)
State Superseded
Headers show

Commit Message

Hans de Goede June 21, 2009, 8:22 a.m. UTC
Hi,

On 06/21/2009 02:39 AM, Mauro Carvalho Chehab wrote:
> Em Sat, 20 Jun 2009 15:26:25 +0200
> Hans de Goede<hdegoede@redhat.com>  escreveu:
>
>> err -28 is ENOSPC which is given by usb_submit_urb, when the
>> required bandwidth for the isoc transfer is not available.
>>
>> With most cams we then automatically fall back to an altsetting
>> which requires less bandwidth, but the st6422 has only one
>> hence the: "gspca: no transfer endpoint found" error.
>>
>> There are 3 possible causes for this:
>> 1) You are using the device through an usb 2.0 hub, this should work
>>      but does not work due to a bug in the usb subsystem of the kernel,
>>      which I have reported but most likely won't be fixed
>


Hi,

This morning I had a bit of inspiration, the stv6422 has a register to which
the current isoc packet size should be written, so I though, hmm, maybe the
whole one altsetting which requests max bandwidth thingie is a bit bogus, and
instead it has a variable (so not fixed by altsetting) packet size,
and indeed it has.

Attached is a patch which:
1) makes it work through an usb 2.0 hub (work around the cannot
    alloc max isoc bandwidth through a usb 2.0 hub bug, by falling
    back in speed).
2) makes the mic and video work at the same time

Unfortunately 1 + 2 combined do not work, this is clearly a bug of the usb
subsystem :(

Regards,

Hans


p.s.

Jean-Francois Moine, can you please take a look at this patch and provide
feedback? It also makes changes the gscpa core.
diff mbox

Patch

diff -r 2899ad868fc6 linux/drivers/media/video/gspca/gspca.c
--- a/linux/drivers/media/video/gspca/gspca.c	Thu Jun 18 19:31:36 2009 +0200
+++ b/linux/drivers/media/video/gspca/gspca.c	Sun Jun 21 10:14:28 2009 +0200
@@ -525,6 +525,9 @@ 
 
 		/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
 		psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+		/* Variable packet size overriding alt setting ? */
+		if (gspca_dev->isoc_pkt_sz)
+			psize = gspca_dev->isoc_pkt_sz;
 		npkt = gspca_dev->cam.npkt;
 		if (npkt == 0)
 			npkt = 32;		/* default value */
@@ -595,6 +598,7 @@ 
  */
 static int gspca_init_transfer(struct gspca_dev *gspca_dev)
 {
+	struct cam *cam = &gspca_dev->cam;
 	struct usb_host_endpoint *ep;
 	int n, ret;
 
@@ -609,9 +613,9 @@ 
 	/* set the higher alternate setting and
 	 * loop until urb submit succeeds */
 	gspca_dev->alt = gspca_dev->nbalt;
+	gspca_dev->isoc_pkt_sz = cam->max_isoc_pkt_sz;
+	ep = get_ep(gspca_dev);
 	for (;;) {
-		PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt);
-		ep = get_ep(gspca_dev);
 		if (ep == NULL) {
 			ret = -EIO;
 			goto out;
@@ -648,7 +652,17 @@ 
 				if (ret == -ENOSPC) {
 					msleep(20);	/* wait for kill
 							 * complete */
-					break;	/* try the previous alt */
+					if (gspca_dev->isoc_pkt_sz) {
+						/* Try smaller packet size */
+						gspca_dev->isoc_pkt_sz -= 100;
+						if (gspca_dev->isoc_pkt_sz <
+						    cam->min_isoc_pkt_sz)
+							goto out;
+					} else {
+						/* try the previous alt */
+						ep = get_ep(gspca_dev);
+					}
+					break;
 				}
 				goto out;
 			}
diff -r 2899ad868fc6 linux/drivers/media/video/gspca/gspca.h
--- a/linux/drivers/media/video/gspca/gspca.h	Thu Jun 18 19:31:36 2009 +0200
+++ b/linux/drivers/media/video/gspca/gspca.h	Sun Jun 21 10:14:28 2009 +0200
@@ -57,6 +57,12 @@ 
 	u8 bulk;		/* image transfer by 0:isoc / 1:bulk */
 	u8 npkt;		/* number of packets in an ISOC message
 				 * 0 is the default value: 32 packets */
+	/* min / max isoc packet size for camera's which have a variable
+	   packet size, when this is the case BOTH must be set to a non zero
+	   value, the wMaxPacketSize of the alsetting will be ignored and the
+	   highest alt setting will be used */
+	int min_isoc_pkt_sz;
+	int max_isoc_pkt_sz;
 	u32 input_flags;	/* value for ENUM_INPUT status flags */
 };
 
@@ -135,6 +141,7 @@ 
 #define USB_BUF_SZ 64
 	__u8 *usb_buf;				/* buffer for USB exchanges */
 	struct urb *urb[MAX_NURBS];
+	int isoc_pkt_sz;			/* variable isoc packet size */
 
 	__u8 *frbuf;				/* buffer for nframes */
 	struct gspca_frame frame[GSPCA_MAX_FRAMES];
diff -r 2899ad868fc6 linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c	Thu Jun 18 19:31:36 2009 +0200
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c	Sun Jun 21 10:14:28 2009 +0200
@@ -133,6 +133,9 @@ 
 
 	sd->gspca_dev.cam.cam_mode = st6422_mode;
 	sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode);
+	sd->gspca_dev.cam.min_isoc_pkt_sz = 460;
+	sd->gspca_dev.cam.max_isoc_pkt_sz = 960;
+	sd->gspca_dev.cam.npkt = 10;
 	sd->desc.ctrls = st6422_ctrl;
 	sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl);
 	sd->sensor_priv = sensor_settings;
@@ -238,21 +241,11 @@ 
 
 static int st6422_start(struct sd *sd)
 {
-	int err, packet_size;
+	int err;
 	struct cam *cam = &sd->gspca_dev.cam;
 	s32 *sensor_settings = sd->sensor_priv;
-	struct usb_host_interface *alt;
-	struct usb_interface *intf;
 
-	intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
-	alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
-	if (!alt) {
-		PDEBUG(D_ERR, "Couldn't get altsetting");
-		return -EIO;
-	}
-
-	packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
-	err = stv06xx_write_bridge(sd, 0x15c1, packet_size);
+	err = stv06xx_write_bridge(sd, 0x15c1, sd->gspca_dev.isoc_pkt_sz);
 	if (err < 0)
 		return err;