blob: 11fbcf4095748fd44ca2c9ebc84a4e01935bd45d [file] [log] [blame]
Vinay Kalia3766b1e2012-01-11 18:58:41 -08001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/slab.h>
15#include <media/msm_vidc.h>
16#include "msm_vidc_internal.h"
17#include "msm_vdec.h"
18#include "msm_venc.h"
19#include "msm_vidc_common.h"
20#include "msm_smem.h"
21
22int msm_vidc_poll(void *instance, struct file *filp,
23 struct poll_table_struct *wait)
24{
25 int rc = 0;
26 struct msm_vidc_inst *inst = instance;
27 struct vb2_queue *outq = &inst->vb2_bufq[OUTPUT_PORT];
28 struct vb2_queue *capq = &inst->vb2_bufq[CAPTURE_PORT];
29 struct vb2_buffer *out_vb = NULL;
30 struct vb2_buffer *cap_vb = NULL;
31 unsigned long flags;
Steve Mucklef132c6c2012-06-06 18:30:57 -070032 poll_wait(filp, &inst->event_handler.wait, wait);
Praneeth Paladuguf2acb852012-05-07 17:44:53 -070033 if (v4l2_event_pending(&inst->event_handler))
34 return POLLPRI;
Vinay Kalia3766b1e2012-01-11 18:58:41 -080035 if (!outq->streaming && !capq->streaming) {
36 pr_err("Returning POLLERR from here: %d, %d\n",
37 outq->streaming, capq->streaming);
38 return POLLERR;
39 }
Steve Mucklef132c6c2012-06-06 18:30:57 -070040 poll_wait(filp, &inst->event_handler.wait, wait);
Praneeth Paladugu5b79a322012-04-18 15:16:29 -070041 if (v4l2_event_pending(&inst->event_handler))
42 return POLLPRI;
Vinay Kalia3766b1e2012-01-11 18:58:41 -080043 poll_wait(filp, &capq->done_wq, wait);
44 poll_wait(filp, &outq->done_wq, wait);
45 spin_lock_irqsave(&capq->done_lock, flags);
46 if (!list_empty(&capq->done_list))
47 cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
48 done_entry);
49 if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE
50 || cap_vb->state == VB2_BUF_STATE_ERROR))
51 rc |= POLLIN | POLLRDNORM;
52 spin_unlock_irqrestore(&capq->done_lock, flags);
53 spin_lock_irqsave(&outq->done_lock, flags);
54 if (!list_empty(&outq->done_list))
55 out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
56 done_entry);
57 if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE
58 || out_vb->state == VB2_BUF_STATE_ERROR))
59 rc |= POLLOUT | POLLWRNORM;
60 spin_unlock_irqrestore(&outq->done_lock, flags);
61 return rc;
62}
63
64int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
65{
66 struct msm_vidc_inst *inst = instance;
67 if (inst->session_type == MSM_VIDC_DECODER)
68 return msm_vdec_querycap(instance, cap);
69 else if (inst->session_type == MSM_VIDC_ENCODER)
70 return msm_venc_querycap(instance, cap);
71 return -EINVAL;
72}
73int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
74{
75 struct msm_vidc_inst *inst = instance;
76 if (inst->session_type == MSM_VIDC_DECODER)
77 return msm_vdec_enum_fmt(instance, f);
78 else if (inst->session_type == MSM_VIDC_ENCODER)
79 return msm_venc_enum_fmt(instance, f);
80 return -EINVAL;
81}
82int msm_vidc_s_fmt(void *instance, struct v4l2_format *f)
83{
84 struct msm_vidc_inst *inst = instance;
85 if (inst->session_type == MSM_VIDC_DECODER)
86 return msm_vdec_s_fmt(instance, f);
87 if (inst->session_type == MSM_VIDC_ENCODER)
88 return msm_venc_s_fmt(instance, f);
89 return -EINVAL;
90}
91int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
92{
93 struct msm_vidc_inst *inst = instance;
94 if (inst->session_type == MSM_VIDC_DECODER)
95 return msm_vdec_g_fmt(instance, f);
96 else if (inst->session_type == MSM_VIDC_ENCODER)
97 return msm_venc_g_fmt(instance, f);
98 return -EINVAL;
99}
100int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
101{
102 struct msm_vidc_inst *inst = instance;
103 if (inst->session_type == MSM_VIDC_DECODER)
104 return msm_vdec_s_ctrl(instance, control);
Ashray Kulkarnid2ab0e32012-04-03 18:40:29 -0700105 if (inst->session_type == MSM_VIDC_ENCODER)
106 return msm_venc_s_ctrl(instance, control);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800107 return -EINVAL;
108}
109int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
110{
111 struct msm_vidc_inst *inst = instance;
112 if (inst->session_type == MSM_VIDC_DECODER)
113 return msm_vdec_g_ctrl(instance, control);
Ashray Kulkarnid2ab0e32012-04-03 18:40:29 -0700114 if (inst->session_type == MSM_VIDC_ENCODER)
115 return msm_venc_g_ctrl(instance, control);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800116 return -EINVAL;
117}
118int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
119{
120 struct msm_vidc_inst *inst = instance;
121 if (inst->session_type == MSM_VIDC_DECODER)
122 return msm_vdec_reqbufs(instance, b);
123 if (inst->session_type == MSM_VIDC_ENCODER)
124 return msm_venc_reqbufs(instance, b);
125 return -EINVAL;
126}
127
128int msm_vidc_prepare_buf(void *instance, struct v4l2_buffer *b)
129{
130 struct msm_vidc_inst *inst = instance;
131 if (inst->session_type == MSM_VIDC_DECODER)
132 return msm_vdec_prepare_buf(instance, b);
133 if (inst->session_type == MSM_VIDC_ENCODER)
134 return msm_venc_prepare_buf(instance, b);
135 return -EINVAL;
136}
137
Praneeth Paladuguf2acb852012-05-07 17:44:53 -0700138int msm_vidc_release_buf(void *instance, struct v4l2_buffer *b)
139{
140 struct msm_vidc_inst *inst = instance;
141 if (inst->session_type == MSM_VIDC_DECODER)
142 return msm_vdec_release_buf(instance, b);
143 return -EINVAL;
144}
145
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800146int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b)
147{
148 struct msm_vidc_inst *inst = instance;
149 if (inst->session_type == MSM_VIDC_DECODER)
150 return msm_vdec_qbuf(instance, b);
151 if (inst->session_type == MSM_VIDC_ENCODER)
152 return msm_venc_qbuf(instance, b);
153 return -EINVAL;
154}
155
156int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
157{
158 struct msm_vidc_inst *inst = instance;
159 if (inst->session_type == MSM_VIDC_DECODER)
160 return msm_vdec_dqbuf(instance, b);
161 if (inst->session_type == MSM_VIDC_ENCODER)
162 return msm_venc_dqbuf(instance, b);
163 return -EINVAL;
164}
165
166int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
167{
168 struct msm_vidc_inst *inst = instance;
169 if (inst->session_type == MSM_VIDC_DECODER)
170 return msm_vdec_streamon(instance, i);
171 if (inst->session_type == MSM_VIDC_ENCODER)
172 return msm_venc_streamon(instance, i);
173 return -EINVAL;
174}
175
176int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i)
177{
178 struct msm_vidc_inst *inst = instance;
179 if (inst->session_type == MSM_VIDC_DECODER)
180 return msm_vdec_streamoff(instance, i);
181 if (inst->session_type == MSM_VIDC_ENCODER)
182 return msm_venc_streamoff(instance, i);
183 return -EINVAL;
184}
185
186void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr,
187 unsigned long size, int write)
188{
Vinay Kaliacf7e27f2012-06-14 19:05:15 -0700189 return (void *)0xdeadbeef;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800190}
191
192void vidc_put_userptr(void *buf_priv)
193{
194}
195
196static const struct vb2_mem_ops msm_vidc_vb2_mem_ops = {
197 .get_userptr = vidc_get_userptr,
198 .put_userptr = vidc_put_userptr,
199};
200
201static inline int vb2_bufq_init(struct msm_vidc_inst *inst,
202 enum v4l2_buf_type type, enum session_type sess)
203{
204 struct vb2_queue *q = NULL;
205 if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
206 q = &inst->vb2_bufq[CAPTURE_PORT];
207 } else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
208 q = &inst->vb2_bufq[OUTPUT_PORT];
209 } else {
210 pr_err("buf_type = %d not recognised\n", type);
211 return -EINVAL;
212 }
213 q->type = type;
214 q->io_modes = VB2_MMAP | VB2_USERPTR;
215 q->io_flags = 0;
216 if (sess == MSM_VIDC_DECODER)
217 q->ops = msm_vdec_get_vb2q_ops();
218 else if (sess == MSM_VIDC_ENCODER)
219 q->ops = msm_venc_get_vb2q_ops();
220 q->mem_ops = &msm_vidc_vb2_mem_ops;
221 q->drv_priv = inst;
222 return vb2_queue_init(q);
223}
224
Praneeth Paladugu5b79a322012-04-18 15:16:29 -0700225int msm_vidc_open(void *vidc_inst, int core_id, int session_type)
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800226{
Praneeth Paladugu5b79a322012-04-18 15:16:29 -0700227 struct msm_vidc_inst *inst = (struct msm_vidc_inst *)vidc_inst;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800228 struct msm_vidc_core *core = NULL;
229 unsigned long flags;
230 int rc = 0;
231 int i = 0;
232 if (core_id >= MSM_VIDC_CORES_MAX ||
233 session_type >= MSM_VIDC_MAX_DEVICES) {
234 pr_err("Invalid input, core_id = %d, session = %d\n",
235 core_id, session_type);
236 goto err_invalid_core;
237 }
238 core = get_vidc_core(core_id);
239 if (!core) {
240 pr_err("Failed to find core for core_id = %d\n", core_id);
241 goto err_invalid_core;
242 }
243
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800244 mutex_init(&inst->sync_lock);
245 spin_lock_init(&inst->lock);
246 inst->session_type = session_type;
247 INIT_LIST_HEAD(&inst->pendingq);
248 INIT_LIST_HEAD(&inst->internalbufs);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800249 inst->state = MSM_VIDC_CORE_UNINIT_DONE;
250 inst->core = core;
251 for (i = SESSION_MSG_INDEX(SESSION_MSG_START);
252 i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) {
253 init_completion(&inst->completions[i]);
254 }
255 inst->mem_client = msm_smem_new_client(SMEM_ION);
256 if (!inst->mem_client) {
257 pr_err("Failed to create memory client\n");
258 goto fail_mem_client;
259 }
260 if (session_type == MSM_VIDC_DECODER) {
261 msm_vdec_inst_init(inst);
262 msm_vdec_ctrl_init(inst);
263 } else if (session_type == MSM_VIDC_ENCODER) {
264 msm_venc_inst_init(inst);
Praneeth Paladugu5b79a322012-04-18 15:16:29 -0700265 msm_venc_ctrl_init(inst);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800266 }
267 rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
268 session_type);
269 if (rc) {
270 pr_err("Failed to initialize vb2 queue on capture port\n");
271 goto fail_init;
272 }
273 rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
274 session_type);
275 if (rc) {
276 pr_err("Failed to initialize vb2 queue on capture port\n");
277 goto fail_init;
278 }
279 rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT);
280 if (rc) {
281 pr_err("Failed to move video instance to init state\n");
282 goto fail_init;
283 }
284 spin_lock_irqsave(&core->lock, flags);
285 list_add_tail(&inst->list, &core->instances);
286 spin_unlock_irqrestore(&core->lock, flags);
Praneeth Paladugu5b79a322012-04-18 15:16:29 -0700287 return rc;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800288fail_init:
289 msm_smem_delete_client(inst->mem_client);
290fail_mem_client:
291 kfree(inst);
292 inst = NULL;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800293err_invalid_core:
Praneeth Paladugu5b79a322012-04-18 15:16:29 -0700294 return rc;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800295}
296
297static void cleanup_instance(struct msm_vidc_inst *inst)
298{
299 unsigned long flags;
300 struct list_head *ptr, *next;
301 struct vb2_buf_entry *entry;
302 struct internal_buf *buf;
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800303 if (inst) {
304 spin_lock_irqsave(&inst->lock, flags);
Ashray Kulkarnicb00cab2012-05-21 14:22:55 -0700305 if (!list_empty(&inst->pendingq)) {
306 list_for_each_safe(ptr, next, &inst->pendingq) {
307 entry = list_entry(ptr, struct vb2_buf_entry,
308 list);
309 list_del(&entry->list);
310 kfree(entry);
311 }
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800312 }
Ashray Kulkarnicb00cab2012-05-21 14:22:55 -0700313 if (!list_empty(&inst->internalbufs)) {
314 list_for_each_safe(ptr, next, &inst->internalbufs) {
315 buf = list_entry(ptr, struct internal_buf,
316 list);
317 list_del(&buf->list);
318 msm_smem_free(inst->mem_client, buf->handle);
319 kfree(buf);
320 }
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800321 }
322 spin_unlock_irqrestore(&inst->lock, flags);
323 msm_smem_delete_client(inst->mem_client);
324 }
325}
326
327int msm_vidc_close(void *instance)
328{
329 struct msm_vidc_inst *inst = instance;
330 struct msm_vidc_inst *temp;
331 struct msm_vidc_core *core;
332 struct list_head *ptr, *next;
333 int rc = 0;
334 core = inst->core;
335 mutex_lock(&core->sync_lock);
336 list_for_each_safe(ptr, next, &core->instances) {
337 temp = list_entry(ptr, struct msm_vidc_inst, list);
Praneeth Paladugu5b79a322012-04-18 15:16:29 -0700338 if (temp == inst)
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800339 list_del(&inst->list);
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800340 }
341 mutex_unlock(&core->sync_lock);
342 rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT);
343 if (rc)
Praneeth Paladugu5b79a322012-04-18 15:16:29 -0700344 pr_err("Failed to move video instance to uninit state\n");
Vinay Kalia3766b1e2012-01-11 18:58:41 -0800345 cleanup_instance(inst);
346 pr_debug("Closed the instance\n");
347 return 0;
348}