[media] v4l2: add const to argument of write-only s_register ioctl
[sfrench/cifs-2.6.git] / drivers / media / usb / em28xx / em28xx-video.c
index 9451e1ed0ec83cc4d211dcaa85b0ba737ae81d79..d09b5c03c723042766913583fc9d47c82b22e004 100644 (file)
@@ -52,7 +52,7 @@
 
 #define DRIVER_DESC         "Empia em28xx based USB video device driver"
 
-#define EM28XX_VERSION "0.1.3"
+#define EM28XX_VERSION "0.2.0"
 
 #define em28xx_videodbg(fmt, arg...) do {\
        if (video_debug) \
@@ -700,6 +700,7 @@ int em28xx_vb2_setup(struct em28xx *dev)
        q = &dev->vb_vidq;
        q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+       q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
        q->drv_priv = dev;
        q->buf_struct_size = sizeof(struct em28xx_buffer);
        q->ops = &em28xx_video_qops;
@@ -713,6 +714,7 @@ int em28xx_vb2_setup(struct em28xx *dev)
        q = &dev->vb_vbiq;
        q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
        q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
+       q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
        q->drv_priv = dev;
        q->buf_struct_size = sizeof(struct em28xx_buffer);
        q->ops = &em28xx_vbi_qops;
@@ -782,24 +784,45 @@ void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
 static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct em28xx *dev = container_of(ctrl->handler, struct em28xx, ctrl_handler);
+       int ret = -EINVAL;
 
        switch (ctrl->id) {
        case V4L2_CID_AUDIO_MUTE:
                dev->mute = ctrl->val;
+               ret = em28xx_audio_analog_set(dev);
                break;
        case V4L2_CID_AUDIO_VOLUME:
                dev->volume = ctrl->val;
+               ret = em28xx_audio_analog_set(dev);
+               break;
+       case V4L2_CID_CONTRAST:
+               ret = em28xx_write_reg(dev, EM28XX_R20_YGAIN, ctrl->val);
+               break;
+       case V4L2_CID_BRIGHTNESS:
+               ret = em28xx_write_reg(dev, EM28XX_R21_YOFFSET, ctrl->val);
+               break;
+       case V4L2_CID_SATURATION:
+               ret = em28xx_write_reg(dev, EM28XX_R22_UVGAIN, ctrl->val);
+               break;
+       case V4L2_CID_BLUE_BALANCE:
+               ret = em28xx_write_reg(dev, EM28XX_R23_UOFFSET, ctrl->val);
+               break;
+       case V4L2_CID_RED_BALANCE:
+               ret = em28xx_write_reg(dev, EM28XX_R24_VOFFSET, ctrl->val);
+               break;
+       case V4L2_CID_SHARPNESS:
+               ret = em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, ctrl->val);
                break;
        }
 
-       return em28xx_audio_analog_set(dev);
+       return (ret < 0) ? ret : 0;
 }
 
 const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
        .s_ctrl = em28xx_s_ctrl,
 };
 
-static void get_scale(struct em28xx *dev,
+static void size_to_scale(struct em28xx *dev,
                        unsigned int width, unsigned int height,
                        unsigned int *hscale, unsigned int *vscale)
 {
@@ -815,6 +838,17 @@ static void get_scale(struct em28xx *dev,
                *vscale = EM28XX_HVSCALE_MAX;
 }
 
+static void scale_to_size(struct em28xx *dev,
+                         unsigned int hscale, unsigned int vscale,
+                         unsigned int *width, unsigned int *height)
+{
+       unsigned int          maxw = norm_maxw(dev);
+       unsigned int          maxh = norm_maxh(dev);
+
+       *width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
+       *height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+}
+
 /* ------------------------------------------------------------------
        IOCTL vidioc handling
    ------------------------------------------------------------------*/
@@ -889,10 +923,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                                      1, 0);
        }
 
-       get_scale(dev, width, height, &hscale, &vscale);
-
-       width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
-       height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
+       size_to_scale(dev, width, height, &hscale, &vscale);
+       scale_to_size(dev, hscale, hscale, &width, &height);
 
        f->fmt.pix.width = width;
        f->fmt.pix.height = height;
@@ -923,7 +955,7 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
        dev->height = height;
 
        /* set new image size */
-       get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+       size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
 
        em28xx_resolution_set(dev);
 
@@ -964,29 +996,29 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
        return 0;
 }
 
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
 {
        struct em28xx_fh   *fh  = priv;
        struct em28xx      *dev = fh->dev;
        struct v4l2_format f;
 
-       if (*norm == dev->norm)
+       if (norm == dev->norm)
                return 0;
 
        if (dev->streaming_users > 0)
                return -EBUSY;
 
-       dev->norm = *norm;
+       dev->norm = norm;
 
        /* Adjusts width/height, if needed */
        f.fmt.pix.width = 720;
-       f.fmt.pix.height = (*norm & V4L2_STD_525_60) ? 480 : 576;
+       f.fmt.pix.height = (norm & V4L2_STD_525_60) ? 480 : 576;
        vidioc_try_fmt_vid_cap(file, priv, &f);
 
        /* set new image size */
        dev->width = f.fmt.pix.width;
        dev->height = f.fmt.pix.height;
-       get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+       size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
 
        em28xx_resolution_set(dev);
        v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
@@ -1163,7 +1195,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 }
 
 static int vidioc_s_tuner(struct file *file, void *priv,
-                               struct v4l2_tuner *t)
+                               const struct v4l2_tuner *t)
 {
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
@@ -1189,8 +1221,9 @@ static int vidioc_g_frequency(struct file *file, void *priv,
 }
 
 static int vidioc_s_frequency(struct file *file, void *priv,
-                               struct v4l2_frequency *f)
+                               const struct v4l2_frequency *f)
 {
+       struct v4l2_frequency new_freq = *f;
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
 
@@ -1198,8 +1231,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
                return -EINVAL;
 
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
-       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, f);
-       dev->ctl_freq = f->frequency;
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq);
+       dev->ctl_freq = new_freq.frequency;
 
        return 0;
 }
@@ -1290,7 +1323,7 @@ static int vidioc_g_register(struct file *file, void *priv,
 }
 
 static int vidioc_s_register(struct file *file, void *priv,
-                            struct v4l2_dbg_register *reg)
+                            const struct v4l2_dbg_register *reg)
 {
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
@@ -1396,8 +1429,12 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
 
        /* Report a continuous range */
        fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
-       fsize->stepwise.min_width = 48;
-       fsize->stepwise.min_height = 32;
+       scale_to_size(dev, EM28XX_HVSCALE_MAX, EM28XX_HVSCALE_MAX,
+                     &fsize->stepwise.min_width, &fsize->stepwise.min_height);
+       if (fsize->stepwise.min_width < 48)
+               fsize->stepwise.min_width = 48;
+       if (fsize->stepwise.min_height < 38)
+               fsize->stepwise.min_height = 38;
        fsize->stepwise.max_width = maxw;
        fsize->stepwise.max_height = maxh;
        fsize->stepwise.step_width = 1;
@@ -1456,7 +1493,7 @@ static int radio_g_tuner(struct file *file, void *priv,
 }
 
 static int radio_s_tuner(struct file *file, void *priv,
-                        struct v4l2_tuner *t)
+                        const struct v4l2_tuner *t)
 {
        struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
 
@@ -1771,9 +1808,42 @@ int em28xx_register_analog_devices(struct em28xx *dev)
                         (EM28XX_XCLK_AUDIO_UNMUTE | val));
 
        em28xx_set_outfmt(dev);
-       em28xx_colorlevels_set_default(dev);
        em28xx_compression_disable(dev);
 
+       /* Add image controls */
+       /* NOTE: at this point, the subdevices are already registered, so bridge
+        * controls are only added/enabled when no subdevice provides them */
+       if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_CONTRAST))
+               v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+                                 V4L2_CID_CONTRAST,
+                                 0, 0x1f, 1, CONTRAST_DEFAULT);
+       if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BRIGHTNESS))
+               v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+                                 V4L2_CID_BRIGHTNESS,
+                                 -0x80, 0x7f, 1, BRIGHTNESS_DEFAULT);
+       if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SATURATION))
+               v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+                                 V4L2_CID_SATURATION,
+                                 0, 0x1f, 1, SATURATION_DEFAULT);
+       if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BLUE_BALANCE))
+               v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+                                 V4L2_CID_BLUE_BALANCE,
+                                 -0x30, 0x30, 1, BLUE_BALANCE_DEFAULT);
+       if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RED_BALANCE))
+               v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+                                 V4L2_CID_RED_BALANCE,
+                                 -0x30, 0x30, 1, RED_BALANCE_DEFAULT);
+       if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SHARPNESS))
+               v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+                                 V4L2_CID_SHARPNESS,
+                                 0, 0x0f, 1, SHARPNESS_DEFAULT);
+
+       /* Reset image controls */
+       em28xx_colorlevels_set_default(dev);
+       v4l2_ctrl_handler_setup(&dev->ctrl_handler);
+       if (dev->ctrl_handler.error)
+               return dev->ctrl_handler.error;
+
        /* allocate and fill video video_device struct */
        dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
        if (!dev->vdev) {