static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes)
{
struct v4l2_event ev;
- struct v4l2_ctrl_fh *pos;
+ struct v4l2_subscribed_event *sev;
- if (list_empty(&ctrl->fhs))
+ if (list_empty(&ctrl->ev_subs))
return;
fill_event(&ev, ctrl, changes);
- list_for_each_entry(pos, &ctrl->fhs, node)
- if (pos->fh != fh)
- v4l2_event_queue_fh(pos->fh, &ev);
+ list_for_each_entry(sev, &ctrl->ev_subs, node)
+ if (sev->fh && sev->fh != fh)
+ v4l2_event_queue_fh(sev->fh, &ev);
}
/* Helper function: copy the current control value back to the caller */
{
struct v4l2_ctrl_ref *ref, *next_ref;
struct v4l2_ctrl *ctrl, *next_ctrl;
- struct v4l2_ctrl_fh *ctrl_fh, *next_ctrl_fh;
+ struct v4l2_subscribed_event *sev, *next_sev;
if (hdl == NULL || hdl->buckets == NULL)
return;
/* Free all controls owned by the handler */
list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
list_del(&ctrl->node);
- list_for_each_entry_safe(ctrl_fh, next_ctrl_fh, &ctrl->fhs, node) {
- list_del(&ctrl_fh->node);
- kfree(ctrl_fh);
- }
+ list_for_each_entry_safe(sev, next_sev, &ctrl->ev_subs, node)
+ list_del(&sev->node);
kfree(ctrl);
}
kfree(hdl->buckets);
}
INIT_LIST_HEAD(&ctrl->node);
- INIT_LIST_HEAD(&ctrl->fhs);
+ INIT_LIST_HEAD(&ctrl->ev_subs);
ctrl->handler = hdl;
ctrl->ops = ops;
ctrl->id = id;
}
EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
-void v4l2_ctrl_add_fh(struct v4l2_ctrl_handler *hdl,
- struct v4l2_ctrl_fh *ctrl_fh,
- struct v4l2_event_subscription *sub)
+void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
+ struct v4l2_subscribed_event *sev)
{
- struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, sub->id);
-
v4l2_ctrl_lock(ctrl);
- list_add_tail(&ctrl_fh->node, &ctrl->fhs);
+ list_add_tail(&sev->node, &ctrl->ev_subs);
if (ctrl->type != V4L2_CTRL_TYPE_CTRL_CLASS &&
- (sub->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL)) {
+ (sev->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_event_queue_fh(sev->fh, &ev);
}
v4l2_ctrl_unlock(ctrl);
}
-EXPORT_SYMBOL(v4l2_ctrl_add_fh);
+EXPORT_SYMBOL(v4l2_ctrl_add_event);
-void v4l2_ctrl_del_fh(struct v4l2_ctrl *ctrl, struct v4l2_fh *fh)
+void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
+ struct v4l2_subscribed_event *sev)
{
- 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;
- }
- }
+ list_del(&sev->node);
v4l2_ctrl_unlock(ctrl);
}
-EXPORT_SYMBOL(v4l2_ctrl_del_fh);
+EXPORT_SYMBOL(v4l2_ctrl_del_event);
int v4l2_ctrl_subscribe_fh(struct v4l2_fh *fh,
struct v4l2_event_subscription *sub, unsigned n)
{
struct v4l2_subscribed_event *sev, *found_ev;
struct v4l2_ctrl *ctrl = NULL;
- struct v4l2_ctrl_fh *ctrl_fh = NULL;
unsigned long flags;
if (sub->type == V4L2_EVENT_CTRL) {
return -EINVAL;
}
- sev = kmalloc(sizeof(*sev), GFP_KERNEL);
+ sev = kzalloc(sizeof(*sev), GFP_KERNEL);
if (!sev)
return -ENOMEM;
- if (ctrl) {
- ctrl_fh = kzalloc(sizeof(*ctrl_fh), GFP_KERNEL);
- if (!ctrl_fh) {
- kfree(sev);
- return -ENOMEM;
- }
- ctrl_fh->fh = fh;
- }
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
INIT_LIST_HEAD(&sev->list);
sev->type = sub->type;
sev->id = sub->id;
+ sev->fh = fh;
+ sev->flags = sub->flags;
list_add(&sev->list, &fh->subscribed);
- sev = NULL;
}
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
/* v4l2_ctrl_add_fh uses a mutex, so do this outside the spin lock */
- if (ctrl) {
- if (found_ev)
- kfree(ctrl_fh);
- else
- v4l2_ctrl_add_fh(fh->ctrl_handler, ctrl_fh, sub);
- }
-
- kfree(sev);
+ if (found_ev)
+ kfree(sev);
+ else if (ctrl)
+ v4l2_ctrl_add_event(ctrl, sev);
return 0;
}
spin_lock_irqsave(&fh->vdev->fh_lock, flags);
sev = v4l2_event_subscribed(fh, sub->type, sub->id);
- if (sev != NULL)
+ if (sev != NULL) {
list_del(&sev->list);
+ sev->fh = NULL;
+ }
spin_unlock_irqrestore(&fh->vdev->fh_lock, flags);
- if (sev->type == V4L2_EVENT_CTRL) {
+ if (sev && sev->type == V4L2_EVENT_CTRL) {
struct v4l2_ctrl *ctrl = v4l2_ctrl_find(fh->ctrl_handler, sev->id);
if (ctrl)
- v4l2_ctrl_del_fh(ctrl, fh);
+ v4l2_ctrl_del_event(ctrl, sev);
}
kfree(sev);
struct video_device;
struct v4l2_subdev;
struct v4l2_event_subscription;
+struct v4l2_subscribed_event;
struct v4l2_fh;
/** struct v4l2_ctrl_ops - The control operations that the driver has to provide.
/** struct v4l2_ctrl - The control structure.
* @node: The list node.
+ * @ev_subs: The list of control event subscriptions.
* @handler: The handler that owns the control.
* @cluster: Point to start of cluster array.
* @ncontrols: Number of controls in cluster array.
struct v4l2_ctrl {
/* Administrative fields */
struct list_head node;
- struct list_head fhs;
+ struct list_head ev_subs;
struct v4l2_ctrl_handler *handler;
struct v4l2_ctrl **cluster;
unsigned ncontrols;
int error;
};
-struct v4l2_ctrl_fh {
- struct list_head node;
- struct v4l2_fh *fh;
-};
-
/** struct v4l2_ctrl_config - Control configuration structure.
* @ops: The control ops.
* @id: The control ID.
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);
+void v4l2_ctrl_add_event(struct v4l2_ctrl *ctrl,
+ struct v4l2_subscribed_event *sev);
+void v4l2_ctrl_del_event(struct v4l2_ctrl *ctrl,
+ struct v4l2_subscribed_event *sev);
/** v4l2_ctrl_subscribe_fh() - Helper function that subscribes a control event.
* @fh: The file handler that subscribed the control event.