Here's a little cafe camera patch:
Jonathan Corbet
corbet at lwn.unroutablenet
Tue Dec 5 13:09:37 EST 2006
Commit: 5a9f682f7b0560b3c1e46518d11268f4029c7341
Parent: b9e5120610df36b708e5574fb8ebd47063a7a82a
commit 5a9f682f7b0560b3c1e46518d11268f4029c7341
Author: Jonathan Corbet <corbet at lwn.net>
AuthorDate: Tue Dec 5 13:14:21 2006 -0500
Commit: Andres Salomon <dilinger at debian.org>
CommitDate: Tue Dec 5 13:14:21 2006 -0500
Here's a little cafe camera patch:
- Adds support for VIDIOC_S_PARM and VIDIOC_G_PARM. That, in turn,
allows an application to control the video frame rate.
- Remove the faked RGB32 format. It was useful for debugging, but the
driver won't get into the mainline with kernel-space reformatting
code.
There's also a hack to make it easier to manipulate ov7670 registers
directly from the command line; that will probably come out eventually.
---
drivers/media/video/cafe_ccic.c | 87 +++++++++++++-------------------
drivers/media/video/ov7670.c | 106 +++++++++++++++++++++++++++++++--------
2 files changed, 120 insertions(+), 73 deletions(-)
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 67c2478..3d83348 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -618,16 +618,6 @@ static void cafe_ctlr_image(struct cafe_
C0_DF_MASK);
break;
- /*
- * For "fake rgb32" get the image pitch right.
- */
- case V4L2_PIX_FMT_RGB32:
- cafe_reg_write_mask(cam, REG_IMGPITCH, fmt->bytesperline/2,
- IMGP_YP_MASK);
- imgsz = ((fmt->height << IMGSZ_V_SHIFT) & IMGSZ_V_MASK) |
- ((fmt->bytesperline/2) & IMGSZ_H_MASK);
- cafe_reg_write(cam, REG_IMGSIZE, imgsz);
- /* fall into ... */
case V4L2_PIX_FMT_RGB444:
cafe_reg_write_mask(cam, REG_CTRL0,
C0_DF_RGB|C0_RGBF_444|C0_RGB4_XRGB,
@@ -908,11 +898,8 @@ static int cafe_alloc_dma_bufs(struct ca
cafe_set_config_needed(cam, 1);
if (loadtime)
cam->dma_buf_size = dma_buf_size;
- else {
+ else
cam->dma_buf_size = cam->pix_format.sizeimage;
- if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32)
- cam->dma_buf_size /= 2;
- }
if (n_dma_bufs > 3)
n_dma_bufs = 3;
@@ -1690,6 +1677,37 @@ static int cafe_vidioc_s_std(struct file
return 0;
}
+/*
+ * G/S_PARM. Most of this is done by the sensor, but we are
+ * the level which controls the number of read buffers.
+ */
+static int cafe_vidioc_g_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parms)
+{
+ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = __cafe_cam_cmd(cam, VIDIOC_G_PARM, parms);
+ mutex_unlock(&cam->s_mutex);
+ parms->parm.capture.readbuffers = n_dma_bufs;
+ return ret;
+}
+
+static int cafe_vidioc_s_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parms)
+{
+ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = __cafe_cam_cmd(cam, VIDIOC_S_PARM, parms);
+ mutex_unlock(&cam->s_mutex);
+ parms->parm.capture.readbuffers = n_dma_bufs;
+ return ret;
+}
+
+
/*
* The TV Norm stuff is weird - we're a camera with little to do with TV,
@@ -1757,7 +1775,8 @@ static struct video_device cafe_v4l_temp
.vidioc_queryctrl = cafe_vidioc_queryctrl,
.vidioc_g_ctrl = cafe_vidioc_g_ctrl,
.vidioc_s_ctrl = cafe_vidioc_s_ctrl,
- /* Do cropping someday */
+ .vidioc_g_parm = cafe_vidioc_g_parm,
+ .vidioc_s_parm = cafe_vidioc_s_parm,
};
@@ -1771,37 +1790,6 @@ static struct video_device cafe_v4l_temp
* Interrupt handler stuff
*/
-/*
- * Create RGB32 from RGB444 so it can be displayed before the applications
- * know about the latter format.
- */
-static void cafe_fake_rgb32(struct cafe_camera *cam, char *dest, char *src)
-{
- int i;
- u16 *ssrc = (u16 *) src;
-
- /* RGB444 version */
- for (i = 0; i < cam->pix_format.sizeimage; i += 4) {
- // dest[0] = (*ssrc & 0xf000) >> 8;
- dest[0] = (*ssrc & 0x000f) << 4;
- dest[1] = (*ssrc & 0x00f0);
- dest[2] = (*ssrc & 0x0f00) >> 4;
- dest[3] = (*ssrc & 0xf000); /* Alpha */
- dest += 4;
- ssrc++;
- }
-#if 0
- /* RGB565 version */
- for (i = 0; i < cam->pix_format.sizeimage; i += 4) {
- dest[0] = (*ssrc & 0xf800) >> 8;
- dest[1] = (*ssrc & 0x07e0) >> 3;
- dest[2] = (*ssrc & 0x001f) << 3;
- dest[3] = 0;
- dest += 4;
- ssrc++;
- }
-#endif
-}
static void cafe_frame_tasklet(unsigned long data)
@@ -1831,11 +1819,8 @@ static void cafe_frame_tasklet(unsigned
*/
sbuf = list_entry(cam->sb_avail.next,
struct cafe_sio_buffer, list);
- if (cam->pix_format.pixelformat == V4L2_PIX_FMT_RGB32)
- cafe_fake_rgb32(cam, sbuf->buffer, cam->dma_bufs[bufno]);
- else
- memcpy(sbuf->buffer, cam->dma_bufs[bufno],
- cam->pix_format.sizeimage);
+ memcpy(sbuf->buffer, cam->dma_bufs[bufno],
+ cam->pix_format.sizeimage);
sbuf->v4lbuf.bytesused = cam->pix_format.sizeimage;
sbuf->v4lbuf.sequence = cam->buf_seq[bufno];
sbuf->v4lbuf.flags &= ~V4L2_BUF_FLAG_QUEUED;
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 7206b8e..4fceabd 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -36,6 +36,11 @@ #define QCIF_WIDTH 176
#define QCIF_HEIGHT 144
/*
+ * Our nominal (default) frame rate.
+ */
+#define OV7670_FRAME_RATE 30
+
+/*
* The 7670 sits on i2c with ID 0x42
*/
#define OV7670_I2C_ADDR 0x42
@@ -291,7 +296,7 @@ static struct regval_list ov7670_default
{ 0xc9, 0x60 }, { REG_COM16, 0x38 },
{ 0x56, 0x40 },
- { 0x34, 0x11 }, { REG_COM11, COM11_EXP },
+ { 0x34, 0x11 }, { REG_COM11, COM11_EXP|COM11_HZAUTO },
{ 0xa4, 0x88 }, { 0x96, 0 },
{ 0x97, 0x30 }, { 0x98, 0x20 },
{ 0x99, 0x30 }, { 0x9a, 0x84 },
@@ -518,19 +523,6 @@ static struct ov7670_format_struct {
.regs = ov7670_fmt_rgb565,
.cmatrix = { 179, -179, 0, -61, -176, 228 },
},
- /*
- * Pretend we do RGB32. This is here on the assumption that the
- * upper layer will reformat RGB444 appropriately.
- *
- * The entire purpose for this thing's existence is to enable easy
- * display of RGB444 for debugging purposes. It will come out soon.
- */
- {
- .desc = "RGB32 (faked)",
- .pixelformat = V4L2_PIX_FMT_RGB32,
- .regs = ov7670_fmt_rgb444,
- .cmatrix = { 179, -179, 0, -61, -176, 228 },
- },
};
#define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0]))
@@ -715,8 +707,6 @@ static int ov7670_try_fmt(struct i2c_cli
pix->width = wsize->width;
pix->height = wsize->height;
pix->bytesperline = pix->width*BYTES_PER_PIXEL;
- if (pix->pixelformat == V4L2_PIX_FMT_RGB32)
- pix->bytesperline *= 2;
pix->sizeimage = pix->height*pix->bytesperline;
return 0;
}
@@ -758,6 +748,63 @@ static int ov7670_s_fmt(struct i2c_clien
}
/*
+ * Implement G/S_PARM. There is a "high quality" mode we could try
+ * to do someday; for now, we just do the frame rate tweak.
+ */
+static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+{
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ unsigned char clkrc;
+ int ret;
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ ret = ov7670_read(c, REG_CLKRC, &clkrc);
+ if (ret < 0)
+ return ret;
+ memset(cp, 0, sizeof(struct v4l2_captureparm));
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe.numerator = 1;
+ cp->timeperframe.denominator = OV7670_FRAME_RATE;
+ if ((clkrc & CLK_EXT) == 0 && (clkrc & CLK_SCALE) > 1)
+ cp->timeperframe.denominator /= (clkrc & CLK_SCALE);
+ return 0;
+}
+
+static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms)
+{
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ struct v4l2_fract *tpf = &cp->timeperframe;
+ unsigned char clkrc;
+ int ret, div;
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (cp->extendedmode != 0)
+ return -EINVAL;
+ /*
+ * CLKRC has a reserved bit, so let's preserve it.
+ */
+ ret = ov7670_read(c, REG_CLKRC, &clkrc);
+ if (ret < 0)
+ return ret;
+ if (tpf->numerator == 0 || tpf->denominator == 0)
+ div = 1; /* Reset to full rate */
+ else
+ div = (tpf->numerator*OV7670_FRAME_RATE)/tpf->denominator;
+ if (div == 0)
+ div = 1;
+ else if (div > CLK_SCALE)
+ div = CLK_SCALE;
+ clkrc = (clkrc & 0x80) | div;
+ tpf->numerator = 1;
+ tpf->denominator = OV7670_FRAME_RATE/div;
+ return ov7670_write(c, REG_CLKRC, clkrc);
+}
+
+
+
+/*
* Code for dealing with controls.
*/
@@ -1171,9 +1218,19 @@ static int ov7670_queryctrl(struct i2c_c
static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
{
- struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
+ struct ov7670_control *octrl;
int ret;
+ if (ctrl->id > V4L2_CID_PRIVATE_BASE) {
+ unsigned char reg = ctrl->id & 0xff;
+ unsigned char v;
+
+ ret = ov7670_read(client, reg, &v);
+ if (ret >= 0)
+ ctrl->value = v;
+ return ret;
+ }
+ octrl = ov7670_find_control(ctrl->id);
if (octrl == NULL)
return -EINVAL;
ret = octrl->query(client, &ctrl->value);
@@ -1184,9 +1241,14 @@ static int ov7670_g_ctrl(struct i2c_clie
static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
{
- struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
+ struct ov7670_control *octrl;
int ret;
+ if (ctrl->id > V4L2_CID_PRIVATE_BASE) {
+ unsigned char reg = ctrl->id & 0xff;
+ return ov7670_write(client, reg, ctrl->value);
+ }
+ octrl = ov7670_find_control(ctrl->id);
if (octrl == NULL)
return -EINVAL;
ret = octrl->tweak(client, ctrl->value);
@@ -1289,10 +1351,10 @@ static int ov7670_command(struct i2c_cli
return ov7670_s_ctrl(client, (struct v4l2_control *) arg);
case VIDIOC_G_CTRL:
return ov7670_g_ctrl(client, (struct v4l2_control *) arg);
- /* Todo:
- g/s_parm
- initialization
- */
+ case VIDIOC_S_PARM:
+ return ov7670_s_parm(client, (struct v4l2_streamparm *) arg);
+ case VIDIOC_G_PARM:
+ return ov7670_g_parm(client, (struct v4l2_streamparm *) arg);
}
return -EINVAL;
}
More information about the Commits-kernel
mailing list