Commit fb139224 authored by Jim Paris's avatar Jim Paris Committed by Mauro Carvalho Chehab

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: default avatarJim Paris <jim@jtan.com>
Signed-off-by: default avatarJean-Francois Moine <moinejf@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 5ea9c4de
...@@ -165,10 +165,6 @@ static const __u8 ov534_reg_initdata[][2] = { ...@@ -165,10 +165,6 @@ static const __u8 ov534_reg_initdata[][2] = {
{ 0xe2, 0x00 }, { 0xe2, 0x00 },
{ 0xe7, 0x3e }, { 0xe7, 0x3e },
{ 0x1c, 0x0a },
{ 0x1d, 0x22 },
{ 0x1d, 0x06 },
{ 0x96, 0x00 }, { 0x96, 0x00 },
{ 0x97, 0x20 }, { 0x97, 0x20 },
...@@ -327,18 +323,9 @@ static int sd_config(struct gspca_dev *gspca_dev, ...@@ -327,18 +323,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = vga_mode; cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode); cam->nmodes = ARRAY_SIZE(vga_mode);
/* cam->bulk_size = 2048;
* On some architectures we need contiguous memory for urb buffers, and
* in low memory situation 'sizeimage' can be too much.
* 16kiB chunks should be available even when we are low in memory.
* TODO: CHECK this description: is the problem arch-dependent or more
* general?
*/
cam->bulk_size = 16 * 1024;
cam->bulk_nurbs = 2; cam->bulk_nurbs = 2;
PDEBUG(D_PROBE, "bulk_size = %d", cam->bulk_size);
return 0; return 0;
} }
...@@ -383,19 +370,10 @@ static int sd_init(struct gspca_dev *gspca_dev) ...@@ -383,19 +370,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
static int sd_start(struct gspca_dev *gspca_dev) static int sd_start(struct gspca_dev *gspca_dev)
{ {
struct gspca_frame *frame;
/* start streaming data */ /* start streaming data */
ov534_set_led(gspca_dev->dev, 1); ov534_set_led(gspca_dev->dev, 1);
ov534_reg_write(gspca_dev->dev, 0xe0, 0x00); ov534_reg_write(gspca_dev->dev, 0xe0, 0x00);
frame = gspca_get_i_frame(gspca_dev);
if (frame == NULL) {
PDEBUG(D_ERR, "NULL frame!");
return -1;
}
gspca_frame_add(gspca_dev, FIRST_PACKET, frame, gspca_dev->usb_buf, 0);
return 0; return 0;
} }
...@@ -406,18 +384,79 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ...@@ -406,18 +384,79 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
ov534_set_led(gspca_dev->dev, 0); ov534_set_led(gspca_dev->dev, 0);
} }
/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
#define UVC_STREAM_EOH (1 << 7)
#define UVC_STREAM_ERR (1 << 6)
#define UVC_STREAM_STI (1 << 5)
#define UVC_STREAM_RES (1 << 4)
#define UVC_STREAM_SCR (1 << 3)
#define UVC_STREAM_PTS (1 << 2)
#define UVC_STREAM_EOF (1 << 1)
#define UVC_STREAM_FID (1 << 0)
static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
__u8 *data, int len) __u8 *data, int len)
{ {
int framesize = frame->v4l2_buf.length; static __u32 last_pts;
__u32 this_pts;
if (len == framesize) { static int last_fid;
frame = gspca_frame_add(gspca_dev, FIRST_PACKET, frame, int this_fid;
data, len);
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0); /* Payloads are prefixed with a the UVC-style header. We
} else consider a frame to start when the FID toggles, or the PTS
PDEBUG(D_PACK, "packet len = %d, framesize = %d", len, changes. A frame ends when EOF is set, and we've received
framesize); the correct number of bytes. */
/* Verify UVC header. Header length is always 12 */
if (data[0] != 12 || len < 12) {
PDEBUG(D_PACK, "bad header");
goto discard;
}
/* Check errors */
if (data[1] & UVC_STREAM_ERR) {
PDEBUG(D_PACK, "payload error");
goto discard;
}
/* Extract PTS and FID */
if (!(data[1] & UVC_STREAM_PTS)) {
PDEBUG(D_PACK, "PTS not present");
goto discard;
}
this_pts = (data[5] << 24) | (data[4] << 16) | (data[3] << 8) | data[2];
this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0;
/* If PTS or FID has changed, start a new frame. */
if (this_pts != last_pts || this_fid != last_fid) {
gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
last_pts = this_pts;
last_fid = this_fid;
}
/* Add the data from this payload */
gspca_frame_add(gspca_dev, INTER_PACKET, frame,
data + 12, len - 12);
/* If this packet is marked as EOF, end the frame */
if (data[1] & UVC_STREAM_EOF) {
last_pts = 0;
if ((frame->data_end - frame->data) !=
(gspca_dev->width * gspca_dev->height * 2)) {
PDEBUG(D_PACK, "short frame");
goto discard;
}
gspca_frame_add(gspca_dev, LAST_PACKET, frame, NULL, 0);
}
/* Done */
return;
discard:
/* Discard data until a new frame starts. */
gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
} }
/* sub-driver description */ /* sub-driver description */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment