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.