aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
authorJim Paris <jim@jtan.com>2008-12-04 02:52:40 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:38:55 -0500
commitfb139224aea3b56237542690516eb9d6d671b135 (patch)
treedac8b862a677d6107a0bffa03ae3b6a76d9afa36 /drivers/media/video
parent5ea9c4def8154a5be836dd31cbd97f49fd34ea8f (diff)
V4L/DVB (9860): gspca - ov534: Frame transfer improvements.
The indirect registers at 0x1c/0x1d control frame settings. If we leave the values at 0x0a and 0x0b at their reset-time defaults, frame data from the camera matches the UVC payload format. This lets us better reassemble the data into frames and know when data was lost. This also lets us relax the bulk_size requirement from 600K to 2K, which should help systems on with limited RAM (like the PS3). Signed-off-by: Jim Paris <jim@jtan.com> Signed-off-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/gspca/ov534.c103
1 files changed, 71 insertions, 32 deletions
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index 79bb6241d27..e02c8f70f81 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -165,10 +165,6 @@ static const __u8 ov534_reg_initdata[][2] = {
165 { 0xe2, 0x00 }, 165 { 0xe2, 0x00 },
166 { 0xe7, 0x3e }, 166 { 0xe7, 0x3e },
167 167
168 { 0x1c, 0x0a },
169 { 0x1d, 0x22 },
170 { 0x1d, 0x06 },
171
172 { 0x96, 0x00 }, 168 { 0x96, 0x00 },
173 169
174 { 0x97, 0x20 }, 170 { 0x97, 0x20 },
@@ -327,18 +323,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
327 cam->cam_mode = vga_mode; 323 cam->cam_mode = vga_mode;
328 cam->nmodes = ARRAY_SIZE(vga_mode); 324 cam->nmodes = ARRAY_SIZE(vga_mode);
329 325
330 /* 326 cam->bulk_size = 2048;
331 * On some architectures we need contiguous memory for urb buffers, and
332 * in low memory situation 'sizeimage' can be too much.
333 * 16kiB chunks should be available even when we are low in memory.
334 * TODO: CHECK this description: is the problem arch-dependent or more
335 * general?
336 */
337 cam->bulk_size = 16 * 1024;
338 cam->bulk_nurbs = 2; 327 cam->bulk_nurbs = 2;
339 328
340 PDEBUG(D_PROBE, "bulk_size = %d", cam->bulk_size);
341
342 return 0; 329 return 0;
343} 330}
344 331
@@ -383,19 +370,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
383 370
384static int sd_start(struct gspca_dev *gspca_dev) 371static int sd_start(struct gspca_dev *gspca_dev)
385{ 372{
386 struct gspca_frame *frame;
387
388 /* start streaming data */ 373 /* start streaming data */
389 ov534_set_led(gspca_dev->dev, 1); 374 ov534_set_led(gspca_dev->dev, 1);
390 ov534_reg_write(gspca_dev->dev, 0xe0, 0x00); 375 ov534_reg_write(gspca_dev->dev, 0xe0, 0x00);
391 376
392 frame = gspca_get_i_frame(gspca_dev);
393 if (frame == NULL) {
394 PDEBUG(D_ERR, "NULL frame!");
395 return -1;
396 }
397 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, gspca_dev->usb_buf, 0);
398
399 return 0; 377 return 0;
400} 378}
401 379
@@ -406,18 +384,79 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
406 ov534_set_led(gspca_dev->dev, 0); 384 ov534_set_led(gspca_dev->dev, 0);
407} 385}
408 386
387/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
388#define UVC_STREAM_EOH (1 << 7)
389#define UVC_STREAM_ERR (1 << 6)
390#define UVC_STREAM_STI (1 << 5)
391#define UVC_STREAM_RES (1 << 4)
392#define UVC_STREAM_SCR (1 << 3)
393#define UVC_STREAM_PTS (1 << 2)
394#define UVC_STREAM_EOF (1 << 1)
395#define UVC_STREAM_FID (1 << 0)
396
409static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, 397static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
410 __u8 *data, int len) 398 __u8 *data, int len)
411{ 399{
412 int framesize = frame->v4l2_buf.length; 400 static __u32 last_pts;
413 401 __u32 this_pts;
414 if (len == framesize) { 402 static int last_fid;
415 frame = gspca_frame_add(gspca_dev, FIRST_PACKET, frame, 403 int this_fid;
416 data, len); 404
417 frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0); 405 /* Payloads are prefixed with a the UVC-style header. We
418 } else 406 consider a frame to start when the FID toggles, or the PTS
419 PDEBUG(D_PACK, "packet len = %d, framesize = %d", len, 407 changes. A frame ends when EOF is set, and we've received
420 framesize); 408 the correct number of bytes. */
409
410 /* Verify UVC header. Header length is always 12 */
411 if (data[0] != 12 || len < 12) {
412 PDEBUG(D_PACK, "bad header");
413 goto discard;
414 }
415
416 /* Check errors */
417 if (data[1] & UVC_STREAM_ERR) {
418 PDEBUG(D_PACK, "payload error");
419 goto discard;
420 }
421
422 /* Extract PTS and FID */
423 if (!(data[1] & UVC_STREAM_PTS)) {
424 PDEBUG(D_PACK, "PTS not present");
425 goto discard;
426 }
427 this_pts = (data[5] << 24) | (data[4] << 16) | (data[3] << 8) | data[2];
428 this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0;
429
430 /* If PTS or FID has changed, start a new frame. */
431 if (this_pts != last_pts || this_fid != last_fid) {
432 gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
433 last_pts = this_pts;
434 last_fid = this_fid;
435 }
436
437 /* Add the data from this payload */
438 gspca_frame_add(gspca_dev, INTER_PACKET, frame,
439 data + 12, len - 12);
440
441 /* If this packet is marked as EOF, end the frame */
442 if (data[1] & UVC_STREAM_EOF) {
443 last_pts = 0;
444
445 if ((frame->data_end - frame->data) !=
446 (gspca_dev->width * gspca_dev->height * 2)) {
447 PDEBUG(D_PACK, "short frame");
448 goto discard;
449 }
450
451 gspca_frame_add(gspca_dev, LAST_PACKET, frame, NULL, 0);
452 }
453
454 /* Done */
455 return;
456
457discard:
458 /* Discard data until a new frame starts. */
459 gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
421} 460}
422 461
423/* sub-driver description */ 462/* sub-driver description */