Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 1 | /* 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 | |
| 22 | int 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; |
Praneeth Paladugu | f2acb85 | 2012-05-07 17:44:53 -0700 | [diff] [blame^] | 32 | poll_wait(filp, &inst->event_handler.events->wait, wait); |
| 33 | if (v4l2_event_pending(&inst->event_handler)) |
| 34 | return POLLPRI; |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 35 | if (!outq->streaming && !capq->streaming) { |
| 36 | pr_err("Returning POLLERR from here: %d, %d\n", |
| 37 | outq->streaming, capq->streaming); |
| 38 | return POLLERR; |
| 39 | } |
Praneeth Paladugu | 5b79a32 | 2012-04-18 15:16:29 -0700 | [diff] [blame] | 40 | poll_wait(filp, &inst->event_handler.events->wait, wait); |
| 41 | if (v4l2_event_pending(&inst->event_handler)) |
| 42 | return POLLPRI; |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 43 | 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 | |
| 64 | int 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 | } |
| 73 | int 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 | } |
| 82 | int 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 | } |
| 91 | int 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 | } |
| 100 | int 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 Kulkarni | d2ab0e3 | 2012-04-03 18:40:29 -0700 | [diff] [blame] | 105 | if (inst->session_type == MSM_VIDC_ENCODER) |
| 106 | return msm_venc_s_ctrl(instance, control); |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 107 | return -EINVAL; |
| 108 | } |
| 109 | int 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 Kulkarni | d2ab0e3 | 2012-04-03 18:40:29 -0700 | [diff] [blame] | 114 | if (inst->session_type == MSM_VIDC_ENCODER) |
| 115 | return msm_venc_g_ctrl(instance, control); |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 116 | return -EINVAL; |
| 117 | } |
| 118 | int 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 | |
| 128 | int 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 Paladugu | f2acb85 | 2012-05-07 17:44:53 -0700 | [diff] [blame^] | 138 | int 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 Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 146 | int 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 | |
| 156 | int 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 | |
| 166 | int 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 | |
| 176 | int 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 | |
| 186 | void *vidc_get_userptr(void *alloc_ctx, unsigned long vaddr, |
| 187 | unsigned long size, int write) |
| 188 | { |
| 189 | return NULL; |
| 190 | } |
| 191 | |
| 192 | void vidc_put_userptr(void *buf_priv) |
| 193 | { |
| 194 | } |
| 195 | |
| 196 | static const struct vb2_mem_ops msm_vidc_vb2_mem_ops = { |
| 197 | .get_userptr = vidc_get_userptr, |
| 198 | .put_userptr = vidc_put_userptr, |
| 199 | }; |
| 200 | |
| 201 | static 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 Paladugu | 5b79a32 | 2012-04-18 15:16:29 -0700 | [diff] [blame] | 225 | int msm_vidc_open(void *vidc_inst, int core_id, int session_type) |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 226 | { |
Praneeth Paladugu | 5b79a32 | 2012-04-18 15:16:29 -0700 | [diff] [blame] | 227 | struct msm_vidc_inst *inst = (struct msm_vidc_inst *)vidc_inst; |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 228 | 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 Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 244 | 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); |
| 249 | INIT_LIST_HEAD(&inst->extradatabufs); |
| 250 | inst->state = MSM_VIDC_CORE_UNINIT_DONE; |
| 251 | inst->core = core; |
| 252 | for (i = SESSION_MSG_INDEX(SESSION_MSG_START); |
| 253 | i <= SESSION_MSG_INDEX(SESSION_MSG_END); i++) { |
| 254 | init_completion(&inst->completions[i]); |
| 255 | } |
| 256 | inst->mem_client = msm_smem_new_client(SMEM_ION); |
| 257 | if (!inst->mem_client) { |
| 258 | pr_err("Failed to create memory client\n"); |
| 259 | goto fail_mem_client; |
| 260 | } |
| 261 | if (session_type == MSM_VIDC_DECODER) { |
| 262 | msm_vdec_inst_init(inst); |
| 263 | msm_vdec_ctrl_init(inst); |
| 264 | } else if (session_type == MSM_VIDC_ENCODER) { |
| 265 | msm_venc_inst_init(inst); |
Praneeth Paladugu | 5b79a32 | 2012-04-18 15:16:29 -0700 | [diff] [blame] | 266 | msm_venc_ctrl_init(inst); |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 267 | } |
| 268 | rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, |
| 269 | session_type); |
| 270 | if (rc) { |
| 271 | pr_err("Failed to initialize vb2 queue on capture port\n"); |
| 272 | goto fail_init; |
| 273 | } |
| 274 | rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, |
| 275 | session_type); |
| 276 | if (rc) { |
| 277 | pr_err("Failed to initialize vb2 queue on capture port\n"); |
| 278 | goto fail_init; |
| 279 | } |
| 280 | rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT); |
| 281 | if (rc) { |
| 282 | pr_err("Failed to move video instance to init state\n"); |
| 283 | goto fail_init; |
| 284 | } |
| 285 | spin_lock_irqsave(&core->lock, flags); |
| 286 | list_add_tail(&inst->list, &core->instances); |
| 287 | spin_unlock_irqrestore(&core->lock, flags); |
Praneeth Paladugu | 5b79a32 | 2012-04-18 15:16:29 -0700 | [diff] [blame] | 288 | return rc; |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 289 | fail_init: |
| 290 | msm_smem_delete_client(inst->mem_client); |
| 291 | fail_mem_client: |
| 292 | kfree(inst); |
| 293 | inst = NULL; |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 294 | err_invalid_core: |
Praneeth Paladugu | 5b79a32 | 2012-04-18 15:16:29 -0700 | [diff] [blame] | 295 | return rc; |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 296 | } |
| 297 | |
| 298 | static void cleanup_instance(struct msm_vidc_inst *inst) |
| 299 | { |
| 300 | unsigned long flags; |
| 301 | struct list_head *ptr, *next; |
| 302 | struct vb2_buf_entry *entry; |
| 303 | struct internal_buf *buf; |
| 304 | struct extradata_buf *ebuf; |
| 305 | if (inst) { |
| 306 | spin_lock_irqsave(&inst->lock, flags); |
| 307 | list_for_each_safe(ptr, next, &inst->pendingq) { |
| 308 | entry = list_entry(ptr, struct vb2_buf_entry, list); |
| 309 | list_del(&entry->list); |
| 310 | kfree(entry); |
| 311 | } |
| 312 | list_for_each_safe(ptr, next, &inst->internalbufs) { |
| 313 | buf = list_entry(ptr, struct internal_buf, list); |
| 314 | list_del(&buf->list); |
| 315 | msm_smem_free(inst->mem_client, buf->handle); |
| 316 | kfree(buf); |
| 317 | } |
| 318 | list_for_each_safe(ptr, next, &inst->extradatabufs) { |
| 319 | ebuf = list_entry(ptr, struct extradata_buf, list); |
| 320 | list_del(&ebuf->list); |
| 321 | msm_smem_free(inst->mem_client, ebuf->handle); |
| 322 | kfree(ebuf); |
| 323 | } |
| 324 | spin_unlock_irqrestore(&inst->lock, flags); |
| 325 | msm_smem_delete_client(inst->mem_client); |
| 326 | } |
| 327 | } |
| 328 | |
| 329 | int msm_vidc_close(void *instance) |
| 330 | { |
| 331 | struct msm_vidc_inst *inst = instance; |
| 332 | struct msm_vidc_inst *temp; |
| 333 | struct msm_vidc_core *core; |
| 334 | struct list_head *ptr, *next; |
| 335 | int rc = 0; |
| 336 | core = inst->core; |
| 337 | mutex_lock(&core->sync_lock); |
| 338 | list_for_each_safe(ptr, next, &core->instances) { |
| 339 | temp = list_entry(ptr, struct msm_vidc_inst, list); |
Praneeth Paladugu | 5b79a32 | 2012-04-18 15:16:29 -0700 | [diff] [blame] | 340 | if (temp == inst) |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 341 | list_del(&inst->list); |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 342 | } |
| 343 | mutex_unlock(&core->sync_lock); |
| 344 | rc = msm_comm_try_state(inst, MSM_VIDC_CORE_UNINIT); |
| 345 | if (rc) |
Praneeth Paladugu | 5b79a32 | 2012-04-18 15:16:29 -0700 | [diff] [blame] | 346 | pr_err("Failed to move video instance to uninit state\n"); |
Vinay Kalia | 3766b1e | 2012-01-11 18:58:41 -0800 | [diff] [blame] | 347 | cleanup_instance(inst); |
| 348 | pr_debug("Closed the instance\n"); |
| 349 | return 0; |
| 350 | } |