aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2012-04-08 11:59:51 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-05-07 15:35:05 -0400
commitb4012002f3a3983ba2797fde1613691d7f287048 (patch)
tree149ff2a22013fb77efd8bb374b9069083f4d5cd5
parentcb74d482f81bf6a3ef3e29cb228c917e371773f2 (diff)
[media] uvcvideo: Add support for control events
Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c121
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c43
-rw-r--r--drivers/media/video/uvc/uvcvideo.h20
3 files changed, 170 insertions, 14 deletions
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 0c27cc154eaf..f15a437e5861 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -21,6 +21,7 @@
21#include <linux/vmalloc.h> 21#include <linux/vmalloc.h>
22#include <linux/wait.h> 22#include <linux/wait.h>
23#include <linux/atomic.h> 23#include <linux/atomic.h>
24#include <media/v4l2-ctrls.h>
24 25
25#include "uvcvideo.h" 26#include "uvcvideo.h"
26 27
@@ -1102,6 +1103,117 @@ done:
1102 return ret; 1103 return ret;
1103} 1104}
1104 1105
1106/* --------------------------------------------------------------------------
1107 * Ctrl event handling
1108 */
1109
1110static void uvc_ctrl_fill_event(struct uvc_video_chain *chain,
1111 struct v4l2_event *ev,
1112 struct uvc_control *ctrl,
1113 struct uvc_control_mapping *mapping,
1114 s32 value, u32 changes)
1115{
1116 struct v4l2_queryctrl v4l2_ctrl;
1117
1118 __uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl);
1119
1120 memset(ev->reserved, 0, sizeof(ev->reserved));
1121 ev->type = V4L2_EVENT_CTRL;
1122 ev->id = v4l2_ctrl.id;
1123 ev->u.ctrl.value = value;
1124 ev->u.ctrl.changes = changes;
1125 ev->u.ctrl.type = v4l2_ctrl.type;
1126 ev->u.ctrl.flags = v4l2_ctrl.flags;
1127 ev->u.ctrl.minimum = v4l2_ctrl.minimum;
1128 ev->u.ctrl.maximum = v4l2_ctrl.maximum;
1129 ev->u.ctrl.step = v4l2_ctrl.step;
1130 ev->u.ctrl.default_value = v4l2_ctrl.default_value;
1131}
1132
1133static void uvc_ctrl_send_event(struct uvc_fh *handle,
1134 struct uvc_control *ctrl, struct uvc_control_mapping *mapping,
1135 s32 value, u32 changes)
1136{
1137 struct v4l2_subscribed_event *sev;
1138 struct v4l2_event ev;
1139
1140 if (list_empty(&mapping->ev_subs))
1141 return;
1142
1143 uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, value, changes);
1144
1145 list_for_each_entry(sev, &mapping->ev_subs, node) {
1146 if (sev->fh && (sev->fh != &handle->vfh ||
1147 (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK)))
1148 v4l2_event_queue_fh(sev->fh, &ev);
1149 }
1150}
1151
1152static void uvc_ctrl_send_events(struct uvc_fh *handle,
1153 const struct v4l2_ext_control *xctrls, unsigned int xctrls_count)
1154{
1155 struct uvc_control_mapping *mapping;
1156 struct uvc_control *ctrl;
1157 unsigned int i;
1158
1159 for (i = 0; i < xctrls_count; ++i) {
1160 ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping);
1161 uvc_ctrl_send_event(handle, ctrl, mapping, xctrls[i].value,
1162 V4L2_EVENT_CTRL_CH_VALUE);
1163 }
1164}
1165
1166static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev)
1167{
1168 struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
1169 struct uvc_control_mapping *mapping;
1170 struct uvc_control *ctrl;
1171 int ret;
1172
1173 ret = mutex_lock_interruptible(&handle->chain->ctrl_mutex);
1174 if (ret < 0)
1175 return -ERESTARTSYS;
1176
1177 ctrl = uvc_find_control(handle->chain, sev->id, &mapping);
1178 if (ctrl == NULL) {
1179 ret = -EINVAL;
1180 goto done;
1181 }
1182
1183 list_add_tail(&sev->node, &mapping->ev_subs);
1184 if (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) {
1185 struct v4l2_event ev;
1186 u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
1187 s32 val = 0;
1188
1189 if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
1190 changes |= V4L2_EVENT_CTRL_CH_VALUE;
1191
1192 uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val,
1193 changes);
1194 v4l2_event_queue_fh(sev->fh, &ev);
1195 }
1196
1197done:
1198 mutex_unlock(&handle->chain->ctrl_mutex);
1199 return ret;
1200}
1201
1202static void uvc_ctrl_del_event(struct v4l2_subscribed_event *sev)
1203{
1204 struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
1205
1206 mutex_lock(&handle->chain->ctrl_mutex);
1207 list_del(&sev->node);
1208 mutex_unlock(&handle->chain->ctrl_mutex);
1209}
1210
1211const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops = {
1212 .add = uvc_ctrl_add_event,
1213 .del = uvc_ctrl_del_event,
1214 .replace = v4l2_ctrl_replace,
1215 .merge = v4l2_ctrl_merge,
1216};
1105 1217
1106/* -------------------------------------------------------------------------- 1218/* --------------------------------------------------------------------------
1107 * Control transactions 1219 * Control transactions
@@ -1179,8 +1291,11 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
1179 return 0; 1291 return 0;
1180} 1292}
1181 1293
1182int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback) 1294int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
1295 const struct v4l2_ext_control *xctrls,
1296 unsigned int xctrls_count)
1183{ 1297{
1298 struct uvc_video_chain *chain = handle->chain;
1184 struct uvc_entity *entity; 1299 struct uvc_entity *entity;
1185 int ret = 0; 1300 int ret = 0;
1186 1301
@@ -1191,6 +1306,8 @@ int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback)
1191 goto done; 1306 goto done;
1192 } 1307 }
1193 1308
1309 if (!rollback)
1310 uvc_ctrl_send_events(handle, xctrls, xctrls_count);
1194done: 1311done:
1195 mutex_unlock(&chain->ctrl_mutex); 1312 mutex_unlock(&chain->ctrl_mutex);
1196 return ret; 1313 return ret;
@@ -1662,6 +1779,8 @@ static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
1662 if (map == NULL) 1779 if (map == NULL)
1663 return -ENOMEM; 1780 return -ENOMEM;
1664 1781
1782 INIT_LIST_HEAD(&map->ev_subs);
1783
1665 size = sizeof(*mapping->menu_info) * mapping->menu_count; 1784 size = sizeof(*mapping->menu_info) * mapping->menu_count;
1666 map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL); 1785 map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
1667 if (map->menu_info == NULL) { 1786 if (map->menu_info == NULL) {
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 4ef21e9cb28c..a3322ed81e39 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -25,6 +25,8 @@
25#include <linux/atomic.h> 25#include <linux/atomic.h>
26 26
27#include <media/v4l2-common.h> 27#include <media/v4l2-common.h>
28#include <media/v4l2-ctrls.h>
29#include <media/v4l2-event.h>
28#include <media/v4l2-ioctl.h> 30#include <media/v4l2-ioctl.h>
29 31
30#include "uvcvideo.h" 32#include "uvcvideo.h"
@@ -505,6 +507,8 @@ static int uvc_v4l2_open(struct file *file)
505 } 507 }
506 } 508 }
507 509
510 v4l2_fh_init(&handle->vfh, stream->vdev);
511 v4l2_fh_add(&handle->vfh);
508 handle->chain = stream->chain; 512 handle->chain = stream->chain;
509 handle->stream = stream; 513 handle->stream = stream;
510 handle->state = UVC_HANDLE_PASSIVE; 514 handle->state = UVC_HANDLE_PASSIVE;
@@ -528,6 +532,8 @@ static int uvc_v4l2_release(struct file *file)
528 532
529 /* Release the file handle. */ 533 /* Release the file handle. */
530 uvc_dismiss_privileges(handle); 534 uvc_dismiss_privileges(handle);
535 v4l2_fh_del(&handle->vfh);
536 v4l2_fh_exit(&handle->vfh);
531 kfree(handle); 537 kfree(handle);
532 file->private_data = NULL; 538 file->private_data = NULL;
533 539
@@ -584,7 +590,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
584 return ret; 590 return ret;
585 591
586 ret = uvc_ctrl_get(chain, &xctrl); 592 ret = uvc_ctrl_get(chain, &xctrl);
587 uvc_ctrl_rollback(chain); 593 uvc_ctrl_rollback(handle);
588 if (ret >= 0) 594 if (ret >= 0)
589 ctrl->value = xctrl.value; 595 ctrl->value = xctrl.value;
590 break; 596 break;
@@ -605,10 +611,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
605 611
606 ret = uvc_ctrl_set(chain, &xctrl); 612 ret = uvc_ctrl_set(chain, &xctrl);
607 if (ret < 0) { 613 if (ret < 0) {
608 uvc_ctrl_rollback(chain); 614 uvc_ctrl_rollback(handle);
609 return ret; 615 return ret;
610 } 616 }
611 ret = uvc_ctrl_commit(chain); 617 ret = uvc_ctrl_commit(handle, &xctrl, 1);
612 if (ret == 0) 618 if (ret == 0)
613 ctrl->value = xctrl.value; 619 ctrl->value = xctrl.value;
614 break; 620 break;
@@ -630,13 +636,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
630 for (i = 0; i < ctrls->count; ++ctrl, ++i) { 636 for (i = 0; i < ctrls->count; ++ctrl, ++i) {
631 ret = uvc_ctrl_get(chain, ctrl); 637 ret = uvc_ctrl_get(chain, ctrl);
632 if (ret < 0) { 638 if (ret < 0) {
633 uvc_ctrl_rollback(chain); 639 uvc_ctrl_rollback(handle);
634 ctrls->error_idx = i; 640 ctrls->error_idx = i;
635 return ret; 641 return ret;
636 } 642 }
637 } 643 }
638 ctrls->error_idx = 0; 644 ctrls->error_idx = 0;
639 ret = uvc_ctrl_rollback(chain); 645 ret = uvc_ctrl_rollback(handle);
640 break; 646 break;
641 } 647 }
642 648
@@ -654,7 +660,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
654 for (i = 0; i < ctrls->count; ++ctrl, ++i) { 660 for (i = 0; i < ctrls->count; ++ctrl, ++i) {
655 ret = uvc_ctrl_set(chain, ctrl); 661 ret = uvc_ctrl_set(chain, ctrl);
656 if (ret < 0) { 662 if (ret < 0) {
657 uvc_ctrl_rollback(chain); 663 uvc_ctrl_rollback(handle);
658 ctrls->error_idx = i; 664 ctrls->error_idx = i;
659 return ret; 665 return ret;
660 } 666 }
@@ -663,9 +669,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
663 ctrls->error_idx = 0; 669 ctrls->error_idx = 0;
664 670
665 if (cmd == VIDIOC_S_EXT_CTRLS) 671 if (cmd == VIDIOC_S_EXT_CTRLS)
666 ret = uvc_ctrl_commit(chain); 672 ret = uvc_ctrl_commit(handle,
673 ctrls->controls, ctrls->count);
667 else 674 else
668 ret = uvc_ctrl_rollback(chain); 675 ret = uvc_ctrl_rollback(handle);
669 break; 676 break;
670 } 677 }
671 678
@@ -990,6 +997,26 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
990 return uvc_video_enable(stream, 0); 997 return uvc_video_enable(stream, 0);
991 } 998 }
992 999
1000 case VIDIOC_SUBSCRIBE_EVENT:
1001 {
1002 struct v4l2_event_subscription *sub = arg;
1003
1004 switch (sub->type) {
1005 case V4L2_EVENT_CTRL:
1006 return v4l2_event_subscribe(&handle->vfh, sub, 0,
1007 &uvc_ctrl_sub_ev_ops);
1008 default:
1009 return -EINVAL;
1010 }
1011 }
1012
1013 case VIDIOC_UNSUBSCRIBE_EVENT:
1014 return v4l2_event_unsubscribe(&handle->vfh, arg);
1015
1016 case VIDIOC_DQEVENT:
1017 return v4l2_event_dequeue(&handle->vfh, arg,
1018 file->f_flags & O_NONBLOCK);
1019
993 /* Analog video standards make no sense for digital cameras. */ 1020 /* Analog video standards make no sense for digital cameras. */
994 case VIDIOC_ENUMSTD: 1021 case VIDIOC_ENUMSTD:
995 case VIDIOC_QUERYSTD: 1022 case VIDIOC_QUERYSTD:
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index 67f88d85bb16..e43deb715d98 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -13,6 +13,8 @@
13#include <linux/videodev2.h> 13#include <linux/videodev2.h>
14#include <media/media-device.h> 14#include <media/media-device.h>
15#include <media/v4l2-device.h> 15#include <media/v4l2-device.h>
16#include <media/v4l2-event.h>
17#include <media/v4l2-fh.h>
16#include <media/videobuf2-core.h> 18#include <media/videobuf2-core.h>
17 19
18/* -------------------------------------------------------------------------- 20/* --------------------------------------------------------------------------
@@ -153,6 +155,7 @@ struct uvc_control_info {
153 155
154struct uvc_control_mapping { 156struct uvc_control_mapping {
155 struct list_head list; 157 struct list_head list;
158 struct list_head ev_subs;
156 159
157 struct uvc_control_info *ctrl; 160 struct uvc_control_info *ctrl;
158 161
@@ -524,6 +527,7 @@ enum uvc_handle_state {
524}; 527};
525 528
526struct uvc_fh { 529struct uvc_fh {
530 struct v4l2_fh vfh;
527 struct uvc_video_chain *chain; 531 struct uvc_video_chain *chain;
528 struct uvc_streaming *stream; 532 struct uvc_streaming *stream;
529 enum uvc_handle_state state; 533 enum uvc_handle_state state;
@@ -643,6 +647,8 @@ extern int uvc_status_suspend(struct uvc_device *dev);
643extern int uvc_status_resume(struct uvc_device *dev); 647extern int uvc_status_resume(struct uvc_device *dev);
644 648
645/* Controls */ 649/* Controls */
650extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
651
646extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, 652extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
647 struct v4l2_queryctrl *v4l2_ctrl); 653 struct v4l2_queryctrl *v4l2_ctrl);
648extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain, 654extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
@@ -655,14 +661,18 @@ extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
655extern int uvc_ctrl_resume_device(struct uvc_device *dev); 661extern int uvc_ctrl_resume_device(struct uvc_device *dev);
656 662
657extern int uvc_ctrl_begin(struct uvc_video_chain *chain); 663extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
658extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback); 664extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
659static inline int uvc_ctrl_commit(struct uvc_video_chain *chain) 665 const struct v4l2_ext_control *xctrls,
666 unsigned int xctrls_count);
667static inline int uvc_ctrl_commit(struct uvc_fh *handle,
668 const struct v4l2_ext_control *xctrls,
669 unsigned int xctrls_count)
660{ 670{
661 return __uvc_ctrl_commit(chain, 0); 671 return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count);
662} 672}
663static inline int uvc_ctrl_rollback(struct uvc_video_chain *chain) 673static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
664{ 674{
665 return __uvc_ctrl_commit(chain, 1); 675 return __uvc_ctrl_commit(handle, 1, NULL, 0);
666} 676}
667 677
668extern int uvc_ctrl_get(struct uvc_video_chain *chain, 678extern int uvc_ctrl_get(struct uvc_video_chain *chain,