*/
        if (q->num_buffers) {
                bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||
+                                 q->cnt_prepare_streaming != q->cnt_unprepare_streaming ||
                                  q->cnt_wait_prepare != q->cnt_wait_finish;
 
                if (unbalanced || debug) {
                        pr_info("     setup: %u start_streaming: %u stop_streaming: %u\n",
                                q->cnt_queue_setup, q->cnt_start_streaming,
                                q->cnt_stop_streaming);
+                       pr_info("     prepare_streaming: %u unprepare_streaming: %u\n",
+                               q->cnt_prepare_streaming, q->cnt_unprepare_streaming);
                        pr_info("     wait_prepare: %u wait_finish: %u\n",
                                q->cnt_wait_prepare, q->cnt_wait_finish);
                }
                q->cnt_queue_setup = 0;
                q->cnt_wait_prepare = 0;
                q->cnt_wait_finish = 0;
+               q->cnt_prepare_streaming = 0;
                q->cnt_start_streaming = 0;
                q->cnt_stop_streaming = 0;
+               q->cnt_unprepare_streaming = 0;
        }
        for (buffer = 0; buffer < q->num_buffers; ++buffer) {
                struct vb2_buffer *vb = q->bufs[buffer];
        if (q->start_streaming_called)
                call_void_qop(q, stop_streaming, q);
 
+       if (q->streaming)
+               call_void_qop(q, unprepare_streaming, q);
+
        /*
         * If you see this warning, then the driver isn't cleaning up properly
         * in stop_streaming(). See the stop_streaming() documentation in
                return -EINVAL;
        }
 
+       ret = call_qop(q, prepare_streaming, q);
+       if (ret)
+               return ret;
+
+       q->streaming = 1;
+
        /*
         * Tell driver to start streaming provided sufficient buffers
         * are available.
        if (q->queued_count >= q->min_buffers_needed) {
                ret = v4l_vb2q_enable_media_source(q);
                if (ret)
-                       return ret;
+                       goto unprepare;
                ret = vb2_start_streaming(q);
                if (ret)
-                       return ret;
+                       goto unprepare;
        }
 
-       q->streaming = 1;
-
        dprintk(q, 3, "successful\n");
        return 0;
+
+unprepare:
+       call_void_qop(q, unprepare_streaming, q);
+       q->streaming = 0;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(vb2_core_streamon);
 
 
  *                     the buffer contents will be ignored anyway.
  * @buf_cleanup:       called once before the buffer is freed; drivers may
  *                     perform any additional cleanup; optional.
+ * @prepare_streaming: called once to prepare for 'streaming' state; this is
+ *                     where validation can be done to verify everything is
+ *                     okay and streaming resources can be claimed. It is
+ *                     called when the VIDIOC_STREAMON ioctl is called. The
+ *                     actual streaming starts when @start_streaming is called.
+ *                     Optional.
  * @start_streaming:   called once to enter 'streaming' state; the driver may
  *                     receive buffers with @buf_queue callback
  *                     before @start_streaming is called; the driver gets the
  *                     callback by calling vb2_buffer_done() with either
  *                     %VB2_BUF_STATE_DONE or %VB2_BUF_STATE_ERROR; may use
  *                     vb2_wait_for_all_buffers() function
+ * @unprepare_streaming:called as counterpart to @prepare_streaming; any claimed
+ *                     streaming resources can be released here. It is
+ *                     called when the VIDIOC_STREAMOFF ioctls is called or
+ *                     when the streaming filehandle is closed. Optional.
  * @buf_queue:         passes buffer vb to the driver; driver may start
  *                     hardware operation on this buffer; driver should give
  *                     the buffer back by calling vb2_buffer_done() function;
        void (*buf_finish)(struct vb2_buffer *vb);
        void (*buf_cleanup)(struct vb2_buffer *vb);
 
+       int (*prepare_streaming)(struct vb2_queue *q);
        int (*start_streaming)(struct vb2_queue *q, unsigned int count);
        void (*stop_streaming)(struct vb2_queue *q);
+       void (*unprepare_streaming)(struct vb2_queue *q);
 
        void (*buf_queue)(struct vb2_buffer *vb);
 
        u32                             cnt_queue_setup;
        u32                             cnt_wait_prepare;
        u32                             cnt_wait_finish;
+       u32                             cnt_prepare_streaming;
        u32                             cnt_start_streaming;
        u32                             cnt_stop_streaming;
+       u32                             cnt_unprepare_streaming;
 #endif
 };