summaryrefslogtreecommitdiffstats
path: root/drivers/media/usb/usbtv
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-12-16 18:39:16 +0100
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-16 18:39:16 +0100
commitbd9999cd6a5eb899504ce14c1f70c5479143bbbc (patch)
treeea8cba08f86c431d49cb3f58254dac8ca60e96d8 /drivers/media/usb/usbtv
parentMerge tag 'edac/v4.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mch... (diff)
parentMerge branch 'patchwork' into v4l_for_linus (diff)
downloadlinux-bd9999cd6a5eb899504ce14c1f70c5479143bbbc.tar.xz
linux-bd9999cd6a5eb899504ce14c1f70c5479143bbbc.zip
Merge tag 'media/v4.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab: - new Mediatek drivers: mtk-mdp and mtk-vcodec - some additions at the media documentation - the CEC core and drivers were promoted from staging to mainstream - some cleanups at the DVB core - the LIRC serial driver got promoted from staging to mainstream - added a driver for Renesas R-Car FDP1 driver - add DVBv5 statistics support to mn88473 driver - several fixes related to printk continuation lines - add support for HSV encoding formats - lots of other cleanups, fixups and driver improvements. * tag 'media/v4.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (496 commits) [media] v4l: tvp5150: Add missing break in set control handler [media] v4l: tvp5150: Don't inline the tvp5150_selmux() function [media] v4l: tvp5150: Compile tvp5150_link_setup out if !CONFIG_MEDIA_CONTROLLER [media] em28xx: don't store usb_device at struct em28xx [media] em28xx: use usb_interface for dev_foo() calls [media] em28xx: don't change the device's name [media] mn88472: fix chip id check on probe [media] mn88473: fix chip id check on probe [media] lirc: fix error paths in lirc_cdev_add() [media] s5p-mfc: Add support for MFC v8 available in Exynos 5433 SoCs [media] s5p-mfc: Rework clock handling [media] s5p-mfc: Don't keep clock prepared all the time [media] s5p-mfc: Kill all IS_ERR_OR_NULL in clocks management code [media] s5p-mfc: Remove dead conditional code [media] s5p-mfc: Ensure that clock is disabled before turning power off [media] s5p-mfc: Remove special clock rate management [media] s5p-mfc: Use printk_ratelimited for reporting ioctl errors [media] s5p-mfc: Set DMA_ATTR_ALLOC_SINGLE_PAGES [media] vivid: Set color_enc on HSV formats [media] v4l2-tpg: Init hv_enc field with a valid value ...
Diffstat (limited to 'drivers/media/usb/usbtv')
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c105
-rw-r--r--drivers/media/usb/usbtv/usbtv.h3
2 files changed, 107 insertions, 1 deletions
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index 6cbe4a245c9f..d3b6d3dfaa09 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013 Lubomir Rintel
+ * Copyright (c) 2013,2016 Lubomir Rintel
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -259,6 +259,10 @@ static int usbtv_setup_capture(struct usbtv *usbtv)
if (ret)
return ret;
+ ret = v4l2_ctrl_handler_setup(&usbtv->ctrl);
+ if (ret)
+ return ret;
+
return 0;
}
@@ -696,11 +700,91 @@ static const struct vb2_ops usbtv_vb2_ops = {
.stop_streaming = usbtv_stop_streaming,
};
+static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct usbtv *usbtv = container_of(ctrl->handler, struct usbtv,
+ ctrl);
+ u8 *data;
+ u16 index, size;
+ int ret;
+
+ data = kmalloc(3, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ /*
+ * Read in the current brightness/contrast registers. We need them
+ * both, because the values are for some reason interleaved.
+ */
+ if (ctrl->id == V4L2_CID_BRIGHTNESS || ctrl->id == V4L2_CID_CONTRAST) {
+ ret = usb_control_msg(usbtv->udev,
+ usb_sndctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, USBTV_BASE + 0x0244, (void *)data, 3, 0);
+ if (ret < 0)
+ goto error;
+ }
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ index = USBTV_BASE + 0x0244;
+ size = 3;
+ data[0] &= 0xf0;
+ data[0] |= (ctrl->val >> 8) & 0xf;
+ data[2] = ctrl->val & 0xff;
+ break;
+ case V4L2_CID_CONTRAST:
+ index = USBTV_BASE + 0x0244;
+ size = 3;
+ data[0] &= 0x0f;
+ data[0] |= (ctrl->val >> 4) & 0xf0;
+ data[1] = ctrl->val & 0xff;
+ break;
+ case V4L2_CID_SATURATION:
+ index = USBTV_BASE + 0x0242;
+ data[0] = ctrl->val >> 8;
+ data[1] = ctrl->val & 0xff;
+ size = 2;
+ break;
+ case V4L2_CID_HUE:
+ index = USBTV_BASE + 0x0240;
+ size = 2;
+ if (ctrl->val > 0) {
+ data[0] = 0x92 + (ctrl->val >> 8);
+ data[1] = ctrl->val & 0xff;
+ } else {
+ data[0] = 0x82 + (-ctrl->val >> 8);
+ data[1] = -ctrl->val & 0xff;
+ }
+ break;
+ default:
+ kfree(data);
+ return -EINVAL;
+ }
+
+ ret = usb_control_msg(usbtv->udev, usb_sndctrlpipe(usbtv->udev, 0),
+ USBTV_CONTROL_REG,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, index, (void *)data, size, 0);
+
+error:
+ if (ret < 0)
+ dev_warn(usbtv->dev, "Failed to submit a control request.\n");
+
+ kfree(data);
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops usbtv_ctrl_ops = {
+ .s_ctrl = usbtv_s_ctrl,
+};
+
static void usbtv_release(struct v4l2_device *v4l2_dev)
{
struct usbtv *usbtv = container_of(v4l2_dev, struct usbtv, v4l2_dev);
v4l2_device_unregister(&usbtv->v4l2_dev);
+ v4l2_ctrl_handler_free(&usbtv->ctrl);
vb2_queue_release(&usbtv->vb2q);
kfree(usbtv);
}
@@ -731,7 +815,24 @@ int usbtv_video_init(struct usbtv *usbtv)
return ret;
}
+ /* controls */
+ v4l2_ctrl_handler_init(&usbtv->ctrl, 4);
+ v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 0x3ff, 1, 0x1d0);
+ v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 0x3ff, 1, 0x1c0);
+ v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 0x3ff, 1, 0x200);
+ v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops,
+ V4L2_CID_HUE, -0xdff, 0xdff, 1, 0x000);
+ ret = usbtv->ctrl.error;
+ if (ret < 0) {
+ dev_warn(usbtv->dev, "Could not initialize controls\n");
+ goto ctrl_fail;
+ }
+
/* v4l2 structure */
+ usbtv->v4l2_dev.ctrl_handler = &usbtv->ctrl;
usbtv->v4l2_dev.release = usbtv_release;
ret = v4l2_device_register(usbtv->dev, &usbtv->v4l2_dev);
if (ret < 0) {
@@ -760,6 +861,8 @@ int usbtv_video_init(struct usbtv *usbtv)
vdev_fail:
v4l2_device_unregister(&usbtv->v4l2_dev);
v4l2_fail:
+ctrl_fail:
+ v4l2_ctrl_handler_free(&usbtv->ctrl);
vb2_queue_release(&usbtv->vb2q);
return ret;
diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h
index 011f9fdc77a9..0231e449877e 100644
--- a/drivers/media/usb/usbtv/usbtv.h
+++ b/drivers/media/usb/usbtv/usbtv.h
@@ -38,6 +38,7 @@
#include <linux/usb.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
@@ -45,6 +46,7 @@
#define USBTV_VIDEO_ENDP 0x81
#define USBTV_AUDIO_ENDP 0x83
#define USBTV_BASE 0xc000
+#define USBTV_CONTROL_REG 11
#define USBTV_REQUEST_REG 12
/* Number of concurrent isochronous urbs submitted.
@@ -87,6 +89,7 @@ struct usbtv {
/* video */
struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl;
struct video_device vdev;
struct vb2_queue vb2q;
struct mutex v4l2_lock;