aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/stv06xx/stv06xx.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2010-10-27 08:12:30 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-12-29 05:16:40 -0500
commitc0b33bdc5b8d9c1120dece660480d4dd86b817ee (patch)
treeebcc92bf6b05336943b9268337ea3d994af4ca43 /drivers/media/video/gspca/stv06xx/stv06xx.c
parentbc25068495b110fcdf35a22f43d32637e99fd018 (diff)
[media] gspca-stv06xx: support bandwidth changing
stv06xx devices have only one altsetting, but the actual used bandwidth can be programmed through a register. We were already setting this register lower then the max packetsize of the altsetting indicates. This patch makes the gspca-stv06xx update the usb descriptor for the alt setting to reflect the actual packetsize in use, so that the usb subsystem uses the correct information for scheduling usb transfers. This patch also tries to fallback to lower speeds in case a ENOSPC error is received when submitting urbs, but currently this is only supported with stv06xx cams with the pb0100 sensor, as this is the only one for which we know how to change the framerate. This patch is based on an initial incomplete patch by Lee Jones <lee.jones@canonical.com> Signed-off-by: Lee Jones <lee.jones@canonical.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/gspca/stv06xx/stv06xx.c')
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c55
1 files changed, 54 insertions, 1 deletions
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index 544d5f72a1e..28ea4175b80 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -263,7 +263,21 @@ static int stv06xx_init(struct gspca_dev *gspca_dev)
263static int stv06xx_start(struct gspca_dev *gspca_dev) 263static int stv06xx_start(struct gspca_dev *gspca_dev)
264{ 264{
265 struct sd *sd = (struct sd *) gspca_dev; 265 struct sd *sd = (struct sd *) gspca_dev;
266 int err; 266 struct usb_host_interface *alt;
267 struct usb_interface *intf;
268 int err, packet_size;
269
270 intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
271 alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
272 if (!alt) {
273 PDEBUG(D_ERR, "Couldn't get altsetting");
274 return -EIO;
275 }
276
277 packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
278 err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size);
279 if (err < 0)
280 return err;
267 281
268 /* Prepare the sensor for start */ 282 /* Prepare the sensor for start */
269 err = sd->sensor->start(sd); 283 err = sd->sensor->start(sd);
@@ -282,6 +296,43 @@ out:
282 return (err < 0) ? err : 0; 296 return (err < 0) ? err : 0;
283} 297}
284 298
299static int stv06xx_isoc_init(struct gspca_dev *gspca_dev)
300{
301 struct usb_host_interface *alt;
302 struct sd *sd = (struct sd *) gspca_dev;
303
304 /* Start isoc bandwidth "negotiation" at max isoc bandwidth */
305 alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
306 alt->endpoint[0].desc.wMaxPacketSize =
307 cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]);
308
309 return 0;
310}
311
312static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev)
313{
314 int ret, packet_size, min_packet_size;
315 struct usb_host_interface *alt;
316 struct sd *sd = (struct sd *) gspca_dev;
317
318 alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
319 packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
320 min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode];
321 if (packet_size <= min_packet_size)
322 return -EIO;
323
324 packet_size -= 100;
325 if (packet_size < min_packet_size)
326 packet_size = min_packet_size;
327 alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size);
328
329 ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
330 if (ret < 0)
331 PDEBUG(D_ERR|D_STREAM, "set alt 1 err %d", ret);
332
333 return ret;
334}
335
285static void stv06xx_stopN(struct gspca_dev *gspca_dev) 336static void stv06xx_stopN(struct gspca_dev *gspca_dev)
286{ 337{
287 int err; 338 int err;
@@ -462,6 +513,8 @@ static const struct sd_desc sd_desc = {
462 .start = stv06xx_start, 513 .start = stv06xx_start,
463 .stopN = stv06xx_stopN, 514 .stopN = stv06xx_stopN,
464 .pkt_scan = stv06xx_pkt_scan, 515 .pkt_scan = stv06xx_pkt_scan,
516 .isoc_init = stv06xx_isoc_init,
517 .isoc_nego = stv06xx_isoc_nego,
465#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) 518#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
466 .int_pkt_scan = sd_int_pkt_scan, 519 .int_pkt_scan = sd_int_pkt_scan,
467#endif 520#endif