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;
+}
+
+
 static void cafe_v4l_dev_release(struct video_device *vd)
 {
        struct cafe_camera *cam = container_of(vd, struct cafe_camera, v4ldev);
        .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,
 };
 
 
 
 #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
  */
        { 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 },
        return 0;
 }
 
+/*
+ * 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.
  */
                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;
 }