+
+void v4l2_ctrl_add_fh(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl_fh *ctrl_fh,
+ struct v4l2_event_subscription *sub)
+{
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, sub->id);
+
+ v4l2_ctrl_lock(ctrl);
+ list_add_tail(&ctrl_fh->node, &ctrl->fhs);
+ if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
+ (sub->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL)) {
+ struct v4l2_event ev;
+
+ fill_event(&ev, ctrl, V4L2_EVENT_CTRL_CH_VALUE |
+ V4L2_EVENT_CTRL_CH_FLAGS);
+ v4l2_event_queue_fh(ctrl_fh->fh, &ev);
+ }
+ v4l2_ctrl_unlock(ctrl);
+}
+EXPORT_SYMBOL(v4l2_ctrl_add_fh);
+
+void v4l2_ctrl_del_fh(struct v4l2_ctrl *ctrl, struct v4l2_fh *fh)
+{
+ struct v4l2_ctrl_fh *pos;
+
+ v4l2_ctrl_lock(ctrl);
+ list_for_each_entry(pos, &ctrl->fhs, node) {
+ if (pos->fh == fh) {
+ list_del(&pos->node);
+ kfree(pos);
+ break;
+ }
+ }
+ 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 (!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);