diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index 5f316667c142..d084cea2b3ba 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -1013,6 +1013,7 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl, insertion is an O(1) operation. */ if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) { list_add_tail(&new_ref->node, &hdl->ctrl_refs); + hdl->nr_of_refs++; goto insert_in_hash; } @@ -2061,3 +2062,22 @@ void v4l2_ctrl_del_fh(struct v4l2_ctrl *ctrl, struct v4l2_fh *fh) v4l2_ctrl_unlock(ctrl); } EXPORT_SYMBOL(v4l2_ctrl_del_fh); + +int v4l2_ctrl_subscribe_fh(struct v4l2_fh *fh, + struct v4l2_event_subscription *sub, unsigned n) +{ + struct v4l2_ctrl_handler *hdl = fh->ctrl_handler; + int ret = 0; + + if (!fh->events) + ret = v4l2_event_init(fh); + if (!ret) { + if (hdl->nr_of_refs * 2 > n) + n = hdl->nr_of_refs * 2; + ret = v4l2_event_alloc(fh, n); + } + if (!ret) + ret = v4l2_event_subscribe(fh, sub); + return ret; +} +EXPORT_SYMBOL(v4l2_ctrl_subscribe_fh); diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index c45bf40e080d..de68a59c7d84 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -169,6 +169,7 @@ struct v4l2_ctrl_ref { * control is needed multiple times, so this is a simple * optimization. * @buckets: Buckets for the hashing. Allows for quick control lookup. + * @nr_of_refs: Total number of control references in the list. * @nr_of_buckets: Total number of buckets in the array. * @error: The error code of the first failed control addition. */ @@ -178,6 +179,7 @@ struct v4l2_ctrl_handler { struct list_head ctrl_refs; struct v4l2_ctrl_ref *cached; struct v4l2_ctrl_ref **buckets; + u16 nr_of_refs; u16 nr_of_buckets; int error; }; @@ -494,11 +496,29 @@ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl); */ int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val); +/* Internal helper functions that deal with control events. */ void v4l2_ctrl_add_fh(struct v4l2_ctrl_handler *hdl, struct v4l2_ctrl_fh *ctrl_fh, struct v4l2_event_subscription *sub); void v4l2_ctrl_del_fh(struct v4l2_ctrl *ctrl, struct v4l2_fh *fh); +/** v4l2_ctrl_subscribe_fh() - Helper function that subscribes a control event. + * @fh: The file handler that subscribed the control event. + * @sub: The event to subscribe (type must be V4L2_EVENT_CTRL). + * @n: How many events should be allocated? (Passed to v4l2_event_alloc). + * Recommended to set to twice the number of controls plus whatever + * is needed for other events. This function will set n to + * max(n, 2 * fh->ctrl_handler->nr_of_refs). + * + * A helper function that initializes the fh for events, allocates the + * list of events and subscribes the control event. + * + * Typically called in the handler of VIDIOC_SUBSCRIBE_EVENT in the + * V4L2_EVENT_CTRL case. + */ +int v4l2_ctrl_subscribe_fh(struct v4l2_fh *fh, + struct v4l2_event_subscription *sub, unsigned n); + /* Helpers for ioctl_ops. If hdl == NULL then they will all return -EINVAL. */ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc); int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm);