diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2014-04-14 06:33:00 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2014-04-16 17:57:25 -0400 |
commit | 3415a89f48dce655ae353bc70a8e292764e8e931 (patch) | |
tree | 5e14b498a4f12817dce2ca2666aa05477ad0f755 /drivers/media/v4l2-core/videobuf2-core.c | |
parent | 5f26f2501b81190b60a0b72d611668fb6a59dd24 (diff) |
[media] vb2: add thread support
In order to implement vb2 DVB support you need to be able to start
a kernel thread that queues and dequeues buffers, calling a callback
function for every buffer. This patch adds support for that.
It's based on drivers/media/v4l2-core/videobuf-dvb.c, but with all the DVB
specific stuff stripped out, thus making it much more generic.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/media/v4l2-core/videobuf2-core.c')
-rw-r--r-- | drivers/media/v4l2-core/videobuf2-core.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 2075bac748c0..3f0cdb150dfd 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c | |||
@@ -6,6 +6,9 @@ | |||
6 | * Author: Pawel Osciak <pawel@osciak.com> | 6 | * Author: Pawel Osciak <pawel@osciak.com> |
7 | * Marek Szyprowski <m.szyprowski@samsung.com> | 7 | * Marek Szyprowski <m.szyprowski@samsung.com> |
8 | * | 8 | * |
9 | * The vb2_thread implementation was based on code from videobuf-dvb.c: | ||
10 | * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs] | ||
11 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 13 | * it under the terms of the GNU General Public License as published by |
11 | * the Free Software Foundation. | 14 | * the Free Software Foundation. |
@@ -18,6 +21,8 @@ | |||
18 | #include <linux/poll.h> | 21 | #include <linux/poll.h> |
19 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
20 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
24 | #include <linux/freezer.h> | ||
25 | #include <linux/kthread.h> | ||
21 | 26 | ||
22 | #include <media/v4l2-dev.h> | 27 | #include <media/v4l2-dev.h> |
23 | #include <media/v4l2-fh.h> | 28 | #include <media/v4l2-fh.h> |
@@ -3005,6 +3010,147 @@ size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count, | |||
3005 | } | 3010 | } |
3006 | EXPORT_SYMBOL_GPL(vb2_write); | 3011 | EXPORT_SYMBOL_GPL(vb2_write); |
3007 | 3012 | ||
3013 | struct vb2_threadio_data { | ||
3014 | struct task_struct *thread; | ||
3015 | vb2_thread_fnc fnc; | ||
3016 | void *priv; | ||
3017 | bool stop; | ||
3018 | }; | ||
3019 | |||
3020 | static int vb2_thread(void *data) | ||
3021 | { | ||
3022 | struct vb2_queue *q = data; | ||
3023 | struct vb2_threadio_data *threadio = q->threadio; | ||
3024 | struct vb2_fileio_data *fileio = q->fileio; | ||
3025 | bool set_timestamp = false; | ||
3026 | int prequeue = 0; | ||
3027 | int index = 0; | ||
3028 | int ret = 0; | ||
3029 | |||
3030 | if (V4L2_TYPE_IS_OUTPUT(q->type)) { | ||
3031 | prequeue = q->num_buffers; | ||
3032 | set_timestamp = | ||
3033 | (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) == | ||
3034 | V4L2_BUF_FLAG_TIMESTAMP_COPY; | ||
3035 | } | ||
3036 | |||
3037 | set_freezable(); | ||
3038 | |||
3039 | for (;;) { | ||
3040 | struct vb2_buffer *vb; | ||
3041 | |||
3042 | /* | ||
3043 | * Call vb2_dqbuf to get buffer back. | ||
3044 | */ | ||
3045 | memset(&fileio->b, 0, sizeof(fileio->b)); | ||
3046 | fileio->b.type = q->type; | ||
3047 | fileio->b.memory = q->memory; | ||
3048 | if (prequeue) { | ||
3049 | fileio->b.index = index++; | ||
3050 | prequeue--; | ||
3051 | } else { | ||
3052 | call_void_qop(q, wait_finish, q); | ||
3053 | ret = vb2_internal_dqbuf(q, &fileio->b, 0); | ||
3054 | call_void_qop(q, wait_prepare, q); | ||
3055 | dprintk(5, "file io: vb2_dqbuf result: %d\n", ret); | ||
3056 | } | ||
3057 | if (threadio->stop) | ||
3058 | break; | ||
3059 | if (ret) | ||
3060 | break; | ||
3061 | try_to_freeze(); | ||
3062 | |||
3063 | vb = q->bufs[fileio->b.index]; | ||
3064 | if (!(fileio->b.flags & V4L2_BUF_FLAG_ERROR)) | ||
3065 | ret = threadio->fnc(vb, threadio->priv); | ||
3066 | if (ret) | ||
3067 | break; | ||
3068 | call_void_qop(q, wait_finish, q); | ||
3069 | if (set_timestamp) | ||
3070 | v4l2_get_timestamp(&fileio->b.timestamp); | ||
3071 | ret = vb2_internal_qbuf(q, &fileio->b); | ||
3072 | call_void_qop(q, wait_prepare, q); | ||
3073 | if (ret) | ||
3074 | break; | ||
3075 | } | ||
3076 | |||
3077 | /* Hmm, linux becomes *very* unhappy without this ... */ | ||
3078 | while (!kthread_should_stop()) { | ||
3079 | set_current_state(TASK_INTERRUPTIBLE); | ||
3080 | schedule(); | ||
3081 | } | ||
3082 | return 0; | ||
3083 | } | ||
3084 | |||
3085 | /* | ||
3086 | * This function should not be used for anything else but the videobuf2-dvb | ||
3087 | * support. If you think you have another good use-case for this, then please | ||
3088 | * contact the linux-media mailinglist first. | ||
3089 | */ | ||
3090 | int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv, | ||
3091 | const char *thread_name) | ||
3092 | { | ||
3093 | struct vb2_threadio_data *threadio; | ||
3094 | int ret = 0; | ||
3095 | |||
3096 | if (q->threadio) | ||
3097 | return -EBUSY; | ||
3098 | if (vb2_is_busy(q)) | ||
3099 | return -EBUSY; | ||
3100 | if (WARN_ON(q->fileio)) | ||
3101 | return -EBUSY; | ||
3102 | |||
3103 | threadio = kzalloc(sizeof(*threadio), GFP_KERNEL); | ||
3104 | if (threadio == NULL) | ||
3105 | return -ENOMEM; | ||
3106 | threadio->fnc = fnc; | ||
3107 | threadio->priv = priv; | ||
3108 | |||
3109 | ret = __vb2_init_fileio(q, !V4L2_TYPE_IS_OUTPUT(q->type)); | ||
3110 | dprintk(3, "file io: vb2_init_fileio result: %d\n", ret); | ||
3111 | if (ret) | ||
3112 | goto nomem; | ||
3113 | q->threadio = threadio; | ||
3114 | threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name); | ||
3115 | if (IS_ERR(threadio->thread)) { | ||
3116 | ret = PTR_ERR(threadio->thread); | ||
3117 | threadio->thread = NULL; | ||
3118 | goto nothread; | ||
3119 | } | ||
3120 | return 0; | ||
3121 | |||
3122 | nothread: | ||
3123 | __vb2_cleanup_fileio(q); | ||
3124 | nomem: | ||
3125 | kfree(threadio); | ||
3126 | return ret; | ||
3127 | } | ||
3128 | EXPORT_SYMBOL_GPL(vb2_thread_start); | ||
3129 | |||
3130 | int vb2_thread_stop(struct vb2_queue *q) | ||
3131 | { | ||
3132 | struct vb2_threadio_data *threadio = q->threadio; | ||
3133 | struct vb2_fileio_data *fileio = q->fileio; | ||
3134 | int err; | ||
3135 | |||
3136 | if (threadio == NULL) | ||
3137 | return 0; | ||
3138 | call_void_qop(q, wait_finish, q); | ||
3139 | threadio->stop = true; | ||
3140 | vb2_internal_streamoff(q, q->type); | ||
3141 | call_void_qop(q, wait_prepare, q); | ||
3142 | q->fileio = NULL; | ||
3143 | fileio->req.count = 0; | ||
3144 | vb2_reqbufs(q, &fileio->req); | ||
3145 | kfree(fileio); | ||
3146 | err = kthread_stop(threadio->thread); | ||
3147 | threadio->thread = NULL; | ||
3148 | kfree(threadio); | ||
3149 | q->fileio = NULL; | ||
3150 | q->threadio = NULL; | ||
3151 | return err; | ||
3152 | } | ||
3153 | EXPORT_SYMBOL_GPL(vb2_thread_stop); | ||
3008 | 3154 | ||
3009 | /* | 3155 | /* |
3010 | * The following functions are not part of the vb2 core API, but are helper | 3156 | * The following functions are not part of the vb2 core API, but are helper |