Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b401200

Browse files
jwrdegoedeMauro Carvalho Chehab
authored andcommitted
[media] uvcvideo: Add support for control events
Signed-off-by: Hans de Goede <[email protected]> Signed-off-by: Laurent Pinchart <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent cb74d48 commit b401200

File tree

3 files changed

+170
-14
lines changed

3 files changed

+170
-14
lines changed

drivers/media/video/uvc/uvc_ctrl.c

Lines changed: 120 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/vmalloc.h>
2222
#include <linux/wait.h>
2323
#include <linux/atomic.h>
24+
#include <media/v4l2-ctrls.h>
2425

2526
#include "uvcvideo.h"
2627

@@ -1102,6 +1103,117 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
11021103
return ret;
11031104
}
11041105

1106+
/* --------------------------------------------------------------------------
1107+
* Ctrl event handling
1108+
*/
1109+
1110+
static 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+
1133+
static 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+
1152+
static 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+
1166+
static 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+
1197+
done:
1198+
mutex_unlock(&handle->chain->ctrl_mutex);
1199+
return ret;
1200+
}
1201+
1202+
static 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+
1211+
const 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+
};
11051217

11061218
/* --------------------------------------------------------------------------
11071219
* Control transactions
@@ -1179,8 +1291,11 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
11791291
return 0;
11801292
}
11811293

1182-
int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback)
1294+
int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
1295+
const struct v4l2_ext_control *xctrls,
1296+
unsigned int xctrls_count)
11831297
{
1298+
struct uvc_video_chain *chain = handle->chain;
11841299
struct uvc_entity *entity;
11851300
int ret = 0;
11861301

@@ -1191,6 +1306,8 @@ int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback)
11911306
goto done;
11921307
}
11931308

1309+
if (!rollback)
1310+
uvc_ctrl_send_events(handle, xctrls, xctrls_count);
11941311
done:
11951312
mutex_unlock(&chain->ctrl_mutex);
11961313
return ret;
@@ -1662,6 +1779,8 @@ static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
16621779
if (map == NULL)
16631780
return -ENOMEM;
16641781

1782+
INIT_LIST_HEAD(&map->ev_subs);
1783+
16651784
size = sizeof(*mapping->menu_info) * mapping->menu_count;
16661785
map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
16671786
if (map->menu_info == NULL) {

drivers/media/video/uvc/uvc_v4l2.c

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <linux/atomic.h>
2626

2727
#include <media/v4l2-common.h>
28+
#include <media/v4l2-ctrls.h>
29+
#include <media/v4l2-event.h>
2830
#include <media/v4l2-ioctl.h>
2931

3032
#include "uvcvideo.h"
@@ -505,6 +507,8 @@ static int uvc_v4l2_open(struct file *file)
505507
}
506508
}
507509

510+
v4l2_fh_init(&handle->vfh, stream->vdev);
511+
v4l2_fh_add(&handle->vfh);
508512
handle->chain = stream->chain;
509513
handle->stream = stream;
510514
handle->state = UVC_HANDLE_PASSIVE;
@@ -528,6 +532,8 @@ static int uvc_v4l2_release(struct file *file)
528532

529533
/* Release the file handle. */
530534
uvc_dismiss_privileges(handle);
535+
v4l2_fh_del(&handle->vfh);
536+
v4l2_fh_exit(&handle->vfh);
531537
kfree(handle);
532538
file->private_data = NULL;
533539

@@ -584,7 +590,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
584590
return ret;
585591

586592
ret = uvc_ctrl_get(chain, &xctrl);
587-
uvc_ctrl_rollback(chain);
593+
uvc_ctrl_rollback(handle);
588594
if (ret >= 0)
589595
ctrl->value = xctrl.value;
590596
break;
@@ -605,10 +611,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
605611

606612
ret = uvc_ctrl_set(chain, &xctrl);
607613
if (ret < 0) {
608-
uvc_ctrl_rollback(chain);
614+
uvc_ctrl_rollback(handle);
609615
return ret;
610616
}
611-
ret = uvc_ctrl_commit(chain);
617+
ret = uvc_ctrl_commit(handle, &xctrl, 1);
612618
if (ret == 0)
613619
ctrl->value = xctrl.value;
614620
break;
@@ -630,13 +636,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
630636
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
631637
ret = uvc_ctrl_get(chain, ctrl);
632638
if (ret < 0) {
633-
uvc_ctrl_rollback(chain);
639+
uvc_ctrl_rollback(handle);
634640
ctrls->error_idx = i;
635641
return ret;
636642
}
637643
}
638644
ctrls->error_idx = 0;
639-
ret = uvc_ctrl_rollback(chain);
645+
ret = uvc_ctrl_rollback(handle);
640646
break;
641647
}
642648

@@ -654,7 +660,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
654660
for (i = 0; i < ctrls->count; ++ctrl, ++i) {
655661
ret = uvc_ctrl_set(chain, ctrl);
656662
if (ret < 0) {
657-
uvc_ctrl_rollback(chain);
663+
uvc_ctrl_rollback(handle);
658664
ctrls->error_idx = i;
659665
return ret;
660666
}
@@ -663,9 +669,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
663669
ctrls->error_idx = 0;
664670

665671
if (cmd == VIDIOC_S_EXT_CTRLS)
666-
ret = uvc_ctrl_commit(chain);
672+
ret = uvc_ctrl_commit(handle,
673+
ctrls->controls, ctrls->count);
667674
else
668-
ret = uvc_ctrl_rollback(chain);
675+
ret = uvc_ctrl_rollback(handle);
669676
break;
670677
}
671678

@@ -990,6 +997,26 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
990997
return uvc_video_enable(stream, 0);
991998
}
992999

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+
9931020
/* Analog video standards make no sense for digital cameras. */
9941021
case VIDIOC_ENUMSTD:
9951022
case VIDIOC_QUERYSTD:

drivers/media/video/uvc/uvcvideo.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include <linux/videodev2.h>
1414
#include <media/media-device.h>
1515
#include <media/v4l2-device.h>
16+
#include <media/v4l2-event.h>
17+
#include <media/v4l2-fh.h>
1618
#include <media/videobuf2-core.h>
1719

1820
/* --------------------------------------------------------------------------
@@ -153,6 +155,7 @@ struct uvc_control_info {
153155

154156
struct uvc_control_mapping {
155157
struct list_head list;
158+
struct list_head ev_subs;
156159

157160
struct uvc_control_info *ctrl;
158161

@@ -524,6 +527,7 @@ enum uvc_handle_state {
524527
};
525528

526529
struct uvc_fh {
530+
struct v4l2_fh vfh;
527531
struct uvc_video_chain *chain;
528532
struct uvc_streaming *stream;
529533
enum uvc_handle_state state;
@@ -643,6 +647,8 @@ extern int uvc_status_suspend(struct uvc_device *dev);
643647
extern int uvc_status_resume(struct uvc_device *dev);
644648

645649
/* Controls */
650+
extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
651+
646652
extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
647653
struct v4l2_queryctrl *v4l2_ctrl);
648654
extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
@@ -655,14 +661,18 @@ extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
655661
extern int uvc_ctrl_resume_device(struct uvc_device *dev);
656662

657663
extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
658-
extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
659-
static inline int uvc_ctrl_commit(struct uvc_video_chain *chain)
664+
extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
665+
const struct v4l2_ext_control *xctrls,
666+
unsigned int xctrls_count);
667+
static inline int uvc_ctrl_commit(struct uvc_fh *handle,
668+
const struct v4l2_ext_control *xctrls,
669+
unsigned int xctrls_count)
660670
{
661-
return __uvc_ctrl_commit(chain, 0);
671+
return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count);
662672
}
663-
static inline int uvc_ctrl_rollback(struct uvc_video_chain *chain)
673+
static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
664674
{
665-
return __uvc_ctrl_commit(chain, 1);
675+
return __uvc_ctrl_commit(handle, 1, NULL, 0);
666676
}
667677

668678
extern int uvc_ctrl_get(struct uvc_video_chain *chain,

0 commit comments

Comments
 (0)