aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca
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
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')
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c55
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h11
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c18
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h3
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_sensor.h4
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_st6422.c17
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_st6422.h3
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h9
8 files changed, 93 insertions, 27 deletions
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index 544d5f72a1e3..28ea4175b80e 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
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
index cf3d0ccc1121..b538dce96f78 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
@@ -146,6 +146,11 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = {
146 .i2c_addr = (0x55 << 1), 146 .i2c_addr = (0x55 << 1),
147 .i2c_len = 1, 147 .i2c_len = 1,
148 148
149 /* FIXME (see if we can lower min_packet_size, needs testing, and also
150 adjusting framerate when the bandwidth gets lower) */
151 .min_packet_size = { 847 },
152 .max_packet_size = { 847 },
153
149 .init = hdcs_init, 154 .init = hdcs_init,
150 .probe = hdcs_probe_1x00, 155 .probe = hdcs_probe_1x00,
151 .start = hdcs_start, 156 .start = hdcs_start,
@@ -160,6 +165,11 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = {
160 .i2c_addr = (0x55 << 1), 165 .i2c_addr = (0x55 << 1),
161 .i2c_len = 1, 166 .i2c_len = 1,
162 167
168 /* FIXME (see if we can lower min_packet_size, needs testing, and also
169 adjusting framerate when the bandwidthm gets lower) */
170 .min_packet_size = { 847 },
171 .max_packet_size = { 847 },
172
163 .init = hdcs_init, 173 .init = hdcs_init,
164 .probe = hdcs_probe_1020, 174 .probe = hdcs_probe_1020,
165 .start = hdcs_start, 175 .start = hdcs_start,
@@ -177,7 +187,6 @@ static const u16 stv_bridge_init[][2] = {
177 {STV_REG04, 0x07}, 187 {STV_REG04, 0x07},
178 188
179 {STV_SCAN_RATE, 0x20}, 189 {STV_SCAN_RATE, 0x20},
180 {STV_ISO_SIZE_L, 847},
181 {STV_Y_CTRL, 0x01}, 190 {STV_Y_CTRL, 0x01},
182 {STV_X_CTRL, 0x0a} 191 {STV_X_CTRL, 0x0a}
183}; 192};
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
index 285221e6b390..ac47b4c94388 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
@@ -208,11 +208,24 @@ static int pb0100_probe(struct sd *sd)
208 208
209static int pb0100_start(struct sd *sd) 209static int pb0100_start(struct sd *sd)
210{ 210{
211 int err; 211 int err, packet_size, max_packet_size;
212 struct usb_host_interface *alt;
213 struct usb_interface *intf;
212 struct cam *cam = &sd->gspca_dev.cam; 214 struct cam *cam = &sd->gspca_dev.cam;
213 s32 *sensor_settings = sd->sensor_priv; 215 s32 *sensor_settings = sd->sensor_priv;
214 u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv; 216 u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
215 217
218 intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
219 alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
220 packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
221
222 /* If we don't have enough bandwidth use a lower framerate */
223 max_packet_size = sd->sensor->max_packet_size[sd->gspca_dev.curr_mode];
224 if (packet_size < max_packet_size)
225 stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
226 else
227 stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(5)|BIT(3)|BIT(1));
228
216 /* Setup sensor window */ 229 /* Setup sensor window */
217 if (mode & PB0100_CROP_TO_VGA) { 230 if (mode & PB0100_CROP_TO_VGA) {
218 stv06xx_write_sensor(sd, PB_RSTART, 30); 231 stv06xx_write_sensor(sd, PB_RSTART, 30);
@@ -328,9 +341,6 @@ static int pb0100_init(struct sd *sd)
328 stv06xx_write_bridge(sd, STV_REG03, 0x45); 341 stv06xx_write_bridge(sd, STV_REG03, 0x45);
329 stv06xx_write_bridge(sd, STV_REG04, 0x07); 342 stv06xx_write_bridge(sd, STV_REG04, 0x07);
330 343
331 /* ISO-Size (0x27b: 635... why? - HDCS uses 847) */
332 stv06xx_write_bridge(sd, STV_ISO_SIZE_L, 847);
333
334 /* Scan/timing for the sensor */ 344 /* Scan/timing for the sensor */
335 stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1)); 345 stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
336 stv06xx_write_sensor(sd, PB_CFILLIN, 14); 346 stv06xx_write_sensor(sd, PB_CFILLIN, 14);
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
index 4de4fa5ebc57..757de246dc75 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
@@ -138,6 +138,9 @@ const struct stv06xx_sensor stv06xx_sensor_pb0100 = {
138 .i2c_addr = 0xba, 138 .i2c_addr = 0xba,
139 .i2c_len = 2, 139 .i2c_len = 2,
140 140
141 .min_packet_size = { 635, 847 },
142 .max_packet_size = { 847, 923 },
143
141 .init = pb0100_init, 144 .init = pb0100_init,
142 .probe = pb0100_probe, 145 .probe = pb0100_probe,
143 .start = pb0100_start, 146 .start = pb0100_start,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
index 934b9cebc1ab..fb229d8ded58 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
@@ -53,6 +53,10 @@ struct stv06xx_sensor {
53 /* length of an i2c word */ 53 /* length of an i2c word */
54 u8 i2c_len; 54 u8 i2c_len;
55 55
56 /* Isoc packet size (per mode) */
57 int min_packet_size[4];
58 int max_packet_size[4];
59
56 /* Probes if the sensor is connected */ 60 /* Probes if the sensor is connected */
57 int (*probe)(struct sd *sd); 61 int (*probe)(struct sd *sd);
58 62
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
index ea677b5d071e..42f3a1e41188 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
@@ -213,7 +213,6 @@ static int st6422_init(struct sd *sd)
213 { 0x150e, 0x8e }, 213 { 0x150e, 0x8e },
214 { 0x150f, 0x37 }, 214 { 0x150f, 0x37 },
215 { 0x15c0, 0x00 }, 215 { 0x15c0, 0x00 },
216 { 0x15c1, 1023 }, /* 160x120, ISOC_PACKET_SIZE */
217 { 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */ 216 { 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */
218 217
219 218
@@ -237,23 +236,9 @@ static void st6422_disconnect(struct sd *sd)
237 236
238static int st6422_start(struct sd *sd) 237static int st6422_start(struct sd *sd)
239{ 238{
240 int err, packet_size; 239 int err;
241 struct cam *cam = &sd->gspca_dev.cam; 240 struct cam *cam = &sd->gspca_dev.cam;
242 s32 *sensor_settings = sd->sensor_priv; 241 s32 *sensor_settings = sd->sensor_priv;
243 struct usb_host_interface *alt;
244 struct usb_interface *intf;
245
246 intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
247 alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
248 if (!alt) {
249 err("Couldn't get altsetting");
250 return -EIO;
251 }
252
253 packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
254 err = stv06xx_write_bridge(sd, 0x15c1, packet_size);
255 if (err < 0)
256 return err;
257 242
258 if (cam->cam_mode[sd->gspca_dev.curr_mode].priv) 243 if (cam->cam_mode[sd->gspca_dev.curr_mode].priv)
259 err = stv06xx_write_bridge(sd, 0x1505, 0x0f); 244 err = stv06xx_write_bridge(sd, 0x1505, 0x0f);
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
index b2d45fe50522..12608aebe50b 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
@@ -49,6 +49,9 @@ static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
49 49
50const struct stv06xx_sensor stv06xx_sensor_st6422 = { 50const struct stv06xx_sensor stv06xx_sensor_st6422 = {
51 .name = "ST6422", 51 .name = "ST6422",
52 /* No known way to lower framerate in case of less bandwidth */
53 .min_packet_size = { 300, 847 },
54 .max_packet_size = { 300, 847 },
52 .init = st6422_init, 55 .init = st6422_init,
53 .probe = st6422_probe, 56 .probe = st6422_probe,
54 .start = st6422_start, 57 .start = st6422_start,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
index b3b5508473bc..7fe3587f5f71 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
@@ -197,6 +197,10 @@ const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
197 .i2c_flush = 5, 197 .i2c_flush = 5,
198 .i2c_addr = 0x20, 198 .i2c_addr = 0x20,
199 .i2c_len = 1, 199 .i2c_len = 1,
200 /* FIXME (see if we can lower packet_size-s, needs testing, and also
201 adjusting framerate when the bandwidth gets lower) */
202 .min_packet_size = { 1023 },
203 .max_packet_size = { 1023 },
200 .init = vv6410_init, 204 .init = vv6410_init,
201 .probe = vv6410_probe, 205 .probe = vv6410_probe,
202 .start = vv6410_start, 206 .start = vv6410_start,
@@ -220,10 +224,6 @@ static const u8 x1536[] = { /* 0x1536 - 0x153b */
220 0x02, 0x00, 0x60, 0x01, 0x20, 0x01 224 0x02, 0x00, 0x60, 0x01, 0x20, 0x01
221}; 225};
222 226
223static const u8 x15c1[] = { /* 0x15c1 - 0x15c2 */
224 0xff, 0x03 /* Output word 0x03ff = 1023 (ISO size) */
225};
226
227static const struct stv_init stv_bridge_init[] = { 227static const struct stv_init stv_bridge_init[] = {
228 /* This reg is written twice. Some kind of reset? */ 228 /* This reg is written twice. Some kind of reset? */
229 {NULL, 0x1620, 0x80}, 229 {NULL, 0x1620, 0x80},
@@ -232,7 +232,6 @@ static const struct stv_init stv_bridge_init[] = {
232 {NULL, 0x1423, 0x04}, 232 {NULL, 0x1423, 0x04},
233 {x1500, 0x1500, ARRAY_SIZE(x1500)}, 233 {x1500, 0x1500, ARRAY_SIZE(x1500)},
234 {x1536, 0x1536, ARRAY_SIZE(x1536)}, 234 {x1536, 0x1536, ARRAY_SIZE(x1536)},
235 {x15c1, 0x15c1, ARRAY_SIZE(x15c1)}
236}; 235};
237 236
238static const u8 vv6410_sensor_init[][2] = { 237static const u8 vv6410_sensor_init[][2] = {