diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-16 18:39:16 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-16 18:39:16 +0100 |
commit | bd9999cd6a5eb899504ce14c1f70c5479143bbbc (patch) | |
tree | ea8cba08f86c431d49cb3f58254dac8ca60e96d8 /drivers/media/usb/usbtv | |
parent | Merge tag 'edac/v4.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mch... (diff) | |
parent | Merge branch 'patchwork' into v4l_for_linus (diff) | |
download | linux-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.c | 105 | ||||
-rw-r--r-- | drivers/media/usb/usbtv/usbtv.h | 3 |
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; |