aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/v4l2-ctrls.c
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2011-06-07 10:13:44 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-07-27 16:53:20 -0400
commit6e239399e5807132f86f64af6c659411c6a3d1a5 (patch)
treeeeb564a25341111f1c7d6e92137e910c4e4d37f3 /drivers/media/video/v4l2-ctrls.c
parentab892bac8438c5c2ff09a60d765d9b0c14941ba9 (diff)
[media] v4l2-ctrls: add control events
Whenever a control changes value or state an event is sent to anyone that subscribed to it. This functionality is useful for control panels but also for applications that need to wait for (usually status) controls to change value. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/v4l2-ctrls.c')
-rw-r--r--drivers/media/video/v4l2-ctrls.c115
1 files changed, 110 insertions, 5 deletions
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
index 70dbeeef6a2e..5f316667c142 100644
--- a/drivers/media/video/v4l2-ctrls.c
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -23,6 +23,7 @@
23#include <media/v4l2-ioctl.h> 23#include <media/v4l2-ioctl.h>
24#include <media/v4l2-device.h> 24#include <media/v4l2-device.h>
25#include <media/v4l2-ctrls.h> 25#include <media/v4l2-ctrls.h>
26#include <media/v4l2-event.h>
26#include <media/v4l2-dev.h> 27#include <media/v4l2-dev.h>
27 28
28#define has_op(master, op) \ 29#define has_op(master, op) \
@@ -556,6 +557,41 @@ static bool type_is_int(const struct v4l2_ctrl *ctrl)
556 } 557 }
557} 558}
558 559
560static void fill_event(struct v4l2_event *ev, struct v4l2_ctrl *ctrl, u32 changes)
561{
562 memset(ev->reserved, 0, sizeof(ev->reserved));
563 ev->type = V4L2_EVENT_CTRL;
564 ev->id = ctrl->id;
565 ev->u.ctrl.changes = changes;
566 ev->u.ctrl.type = ctrl->type;
567 ev->u.ctrl.flags = ctrl->flags;
568 if (ctrl->type == V4L2_CTRL_TYPE_STRING)
569 ev->u.ctrl.value64 = 0;
570 else
571 ev->u.ctrl.value64 = ctrl->cur.val64;
572 ev->u.ctrl.minimum = ctrl->minimum;
573 ev->u.ctrl.maximum = ctrl->maximum;
574 if (ctrl->type == V4L2_CTRL_TYPE_MENU)
575 ev->u.ctrl.step = 1;
576 else
577 ev->u.ctrl.step = ctrl->step;
578 ev->u.ctrl.default_value = ctrl->default_value;
579}
580
581static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
582{
583 struct v4l2_event ev;
584 struct v4l2_ctrl_fh *pos;
585
586 if (list_empty(&ctrl->fhs))
587 return;
588 fill_event(&ev, ctrl, changes);
589
590 list_for_each_entry(pos, &ctrl->fhs, node)
591 if (pos->fh != fh)
592 v4l2_event_queue_fh(pos->fh, &ev);
593}
594
559/* Helper function: copy the current control value back to the caller */ 595/* Helper function: copy the current control value back to the caller */
560static int cur_to_user(struct v4l2_ext_control *c, 596static int cur_to_user(struct v4l2_ext_control *c,
561 struct v4l2_ctrl *ctrl) 597 struct v4l2_ctrl *ctrl)
@@ -660,17 +696,25 @@ static int ctrl_is_volatile(struct v4l2_ext_control *c,
660static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, 696static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
661 bool update_inactive) 697 bool update_inactive)
662{ 698{
699 bool changed = false;
700
663 if (ctrl == NULL) 701 if (ctrl == NULL)
664 return; 702 return;
665 switch (ctrl->type) { 703 switch (ctrl->type) {
704 case V4L2_CTRL_TYPE_BUTTON:
705 changed = true;
706 break;
666 case V4L2_CTRL_TYPE_STRING: 707 case V4L2_CTRL_TYPE_STRING:
667 /* strings are always 0-terminated */ 708 /* strings are always 0-terminated */
709 changed = strcmp(ctrl->string, ctrl->cur.string);
668 strcpy(ctrl->cur.string, ctrl->string); 710 strcpy(ctrl->cur.string, ctrl->string);
669 break; 711 break;
670 case V4L2_CTRL_TYPE_INTEGER64: 712 case V4L2_CTRL_TYPE_INTEGER64:
713 changed = ctrl->val64 != ctrl->cur.val64;
671 ctrl->cur.val64 = ctrl->val64; 714 ctrl->cur.val64 = ctrl->val64;
672 break; 715 break;
673 default: 716 default:
717 changed = ctrl->val != ctrl->cur.val;
674 ctrl->cur.val = ctrl->val; 718 ctrl->cur.val = ctrl->val;
675 break; 719 break;
676 } 720 }
@@ -679,6 +723,10 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
679 if (!is_cur_manual(ctrl->cluster[0])) 723 if (!is_cur_manual(ctrl->cluster[0]))
680 ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; 724 ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
681 } 725 }
726 if (changed || update_inactive)
727 send_event(fh, ctrl,
728 (changed ? V4L2_EVENT_CTRL_CH_VALUE : 0) |
729 (update_inactive ? V4L2_EVENT_CTRL_CH_FLAGS : 0));
682} 730}
683 731
684/* Copy the current value to the new value */ 732/* Copy the current value to the new value */
@@ -819,6 +867,7 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
819{ 867{
820 struct v4l2_ctrl_ref *ref, *next_ref; 868 struct v4l2_ctrl_ref *ref, *next_ref;
821 struct v4l2_ctrl *ctrl, *next_ctrl; 869 struct v4l2_ctrl *ctrl, *next_ctrl;
870 struct v4l2_ctrl_fh *ctrl_fh, *next_ctrl_fh;
822 871
823 if (hdl == NULL || hdl->buckets == NULL) 872 if (hdl == NULL || hdl->buckets == NULL)
824 return; 873 return;
@@ -832,6 +881,10 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
832 /* Free all controls owned by the handler */ 881 /* Free all controls owned by the handler */
833 list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) { 882 list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
834 list_del(&ctrl->node); 883 list_del(&ctrl->node);
884 list_for_each_entry_safe(ctrl_fh, next_ctrl_fh, &ctrl->fhs, node) {
885 list_del(&ctrl_fh->node);
886 kfree(ctrl_fh);
887 }
835 kfree(ctrl); 888 kfree(ctrl);
836 } 889 }
837 kfree(hdl->buckets); 890 kfree(hdl->buckets);
@@ -1030,6 +1083,7 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
1030 } 1083 }
1031 1084
1032 INIT_LIST_HEAD(&ctrl->node); 1085 INIT_LIST_HEAD(&ctrl->node);
1086 INIT_LIST_HEAD(&ctrl->fhs);
1033 ctrl->handler = hdl; 1087 ctrl->handler = hdl;
1034 ctrl->ops = ops; 1088 ctrl->ops = ops;
1035 ctrl->id = id; 1089 ctrl->id = id;
@@ -1171,6 +1225,9 @@ int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
1171 /* Skip handler-private controls. */ 1225 /* Skip handler-private controls. */
1172 if (ctrl->is_private) 1226 if (ctrl->is_private)
1173 continue; 1227 continue;
1228 /* And control classes */
1229 if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
1230 continue;
1174 ret = handler_new_ref(hdl, ctrl); 1231 ret = handler_new_ref(hdl, ctrl);
1175 if (ret) 1232 if (ret)
1176 break; 1233 break;
@@ -1222,15 +1279,21 @@ EXPORT_SYMBOL(v4l2_ctrl_auto_cluster);
1222/* Activate/deactivate a control. */ 1279/* Activate/deactivate a control. */
1223void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active) 1280void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
1224{ 1281{
1282 /* invert since the actual flag is called 'inactive' */
1283 bool inactive = !active;
1284 bool old;
1285
1225 if (ctrl == NULL) 1286 if (ctrl == NULL)
1226 return; 1287 return;
1227 1288
1228 if (!active) 1289 if (inactive)
1229 /* set V4L2_CTRL_FLAG_INACTIVE */ 1290 /* set V4L2_CTRL_FLAG_INACTIVE */
1230 set_bit(4, &ctrl->flags); 1291 old = test_and_set_bit(4, &ctrl->flags);
1231 else 1292 else
1232 /* clear V4L2_CTRL_FLAG_INACTIVE */ 1293 /* clear V4L2_CTRL_FLAG_INACTIVE */
1233 clear_bit(4, &ctrl->flags); 1294 old = test_and_clear_bit(4, &ctrl->flags);
1295 if (old != inactive)
1296 send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
1234} 1297}
1235EXPORT_SYMBOL(v4l2_ctrl_activate); 1298EXPORT_SYMBOL(v4l2_ctrl_activate);
1236 1299
@@ -1242,15 +1305,21 @@ EXPORT_SYMBOL(v4l2_ctrl_activate);
1242 these controls. */ 1305 these controls. */
1243void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed) 1306void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
1244{ 1307{
1308 bool old;
1309
1245 if (ctrl == NULL) 1310 if (ctrl == NULL)
1246 return; 1311 return;
1247 1312
1313 v4l2_ctrl_lock(ctrl);
1248 if (grabbed) 1314 if (grabbed)
1249 /* set V4L2_CTRL_FLAG_GRABBED */ 1315 /* set V4L2_CTRL_FLAG_GRABBED */
1250 set_bit(1, &ctrl->flags); 1316 old = test_and_set_bit(1, &ctrl->flags);
1251 else 1317 else
1252 /* clear V4L2_CTRL_FLAG_GRABBED */ 1318 /* clear V4L2_CTRL_FLAG_GRABBED */
1253 clear_bit(1, &ctrl->flags); 1319 old = test_and_clear_bit(1, &ctrl->flags);
1320 if (old != grabbed)
1321 send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_FLAGS);
1322 v4l2_ctrl_unlock(ctrl);
1254} 1323}
1255EXPORT_SYMBOL(v4l2_ctrl_grab); 1324EXPORT_SYMBOL(v4l2_ctrl_grab);
1256 1325
@@ -1956,3 +2025,39 @@ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
1956 return set_ctrl(NULL, ctrl, &val); 2025 return set_ctrl(NULL, ctrl, &val);
1957} 2026}
1958EXPORT_SYMBOL(v4l2_ctrl_s_ctrl); 2027EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
2028
2029void v4l2_ctrl_add_fh(struct v4l2_ctrl_handler *hdl,
2030 struct v4l2_ctrl_fh *ctrl_fh,
2031 struct v4l2_event_subscription *sub)
2032{
2033 struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, sub->id);
2034
2035 v4l2_ctrl_lock(ctrl);
2036 list_add_tail(&ctrl_fh->node, &ctrl->fhs);
2037 if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
2038 (sub->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL)) {
2039 struct v4l2_event ev;
2040
2041 fill_event(&ev, ctrl, V4L2_EVENT_CTRL_CH_VALUE |
2042 V4L2_EVENT_CTRL_CH_FLAGS);
2043 v4l2_event_queue_fh(ctrl_fh->fh, &ev);
2044 }
2045 v4l2_ctrl_unlock(ctrl);
2046}
2047EXPORT_SYMBOL(v4l2_ctrl_add_fh);
2048
2049void v4l2_ctrl_del_fh(struct v4l2_ctrl *ctrl, struct v4l2_fh *fh)
2050{
2051 struct v4l2_ctrl_fh *pos;
2052
2053 v4l2_ctrl_lock(ctrl);
2054 list_for_each_entry(pos, &ctrl->fhs, node) {
2055 if (pos->fh == fh) {
2056 list_del(&pos->node);
2057 kfree(pos);
2058 break;
2059 }
2060 }
2061 v4l2_ctrl_unlock(ctrl);
2062}
2063EXPORT_SYMBOL(v4l2_ctrl_del_fh);