diff options
author | Hans de Goede <hdegoede@redhat.com> | 2010-10-27 08:12:30 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-12-29 05:16:40 -0500 |
commit | c0b33bdc5b8d9c1120dece660480d4dd86b817ee (patch) | |
tree | ebcc92bf6b05336943b9268337ea3d994af4ca43 /drivers/media/video/gspca/stv06xx/stv06xx.c | |
parent | bc25068495b110fcdf35a22f43d32637e99fd018 (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.c | 55 |
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) | |||
263 | static int stv06xx_start(struct gspca_dev *gspca_dev) | 263 | static 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 | ||
299 | static 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 | |||
312 | static 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 | |||
285 | static void stv06xx_stopN(struct gspca_dev *gspca_dev) | 336 | static 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 |