]>
Commit | Line | Data |
---|---|---|
622897da MH |
1 | /* |
2 | * Copyright (C) 2012 Texas Instruments Inc | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License as | |
6 | * published by the Free Software Foundation version 2. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | * You should have received a copy of the GNU General Public License | |
14 | * along with this program; if not, write to the Free Software | |
15 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
16 | * | |
17 | * Contributors: | |
18 | * Manjunath Hadli <manjunath.hadli@ti.com> | |
19 | * Prabhakar Lad <prabhakar.lad@ti.com> | |
20 | */ | |
21 | ||
22 | #include <linux/module.h> | |
23 | #include <linux/slab.h> | |
24 | ||
25 | #include <media/v4l2-ioctl.h> | |
26 | ||
27 | #include "vpfe.h" | |
28 | #include "vpfe_mc_capture.h" | |
29 | ||
622897da MH |
30 | static int debug; |
31 | ||
32 | /* get v4l2 subdev pointer to external subdev which is active */ | |
33 | static struct media_entity *vpfe_get_input_entity | |
34 | (struct vpfe_video_device *video) | |
35 | { | |
36 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
37 | struct media_pad *remote; | |
38 | ||
1bddf1b3 | 39 | remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]); |
622897da MH |
40 | if (remote == NULL) { |
41 | pr_err("Invalid media connection to isif/ccdc\n"); | |
42 | return NULL; | |
43 | } | |
44 | return remote->entity; | |
45 | } | |
46 | ||
47 | /* updates external subdev(sensor/decoder) which is active */ | |
48 | static int vpfe_update_current_ext_subdev(struct vpfe_video_device *video) | |
49 | { | |
50 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
51 | struct vpfe_config *vpfe_cfg; | |
52 | struct v4l2_subdev *subdev; | |
53 | struct media_pad *remote; | |
54 | int i; | |
55 | ||
1bddf1b3 | 56 | remote = media_entity_remote_pad(&vpfe_dev->vpfe_isif.pads[0]); |
622897da MH |
57 | if (remote == NULL) { |
58 | pr_err("Invalid media connection to isif/ccdc\n"); | |
59 | return -EINVAL; | |
60 | } | |
61 | ||
62 | subdev = media_entity_to_v4l2_subdev(remote->entity); | |
63 | vpfe_cfg = vpfe_dev->pdev->platform_data; | |
64 | for (i = 0; i < vpfe_cfg->num_subdevs; i++) { | |
65 | if (!strcmp(vpfe_cfg->sub_devs[i].module_name, subdev->name)) { | |
66 | video->current_ext_subdev = &vpfe_cfg->sub_devs[i]; | |
67 | break; | |
68 | } | |
69 | } | |
70 | ||
71 | /* if user not linked decoder/sensor to isif/ccdc */ | |
72 | if (i == vpfe_cfg->num_subdevs) { | |
73 | pr_err("Invalid media chain connection to isif/ccdc\n"); | |
74 | return -EINVAL; | |
75 | } | |
76 | /* find the v4l2 subdev pointer */ | |
77 | for (i = 0; i < vpfe_dev->num_ext_subdevs; i++) { | |
78 | if (!strcmp(video->current_ext_subdev->module_name, | |
79 | vpfe_dev->sd[i]->name)) | |
80 | video->current_ext_subdev->subdev = vpfe_dev->sd[i]; | |
81 | } | |
82 | return 0; | |
83 | } | |
84 | ||
85 | /* get the subdev which is connected to the output video node */ | |
86 | static struct v4l2_subdev * | |
87 | vpfe_video_remote_subdev(struct vpfe_video_device *video, u32 *pad) | |
88 | { | |
1bddf1b3 | 89 | struct media_pad *remote = media_entity_remote_pad(&video->pad); |
622897da MH |
90 | |
91 | if (remote == NULL || remote->entity->type != MEDIA_ENT_T_V4L2_SUBDEV) | |
92 | return NULL; | |
93 | if (pad) | |
94 | *pad = remote->index; | |
95 | return media_entity_to_v4l2_subdev(remote->entity); | |
96 | } | |
97 | ||
98 | /* get the format set at output pad of the adjacent subdev */ | |
99 | static int | |
100 | __vpfe_video_get_format(struct vpfe_video_device *video, | |
101 | struct v4l2_format *format) | |
102 | { | |
103 | struct v4l2_subdev_format fmt; | |
104 | struct v4l2_subdev *subdev; | |
105 | struct media_pad *remote; | |
106 | u32 pad; | |
107 | int ret; | |
108 | ||
109 | subdev = vpfe_video_remote_subdev(video, &pad); | |
110 | if (subdev == NULL) | |
111 | return -EINVAL; | |
112 | ||
113 | fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; | |
1bddf1b3 | 114 | remote = media_entity_remote_pad(&video->pad); |
622897da MH |
115 | fmt.pad = remote->index; |
116 | ||
117 | ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt); | |
118 | if (ret == -ENOIOCTLCMD) | |
119 | return -EINVAL; | |
120 | ||
121 | format->type = video->type; | |
122 | /* convert mbus_format to v4l2_format */ | |
123 | v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); | |
124 | mbus_to_pix(&fmt.format, &format->fmt.pix); | |
125 | ||
126 | return 0; | |
127 | } | |
128 | ||
129 | /* make a note of pipeline details */ | |
130 | static void vpfe_prepare_pipeline(struct vpfe_video_device *video) | |
131 | { | |
132 | struct media_entity *entity = &video->video_dev.entity; | |
133 | struct media_device *mdev = entity->parent; | |
134 | struct vpfe_pipeline *pipe = &video->pipe; | |
135 | struct vpfe_video_device *far_end = NULL; | |
136 | struct media_entity_graph graph; | |
137 | ||
138 | pipe->input_num = 0; | |
139 | pipe->output_num = 0; | |
140 | ||
141 | if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
142 | pipe->inputs[pipe->input_num++] = video; | |
143 | else | |
144 | pipe->outputs[pipe->output_num++] = video; | |
145 | ||
146 | mutex_lock(&mdev->graph_mutex); | |
147 | media_entity_graph_walk_start(&graph, entity); | |
148 | while ((entity = media_entity_graph_walk_next(&graph))) { | |
149 | if (entity == &video->video_dev.entity) | |
150 | continue; | |
151 | if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE) | |
152 | continue; | |
153 | far_end = to_vpfe_video(media_entity_to_video_device(entity)); | |
154 | if (far_end->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
155 | pipe->inputs[pipe->input_num++] = far_end; | |
156 | else | |
157 | pipe->outputs[pipe->output_num++] = far_end; | |
158 | } | |
159 | mutex_unlock(&mdev->graph_mutex); | |
160 | } | |
161 | ||
162 | /* update pipe state selected by user */ | |
163 | static int vpfe_update_pipe_state(struct vpfe_video_device *video) | |
164 | { | |
165 | struct vpfe_pipeline *pipe = &video->pipe; | |
166 | int ret; | |
167 | ||
168 | vpfe_prepare_pipeline(video); | |
169 | ||
170 | /* Find out if there is any input video | |
171 | if yes, it is single shot. | |
172 | */ | |
173 | if (pipe->input_num == 0) { | |
174 | pipe->state = VPFE_PIPELINE_STREAM_CONTINUOUS; | |
175 | ret = vpfe_update_current_ext_subdev(video); | |
176 | if (ret) { | |
177 | pr_err("Invalid external subdev\n"); | |
178 | return ret; | |
179 | } | |
180 | } else { | |
181 | pipe->state = VPFE_PIPELINE_STREAM_SINGLESHOT; | |
182 | } | |
183 | video->initialized = 1; | |
184 | video->skip_frame_count = 1; | |
185 | video->skip_frame_count_init = 1; | |
186 | return 0; | |
187 | } | |
188 | ||
189 | /* checks wether pipeline is ready for enabling */ | |
190 | int vpfe_video_is_pipe_ready(struct vpfe_pipeline *pipe) | |
191 | { | |
192 | int i; | |
193 | ||
194 | for (i = 0; i < pipe->input_num; i++) | |
195 | if (!pipe->inputs[i]->started || | |
196 | pipe->inputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED) | |
197 | return 0; | |
198 | for (i = 0; i < pipe->output_num; i++) | |
199 | if (!pipe->outputs[i]->started || | |
200 | pipe->outputs[i]->state != VPFE_VIDEO_BUFFER_QUEUED) | |
201 | return 0; | |
202 | return 1; | |
203 | } | |
204 | ||
205 | /** | |
206 | * Validate a pipeline by checking both ends of all links for format | |
207 | * discrepancies. | |
208 | * | |
209 | * Return 0 if all formats match, or -EPIPE if at least one link is found with | |
210 | * different formats on its two ends. | |
211 | */ | |
212 | static int vpfe_video_validate_pipeline(struct vpfe_pipeline *pipe) | |
213 | { | |
214 | struct v4l2_subdev_format fmt_source; | |
215 | struct v4l2_subdev_format fmt_sink; | |
216 | struct v4l2_subdev *subdev; | |
217 | struct media_pad *pad; | |
218 | int ret; | |
219 | ||
220 | /* | |
221 | * Should not matter if it is output[0] or 1 as | |
222 | * the general ideas is to traverse backwards and | |
223 | * the fact that the out video node always has the | |
224 | * format of the connected pad. | |
225 | */ | |
226 | subdev = vpfe_video_remote_subdev(pipe->outputs[0], NULL); | |
227 | if (subdev == NULL) | |
228 | return -EPIPE; | |
229 | ||
230 | while (1) { | |
231 | /* Retrieve the sink format */ | |
232 | pad = &subdev->entity.pads[0]; | |
233 | if (!(pad->flags & MEDIA_PAD_FL_SINK)) | |
234 | break; | |
235 | ||
236 | fmt_sink.which = V4L2_SUBDEV_FORMAT_ACTIVE; | |
237 | fmt_sink.pad = pad->index; | |
238 | ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, | |
239 | &fmt_sink); | |
240 | ||
241 | if (ret < 0 && ret != -ENOIOCTLCMD) | |
242 | return -EPIPE; | |
243 | ||
244 | /* Retrieve the source format */ | |
1bddf1b3 | 245 | pad = media_entity_remote_pad(pad); |
622897da MH |
246 | if (pad == NULL || |
247 | pad->entity->type != MEDIA_ENT_T_V4L2_SUBDEV) | |
248 | break; | |
249 | ||
250 | subdev = media_entity_to_v4l2_subdev(pad->entity); | |
251 | ||
252 | fmt_source.which = V4L2_SUBDEV_FORMAT_ACTIVE; | |
253 | fmt_source.pad = pad->index; | |
254 | ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt_source); | |
255 | if (ret < 0 && ret != -ENOIOCTLCMD) | |
256 | return -EPIPE; | |
257 | ||
258 | /* Check if the two ends match */ | |
259 | if (fmt_source.format.code != fmt_sink.format.code || | |
260 | fmt_source.format.width != fmt_sink.format.width || | |
261 | fmt_source.format.height != fmt_sink.format.height) | |
262 | return -EPIPE; | |
263 | } | |
264 | return 0; | |
265 | } | |
266 | ||
267 | /* | |
268 | * vpfe_pipeline_enable() - Enable streaming on a pipeline | |
269 | * @vpfe_dev: vpfe device | |
270 | * @pipe: vpfe pipeline | |
271 | * | |
272 | * Walk the entities chain starting at the pipeline output video node and start | |
273 | * all modules in the chain in the given mode. | |
274 | * | |
275 | * Return 0 if successful, or the return value of the failed video::s_stream | |
276 | * operation otherwise. | |
277 | */ | |
278 | static int vpfe_pipeline_enable(struct vpfe_pipeline *pipe) | |
279 | { | |
280 | struct media_entity_graph graph; | |
281 | struct media_entity *entity; | |
282 | struct v4l2_subdev *subdev; | |
283 | struct media_device *mdev; | |
284 | int ret = 0; | |
285 | ||
286 | if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) | |
287 | entity = vpfe_get_input_entity(pipe->outputs[0]); | |
288 | else | |
289 | entity = &pipe->inputs[0]->video_dev.entity; | |
290 | ||
291 | mdev = entity->parent; | |
292 | mutex_lock(&mdev->graph_mutex); | |
293 | media_entity_graph_walk_start(&graph, entity); | |
294 | while ((entity = media_entity_graph_walk_next(&graph))) { | |
295 | ||
296 | if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE) | |
297 | continue; | |
298 | subdev = media_entity_to_v4l2_subdev(entity); | |
299 | ret = v4l2_subdev_call(subdev, video, s_stream, 1); | |
300 | if (ret < 0 && ret != -ENOIOCTLCMD) | |
301 | break; | |
302 | } | |
303 | mutex_unlock(&mdev->graph_mutex); | |
304 | return ret; | |
305 | } | |
306 | ||
307 | /* | |
308 | * vpfe_pipeline_disable() - Disable streaming on a pipeline | |
309 | * @vpfe_dev: vpfe device | |
310 | * @pipe: VPFE pipeline | |
311 | * | |
312 | * Walk the entities chain starting at the pipeline output video node and stop | |
313 | * all modules in the chain. | |
314 | * | |
315 | * Return 0 if all modules have been properly stopped, or -ETIMEDOUT if a module | |
316 | * can't be stopped. | |
317 | */ | |
318 | static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe) | |
319 | { | |
320 | struct media_entity_graph graph; | |
321 | struct media_entity *entity; | |
322 | struct v4l2_subdev *subdev; | |
323 | struct media_device *mdev; | |
324 | int ret = 0; | |
325 | ||
326 | if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) | |
327 | entity = vpfe_get_input_entity(pipe->outputs[0]); | |
328 | else | |
329 | entity = &pipe->inputs[0]->video_dev.entity; | |
330 | ||
331 | mdev = entity->parent; | |
332 | mutex_lock(&mdev->graph_mutex); | |
333 | media_entity_graph_walk_start(&graph, entity); | |
334 | ||
335 | while ((entity = media_entity_graph_walk_next(&graph))) { | |
336 | ||
337 | if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE) | |
338 | continue; | |
339 | subdev = media_entity_to_v4l2_subdev(entity); | |
340 | ret = v4l2_subdev_call(subdev, video, s_stream, 0); | |
341 | if (ret < 0 && ret != -ENOIOCTLCMD) | |
342 | break; | |
343 | } | |
344 | mutex_unlock(&mdev->graph_mutex); | |
345 | ||
3e6e3b3d | 346 | return ret ? -ETIMEDOUT : 0; |
622897da MH |
347 | } |
348 | ||
349 | /* | |
350 | * vpfe_pipeline_set_stream() - Enable/disable streaming on a pipeline | |
351 | * @vpfe_dev: VPFE device | |
352 | * @pipe: VPFE pipeline | |
353 | * @state: Stream state (stopped or active) | |
354 | * | |
355 | * Set the pipeline to the given stream state. | |
356 | * | |
2f9e96c3 | 357 | * Return 0 if successful, or the return value of the failed video::s_stream |
622897da MH |
358 | * operation otherwise. |
359 | */ | |
360 | static int vpfe_pipeline_set_stream(struct vpfe_pipeline *pipe, | |
361 | enum vpfe_pipeline_stream_state state) | |
362 | { | |
363 | if (state == VPFE_PIPELINE_STREAM_STOPPED) | |
364 | return vpfe_pipeline_disable(pipe); | |
365 | ||
366 | return vpfe_pipeline_enable(pipe); | |
367 | } | |
368 | ||
369 | static int all_videos_stopped(struct vpfe_video_device *video) | |
370 | { | |
371 | struct vpfe_pipeline *pipe = &video->pipe; | |
372 | int i; | |
373 | ||
374 | for (i = 0; i < pipe->input_num; i++) | |
375 | if (pipe->inputs[i]->started) | |
376 | return 0; | |
377 | for (i = 0; i < pipe->output_num; i++) | |
378 | if (pipe->outputs[i]->started) | |
379 | return 0; | |
380 | return 1; | |
381 | } | |
382 | ||
383 | /* | |
384 | * vpfe_open() - open video device | |
385 | * @file: file pointer | |
386 | * | |
387 | * initialize media pipeline state, allocate memory for file handle | |
388 | * | |
389 | * Return 0 if successful, or the return -ENODEV otherwise. | |
390 | */ | |
391 | static int vpfe_open(struct file *file) | |
392 | { | |
393 | struct vpfe_video_device *video = video_drvdata(file); | |
394 | struct vpfe_fh *handle; | |
395 | ||
396 | /* Allocate memory for the file handle object */ | |
397 | handle = kzalloc(sizeof(struct vpfe_fh), GFP_KERNEL); | |
398 | ||
399 | if (handle == NULL) | |
400 | return -ENOMEM; | |
401 | ||
402 | v4l2_fh_init(&handle->vfh, &video->video_dev); | |
403 | v4l2_fh_add(&handle->vfh); | |
404 | ||
405 | mutex_lock(&video->lock); | |
406 | /* If decoder is not initialized. initialize it */ | |
407 | if (!video->initialized && vpfe_update_pipe_state(video)) { | |
408 | mutex_unlock(&video->lock); | |
409 | return -ENODEV; | |
410 | } | |
411 | /* Increment device users counter */ | |
412 | video->usrs++; | |
413 | /* Set io_allowed member to false */ | |
414 | handle->io_allowed = 0; | |
622897da MH |
415 | handle->video = video; |
416 | file->private_data = &handle->vfh; | |
417 | mutex_unlock(&video->lock); | |
418 | ||
419 | return 0; | |
420 | } | |
421 | ||
422 | /* get the next buffer available from dma queue */ | |
423 | static unsigned long | |
424 | vpfe_video_get_next_buffer(struct vpfe_video_device *video) | |
425 | { | |
426 | video->cur_frm = video->next_frm = | |
427 | list_entry(video->dma_queue.next, | |
428 | struct vpfe_cap_buffer, list); | |
429 | ||
430 | list_del(&video->next_frm->list); | |
2d700715 JS |
431 | video->next_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; |
432 | return vb2_dma_contig_plane_dma_addr(&video->next_frm->vb.vb2_buf, 0); | |
622897da MH |
433 | } |
434 | ||
435 | /* schedule the next buffer which is available on dma queue */ | |
436 | void vpfe_video_schedule_next_buffer(struct vpfe_video_device *video) | |
437 | { | |
438 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
439 | unsigned long addr; | |
440 | ||
441 | if (list_empty(&video->dma_queue)) | |
442 | return; | |
443 | ||
444 | video->next_frm = list_entry(video->dma_queue.next, | |
445 | struct vpfe_cap_buffer, list); | |
446 | ||
447 | if (VPFE_PIPELINE_STREAM_SINGLESHOT == video->pipe.state) | |
448 | video->cur_frm = video->next_frm; | |
449 | ||
450 | list_del(&video->next_frm->list); | |
2d700715 JS |
451 | video->next_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; |
452 | addr = vb2_dma_contig_plane_dma_addr(&video->next_frm->vb.vb2_buf, 0); | |
622897da MH |
453 | video->ops->queue(vpfe_dev, addr); |
454 | video->state = VPFE_VIDEO_BUFFER_QUEUED; | |
455 | } | |
456 | ||
457 | /* schedule the buffer for capturing bottom field */ | |
458 | void vpfe_video_schedule_bottom_field(struct vpfe_video_device *video) | |
459 | { | |
460 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
461 | unsigned long addr; | |
462 | ||
2d700715 | 463 | addr = vb2_dma_contig_plane_dma_addr(&video->cur_frm->vb.vb2_buf, 0); |
622897da MH |
464 | addr += video->field_off; |
465 | video->ops->queue(vpfe_dev, addr); | |
466 | } | |
467 | ||
468 | /* make buffer available for dequeue */ | |
469 | void vpfe_video_process_buffer_complete(struct vpfe_video_device *video) | |
470 | { | |
471 | struct vpfe_pipeline *pipe = &video->pipe; | |
472 | ||
2d700715 JS |
473 | v4l2_get_timestamp(&video->cur_frm->vb.timestamp); |
474 | vb2_buffer_done(&video->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE); | |
622897da MH |
475 | if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS) |
476 | video->cur_frm = video->next_frm; | |
477 | } | |
478 | ||
479 | /* vpfe_stop_capture() - stop streaming */ | |
480 | static void vpfe_stop_capture(struct vpfe_video_device *video) | |
481 | { | |
482 | struct vpfe_pipeline *pipe = &video->pipe; | |
483 | ||
484 | video->started = 0; | |
485 | ||
486 | if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
487 | return; | |
488 | if (all_videos_stopped(video)) | |
489 | vpfe_pipeline_set_stream(pipe, | |
490 | VPFE_PIPELINE_STREAM_STOPPED); | |
491 | } | |
492 | ||
493 | /* | |
494 | * vpfe_release() - release video device | |
495 | * @file: file pointer | |
496 | * | |
497 | * deletes buffer queue, frees the buffers and the vpfe file handle | |
498 | * | |
499 | * Return 0 | |
500 | */ | |
501 | static int vpfe_release(struct file *file) | |
502 | { | |
503 | struct vpfe_video_device *video = video_drvdata(file); | |
504 | struct v4l2_fh *vfh = file->private_data; | |
505 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
506 | struct vpfe_fh *fh = container_of(vfh, struct vpfe_fh, vfh); | |
507 | ||
508 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_release\n"); | |
509 | ||
510 | /* Get the device lock */ | |
511 | mutex_lock(&video->lock); | |
512 | /* if this instance is doing IO */ | |
513 | if (fh->io_allowed) { | |
514 | if (video->started) { | |
515 | vpfe_stop_capture(video); | |
516 | /* mark pipe state as stopped in vpfe_release(), | |
517 | as app might call streamon() after streamoff() | |
518 | in which case driver has to start streaming. | |
519 | */ | |
520 | video->pipe.state = VPFE_PIPELINE_STREAM_STOPPED; | |
521 | vb2_streamoff(&video->buffer_queue, | |
522 | video->buffer_queue.type); | |
523 | } | |
524 | video->io_usrs = 0; | |
525 | /* Free buffers allocated */ | |
526 | vb2_queue_release(&video->buffer_queue); | |
527 | vb2_dma_contig_cleanup_ctx(video->alloc_ctx); | |
528 | } | |
529 | /* Decrement device users counter */ | |
530 | video->usrs--; | |
933fd6e5 LP |
531 | v4l2_fh_del(&fh->vfh); |
532 | v4l2_fh_exit(&fh->vfh); | |
622897da MH |
533 | /* If this is the last file handle */ |
534 | if (!video->usrs) | |
535 | video->initialized = 0; | |
536 | mutex_unlock(&video->lock); | |
537 | file->private_data = NULL; | |
538 | /* Free memory allocated to file handle object */ | |
539 | v4l2_fh_del(vfh); | |
540 | kzfree(fh); | |
541 | return 0; | |
542 | } | |
543 | ||
544 | /* | |
545 | * vpfe_mmap() - It is used to map kernel space buffers | |
546 | * into user spaces | |
547 | */ | |
548 | static int vpfe_mmap(struct file *file, struct vm_area_struct *vma) | |
549 | { | |
550 | struct vpfe_video_device *video = video_drvdata(file); | |
551 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
552 | ||
553 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_mmap\n"); | |
554 | return vb2_mmap(&video->buffer_queue, vma); | |
555 | } | |
556 | ||
557 | /* | |
558 | * vpfe_poll() - It is used for select/poll system call | |
559 | */ | |
560 | static unsigned int vpfe_poll(struct file *file, poll_table *wait) | |
561 | { | |
562 | struct vpfe_video_device *video = video_drvdata(file); | |
563 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
564 | ||
565 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_poll\n"); | |
566 | if (video->started) | |
567 | return vb2_poll(&video->buffer_queue, file, wait); | |
568 | return 0; | |
569 | } | |
570 | ||
571 | /* vpfe capture driver file operations */ | |
572 | static const struct v4l2_file_operations vpfe_fops = { | |
573 | .owner = THIS_MODULE, | |
574 | .open = vpfe_open, | |
575 | .release = vpfe_release, | |
576 | .unlocked_ioctl = video_ioctl2, | |
577 | .mmap = vpfe_mmap, | |
578 | .poll = vpfe_poll | |
579 | }; | |
580 | ||
581 | /* | |
582 | * vpfe_querycap() - query capabilities of video device | |
583 | * @file: file pointer | |
584 | * @priv: void pointer | |
585 | * @cap: pointer to v4l2_capability structure | |
586 | * | |
587 | * fills v4l2 capabilities structure | |
588 | * | |
589 | * Return 0 | |
590 | */ | |
591 | static int vpfe_querycap(struct file *file, void *priv, | |
592 | struct v4l2_capability *cap) | |
593 | { | |
594 | struct vpfe_video_device *video = video_drvdata(file); | |
595 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
596 | ||
597 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n"); | |
598 | ||
599 | if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | |
57e774cc | 600 | cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; |
622897da | 601 | else |
57e774cc HV |
602 | cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; |
603 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | | |
604 | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; | |
622897da MH |
605 | strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver)); |
606 | strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info)); | |
607 | strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card)); | |
608 | ||
609 | return 0; | |
610 | } | |
611 | ||
612 | /* | |
613 | * vpfe_g_fmt() - get the format which is active on video device | |
614 | * @file: file pointer | |
615 | * @priv: void pointer | |
616 | * @fmt: pointer to v4l2_format structure | |
617 | * | |
618 | * fills v4l2 format structure with active format | |
619 | * | |
620 | * Return 0 | |
621 | */ | |
622 | static int vpfe_g_fmt(struct file *file, void *priv, | |
623 | struct v4l2_format *fmt) | |
624 | { | |
625 | struct vpfe_video_device *video = video_drvdata(file); | |
626 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
627 | ||
628 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_fmt\n"); | |
629 | /* Fill in the information about format */ | |
630 | *fmt = video->fmt; | |
631 | return 0; | |
632 | } | |
633 | ||
634 | /* | |
635 | * vpfe_enum_fmt() - enum formats supported on media chain | |
636 | * @file: file pointer | |
637 | * @priv: void pointer | |
638 | * @fmt: pointer to v4l2_fmtdesc structure | |
639 | * | |
640 | * fills v4l2_fmtdesc structure with output format set on adjacent subdev, | |
641 | * only one format is enumearted as subdevs are already configured | |
642 | * | |
2f9e96c3 | 643 | * Return 0 if successful, error code otherwise |
622897da MH |
644 | */ |
645 | static int vpfe_enum_fmt(struct file *file, void *priv, | |
646 | struct v4l2_fmtdesc *fmt) | |
647 | { | |
648 | struct vpfe_video_device *video = video_drvdata(file); | |
649 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
650 | struct v4l2_subdev_format sd_fmt; | |
651 | struct v4l2_mbus_framefmt mbus; | |
652 | struct v4l2_subdev *subdev; | |
653 | struct v4l2_format format; | |
654 | struct media_pad *remote; | |
655 | int ret; | |
656 | ||
657 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_fmt\n"); | |
658 | ||
659 | /* since already subdev pad format is set, | |
660 | only one pixel format is available */ | |
661 | if (fmt->index > 0) { | |
662 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid index\n"); | |
663 | return -EINVAL; | |
664 | } | |
665 | /* get the remote pad */ | |
1bddf1b3 | 666 | remote = media_entity_remote_pad(&video->pad); |
622897da MH |
667 | if (remote == NULL) { |
668 | v4l2_err(&vpfe_dev->v4l2_dev, | |
669 | "invalid remote pad for video node\n"); | |
670 | return -EINVAL; | |
671 | } | |
672 | /* get the remote subdev */ | |
673 | subdev = vpfe_video_remote_subdev(video, NULL); | |
674 | if (subdev == NULL) { | |
675 | v4l2_err(&vpfe_dev->v4l2_dev, | |
676 | "invalid remote subdev for video node\n"); | |
677 | return -EINVAL; | |
678 | } | |
679 | sd_fmt.pad = remote->index; | |
680 | sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; | |
681 | /* get output format of remote subdev */ | |
682 | ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &sd_fmt); | |
683 | if (ret) { | |
684 | v4l2_err(&vpfe_dev->v4l2_dev, | |
685 | "invalid remote subdev for video node\n"); | |
686 | return ret; | |
687 | } | |
688 | /* convert to pix format */ | |
689 | mbus.code = sd_fmt.format.code; | |
690 | mbus_to_pix(&mbus, &format.fmt.pix); | |
691 | /* copy the result */ | |
692 | fmt->pixelformat = format.fmt.pix.pixelformat; | |
693 | ||
694 | return 0; | |
695 | } | |
696 | ||
697 | /* | |
698 | * vpfe_s_fmt() - set the format on video device | |
699 | * @file: file pointer | |
700 | * @priv: void pointer | |
701 | * @fmt: pointer to v4l2_format structure | |
702 | * | |
703 | * validate and set the format on video device | |
704 | * | |
705 | * Return 0 on success, error code otherwise | |
706 | */ | |
707 | static int vpfe_s_fmt(struct file *file, void *priv, | |
708 | struct v4l2_format *fmt) | |
709 | { | |
710 | struct vpfe_video_device *video = video_drvdata(file); | |
711 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
712 | struct v4l2_format format; | |
713 | int ret; | |
714 | ||
715 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt\n"); | |
716 | /* If streaming is started, return error */ | |
717 | if (video->started) { | |
718 | v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is started\n"); | |
719 | return -EBUSY; | |
720 | } | |
721 | /* get adjacent subdev's output pad format */ | |
722 | ret = __vpfe_video_get_format(video, &format); | |
723 | if (ret) | |
724 | return ret; | |
725 | *fmt = format; | |
726 | video->fmt = *fmt; | |
727 | return 0; | |
728 | } | |
729 | ||
730 | /* | |
731 | * vpfe_try_fmt() - try the format on video device | |
732 | * @file: file pointer | |
733 | * @priv: void pointer | |
734 | * @fmt: pointer to v4l2_format structure | |
735 | * | |
736 | * validate the format, update with correct format | |
737 | * based on output format set on adjacent subdev | |
738 | * | |
739 | * Return 0 on success, error code otherwise | |
740 | */ | |
741 | static int vpfe_try_fmt(struct file *file, void *priv, | |
742 | struct v4l2_format *fmt) | |
743 | { | |
744 | struct vpfe_video_device *video = video_drvdata(file); | |
745 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
746 | struct v4l2_format format; | |
747 | int ret; | |
748 | ||
749 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt\n"); | |
750 | /* get adjacent subdev's output pad format */ | |
751 | ret = __vpfe_video_get_format(video, &format); | |
752 | if (ret) | |
753 | return ret; | |
754 | ||
755 | *fmt = format; | |
756 | return 0; | |
757 | } | |
758 | ||
759 | /* | |
760 | * vpfe_enum_input() - enum inputs supported on media chain | |
761 | * @file: file pointer | |
762 | * @priv: void pointer | |
763 | * @fmt: pointer to v4l2_fmtdesc structure | |
764 | * | |
765 | * fills v4l2_input structure with input available on media chain, | |
766 | * only one input is enumearted as media chain is setup by this time | |
767 | * | |
2f9e96c3 | 768 | * Return 0 if successful, -EINVAL is media chain is invalid |
622897da MH |
769 | */ |
770 | static int vpfe_enum_input(struct file *file, void *priv, | |
771 | struct v4l2_input *inp) | |
772 | { | |
773 | struct vpfe_video_device *video = video_drvdata(file); | |
774 | struct vpfe_ext_subdev_info *sdinfo = video->current_ext_subdev; | |
775 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
776 | ||
777 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_input\n"); | |
2f9e96c3 | 778 | /* enumerate from the subdev user has chosen through mc */ |
622897da MH |
779 | if (inp->index < sdinfo->num_inputs) { |
780 | memcpy(inp, &sdinfo->inputs[inp->index], | |
781 | sizeof(struct v4l2_input)); | |
782 | return 0; | |
783 | } | |
784 | return -EINVAL; | |
785 | } | |
786 | ||
787 | /* | |
788 | * vpfe_g_input() - get index of the input which is active | |
789 | * @file: file pointer | |
790 | * @priv: void pointer | |
791 | * @index: pointer to unsigned int | |
792 | * | |
793 | * set index with input index which is active | |
794 | */ | |
795 | static int vpfe_g_input(struct file *file, void *priv, unsigned int *index) | |
796 | { | |
797 | struct vpfe_video_device *video = video_drvdata(file); | |
798 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
799 | ||
800 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_input\n"); | |
801 | ||
802 | *index = video->current_input; | |
803 | return 0; | |
804 | } | |
805 | ||
806 | /* | |
807 | * vpfe_s_input() - set input which is pointed by input index | |
808 | * @file: file pointer | |
809 | * @priv: void pointer | |
810 | * @index: pointer to unsigned int | |
811 | * | |
812 | * set input on external subdev | |
813 | * | |
814 | * Return 0 on success, error code otherwise | |
815 | */ | |
816 | static int vpfe_s_input(struct file *file, void *priv, unsigned int index) | |
817 | { | |
818 | struct vpfe_video_device *video = video_drvdata(file); | |
819 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
820 | struct vpfe_ext_subdev_info *sdinfo; | |
821 | struct vpfe_route *route; | |
822 | struct v4l2_input *inps; | |
823 | u32 output; | |
824 | u32 input; | |
825 | int ret; | |
826 | int i; | |
827 | ||
828 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); | |
829 | ||
830 | ret = mutex_lock_interruptible(&video->lock); | |
831 | if (ret) | |
832 | return ret; | |
833 | /* | |
834 | * If streaming is started return device busy | |
835 | * error | |
836 | */ | |
837 | if (video->started) { | |
838 | v4l2_err(&vpfe_dev->v4l2_dev, "Streaming is on\n"); | |
839 | ret = -EBUSY; | |
840 | goto unlock_out; | |
841 | } | |
842 | ||
843 | sdinfo = video->current_ext_subdev; | |
844 | if (!sdinfo->registered) { | |
845 | ret = -EINVAL; | |
846 | goto unlock_out; | |
847 | } | |
848 | if (vpfe_dev->cfg->setup_input && | |
849 | vpfe_dev->cfg->setup_input(sdinfo->grp_id) < 0) { | |
850 | ret = -EFAULT; | |
851 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | |
852 | "couldn't setup input for %s\n", | |
853 | sdinfo->module_name); | |
854 | goto unlock_out; | |
855 | } | |
856 | route = &sdinfo->routes[index]; | |
857 | if (route && sdinfo->can_route) { | |
858 | input = route->input; | |
859 | output = route->output; | |
860 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, | |
861 | sdinfo->grp_id, video, | |
862 | s_routing, input, output, 0); | |
863 | if (ret) { | |
864 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | |
865 | "s_input:error in setting input in decoder\n"); | |
866 | ret = -EINVAL; | |
867 | goto unlock_out; | |
868 | } | |
869 | } | |
870 | /* set standards set by subdev in video device */ | |
871 | for (i = 0; i < sdinfo->num_inputs; i++) { | |
872 | inps = &sdinfo->inputs[i]; | |
873 | video->video_dev.tvnorms |= inps->std; | |
874 | } | |
875 | video->current_input = index; | |
876 | unlock_out: | |
877 | mutex_unlock(&video->lock); | |
878 | return ret; | |
879 | } | |
880 | ||
881 | /* | |
882 | * vpfe_querystd() - query std which is being input on external subdev | |
883 | * @file: file pointer | |
884 | * @priv: void pointer | |
885 | * @std_id: pointer to v4l2_std_id structure | |
886 | * | |
887 | * call external subdev through v4l2_device_call_until_err to | |
888 | * get the std that is being active. | |
889 | * | |
890 | * Return 0 on success, error code otherwise | |
891 | */ | |
892 | static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) | |
893 | { | |
894 | struct vpfe_video_device *video = video_drvdata(file); | |
895 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
896 | struct vpfe_ext_subdev_info *sdinfo; | |
897 | int ret; | |
898 | ||
899 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); | |
900 | ||
901 | ret = mutex_lock_interruptible(&video->lock); | |
902 | sdinfo = video->current_ext_subdev; | |
903 | if (ret) | |
904 | return ret; | |
905 | /* Call querystd function of decoder device */ | |
906 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | |
907 | video, querystd, std_id); | |
908 | mutex_unlock(&video->lock); | |
909 | return ret; | |
910 | } | |
911 | ||
912 | /* | |
913 | * vpfe_s_std() - set std on external subdev | |
914 | * @file: file pointer | |
915 | * @priv: void pointer | |
916 | * @std_id: pointer to v4l2_std_id structure | |
917 | * | |
918 | * set std pointed by std_id on external subdev by calling it using | |
919 | * v4l2_device_call_until_err | |
920 | * | |
921 | * Return 0 on success, error code otherwise | |
922 | */ | |
314527ac | 923 | static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) |
622897da MH |
924 | { |
925 | struct vpfe_video_device *video = video_drvdata(file); | |
926 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
927 | struct vpfe_ext_subdev_info *sdinfo; | |
928 | int ret; | |
929 | ||
930 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); | |
931 | ||
932 | /* Call decoder driver function to set the standard */ | |
933 | ret = mutex_lock_interruptible(&video->lock); | |
934 | if (ret) | |
935 | return ret; | |
936 | sdinfo = video->current_ext_subdev; | |
937 | /* If streaming is started, return device busy error */ | |
938 | if (video->started) { | |
939 | v4l2_err(&vpfe_dev->v4l2_dev, "streaming is started\n"); | |
940 | ret = -EBUSY; | |
941 | goto unlock_out; | |
942 | } | |
943 | ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id, | |
8774bed9 | 944 | video, s_std, std_id); |
622897da MH |
945 | if (ret < 0) { |
946 | v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n"); | |
947 | video->stdid = V4L2_STD_UNKNOWN; | |
948 | goto unlock_out; | |
949 | } | |
314527ac | 950 | video->stdid = std_id; |
622897da MH |
951 | unlock_out: |
952 | mutex_unlock(&video->lock); | |
953 | return ret; | |
954 | } | |
955 | ||
956 | static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm) | |
957 | { | |
958 | struct vpfe_video_device *video = video_drvdata(file); | |
959 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
960 | ||
961 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_std\n"); | |
962 | *tvnorm = video->stdid; | |
963 | return 0; | |
964 | } | |
965 | ||
966 | /* | |
967 | * vpfe_enum_dv_timings() - enumerate dv_timings which are supported by | |
968 | * to external subdev | |
969 | * @file: file pointer | |
970 | * @priv: void pointer | |
971 | * @timings: pointer to v4l2_enum_dv_timings structure | |
972 | * | |
973 | * enum dv_timings's which are supported by external subdev through | |
974 | * v4l2_subdev_call | |
975 | * | |
976 | * Return 0 on success, error code otherwise | |
977 | */ | |
978 | static int | |
979 | vpfe_enum_dv_timings(struct file *file, void *fh, | |
980 | struct v4l2_enum_dv_timings *timings) | |
981 | { | |
982 | struct vpfe_video_device *video = video_drvdata(file); | |
983 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
984 | struct v4l2_subdev *subdev = video->current_ext_subdev->subdev; | |
985 | ||
0eda185c LP |
986 | timings->pad = 0; |
987 | ||
622897da | 988 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_dv_timings\n"); |
0eda185c | 989 | return v4l2_subdev_call(subdev, pad, enum_dv_timings, timings); |
622897da MH |
990 | } |
991 | ||
992 | /* | |
993 | * vpfe_query_dv_timings() - query the dv_timings which is being input | |
994 | * to external subdev | |
995 | * @file: file pointer | |
996 | * @priv: void pointer | |
997 | * @timings: pointer to v4l2_dv_timings structure | |
998 | * | |
999 | * get dv_timings which is being input on external subdev through | |
1000 | * v4l2_subdev_call | |
1001 | * | |
1002 | * Return 0 on success, error code otherwise | |
1003 | */ | |
1004 | static int | |
1005 | vpfe_query_dv_timings(struct file *file, void *fh, | |
1006 | struct v4l2_dv_timings *timings) | |
1007 | { | |
1008 | struct vpfe_video_device *video = video_drvdata(file); | |
1009 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1010 | struct v4l2_subdev *subdev = video->current_ext_subdev->subdev; | |
1011 | ||
1012 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_query_dv_timings\n"); | |
1013 | return v4l2_subdev_call(subdev, video, query_dv_timings, timings); | |
1014 | } | |
1015 | ||
1016 | /* | |
4bd3bb71 | 1017 | * vpfe_s_dv_timings() - set dv_timings on external subdev |
622897da MH |
1018 | * @file: file pointer |
1019 | * @priv: void pointer | |
1020 | * @timings: pointer to v4l2_dv_timings structure | |
1021 | * | |
4bd3bb71 | 1022 | * set dv_timings pointed by timings on external subdev through |
622897da MH |
1023 | * v4l2_device_call_until_err, this configures amplifier also |
1024 | * | |
1025 | * Return 0 on success, error code otherwise | |
1026 | */ | |
1027 | static int | |
1028 | vpfe_s_dv_timings(struct file *file, void *fh, | |
1029 | struct v4l2_dv_timings *timings) | |
1030 | { | |
1031 | struct vpfe_video_device *video = video_drvdata(file); | |
1032 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1033 | ||
1034 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_dv_timings\n"); | |
1035 | ||
1036 | video->stdid = V4L2_STD_UNKNOWN; | |
1037 | return v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, | |
1038 | video->current_ext_subdev->grp_id, | |
1039 | video, s_dv_timings, timings); | |
1040 | } | |
1041 | ||
1042 | /* | |
4bd3bb71 | 1043 | * vpfe_g_dv_timings() - get dv_timings which is set on external subdev |
622897da MH |
1044 | * @file: file pointer |
1045 | * @priv: void pointer | |
1046 | * @timings: pointer to v4l2_dv_timings structure | |
1047 | * | |
4bd3bb71 | 1048 | * get dv_timings which is set on external subdev through |
622897da MH |
1049 | * v4l2_subdev_call |
1050 | * | |
1051 | * Return 0 on success, error code otherwise | |
1052 | */ | |
1053 | static int | |
1054 | vpfe_g_dv_timings(struct file *file, void *fh, | |
1055 | struct v4l2_dv_timings *timings) | |
1056 | { | |
1057 | struct vpfe_video_device *video = video_drvdata(file); | |
1058 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1059 | struct v4l2_subdev *subdev = video->current_ext_subdev->subdev; | |
1060 | ||
1061 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_g_dv_timings\n"); | |
1062 | return v4l2_subdev_call(subdev, video, g_dv_timings, timings); | |
1063 | } | |
1064 | ||
1065 | /* | |
1066 | * Videobuf operations | |
1067 | */ | |
1068 | /* | |
1069 | * vpfe_buffer_queue_setup : Callback function for buffer setup. | |
1070 | * @vq: vb2_queue ptr | |
1071 | * @fmt: v4l2 format | |
1072 | * @nbuffers: ptr to number of buffers requested by application | |
1073 | * @nplanes:: contains number of distinct video planes needed to hold a frame | |
1074 | * @sizes[]: contains the size (in bytes) of each plane. | |
1075 | * @alloc_ctxs: ptr to allocation context | |
1076 | * | |
1077 | * This callback function is called when reqbuf() is called to adjust | |
1078 | * the buffer nbuffers and buffer size | |
1079 | */ | |
1080 | static int | |
df9ecb0c | 1081 | vpfe_buffer_queue_setup(struct vb2_queue *vq, |
622897da MH |
1082 | unsigned int *nbuffers, unsigned int *nplanes, |
1083 | unsigned int sizes[], void *alloc_ctxs[]) | |
1084 | { | |
1085 | struct vpfe_fh *fh = vb2_get_drv_priv(vq); | |
1086 | struct vpfe_video_device *video = fh->video; | |
1087 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
622897da MH |
1088 | unsigned long size; |
1089 | ||
1090 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_queue_setup\n"); | |
1091 | size = video->fmt.fmt.pix.sizeimage; | |
1092 | ||
171fe6d1 LP |
1093 | if (vq->num_buffers + *nbuffers < 3) |
1094 | *nbuffers = 3 - vq->num_buffers; | |
1095 | ||
622897da MH |
1096 | *nplanes = 1; |
1097 | sizes[0] = size; | |
1098 | alloc_ctxs[0] = video->alloc_ctx; | |
1099 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, | |
1100 | "nbuffers=%d, size=%lu\n", *nbuffers, size); | |
1101 | return 0; | |
1102 | } | |
1103 | ||
1104 | /* | |
1105 | * vpfe_buffer_prepare : callback function for buffer prepare | |
1106 | * @vb: ptr to vb2_buffer | |
1107 | * | |
1108 | * This is the callback function for buffer prepare when vb2_qbuf() | |
1109 | * function is called. The buffer is prepared and user space virtual address | |
1110 | * or user address is converted into physical address | |
1111 | */ | |
1112 | static int vpfe_buffer_prepare(struct vb2_buffer *vb) | |
1113 | { | |
1114 | struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); | |
1115 | struct vpfe_video_device *video = fh->video; | |
1116 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1117 | unsigned long addr; | |
1118 | ||
1119 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buffer_prepare\n"); | |
1120 | ||
1121 | if (vb->state != VB2_BUF_STATE_ACTIVE && | |
1122 | vb->state != VB2_BUF_STATE_PREPARED) | |
1123 | return 0; | |
1124 | ||
1125 | /* Initialize buffer */ | |
1126 | vb2_set_plane_payload(vb, 0, video->fmt.fmt.pix.sizeimage); | |
1127 | if (vb2_plane_vaddr(vb, 0) && | |
1128 | vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) | |
1129 | return -EINVAL; | |
1130 | ||
1131 | addr = vb2_dma_contig_plane_dma_addr(vb, 0); | |
1132 | /* Make sure user addresses are aligned to 32 bytes */ | |
1133 | if (!ALIGN(addr, 32)) | |
1134 | return -EINVAL; | |
1135 | ||
1136 | return 0; | |
1137 | } | |
1138 | ||
1139 | static void vpfe_buffer_queue(struct vb2_buffer *vb) | |
1140 | { | |
2d700715 | 1141 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
622897da MH |
1142 | /* Get the file handle object and device object */ |
1143 | struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); | |
1144 | struct vpfe_video_device *video = fh->video; | |
1145 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1146 | struct vpfe_pipeline *pipe = &video->pipe; | |
2d700715 | 1147 | struct vpfe_cap_buffer *buf = container_of(vbuf, |
622897da MH |
1148 | struct vpfe_cap_buffer, vb); |
1149 | unsigned long flags; | |
1150 | unsigned long empty; | |
1151 | unsigned long addr; | |
1152 | ||
1153 | spin_lock_irqsave(&video->dma_queue_lock, flags); | |
1154 | empty = list_empty(&video->dma_queue); | |
1155 | /* add the buffer to the DMA queue */ | |
1156 | list_add_tail(&buf->list, &video->dma_queue); | |
1157 | spin_unlock_irqrestore(&video->dma_queue_lock, flags); | |
1158 | /* this case happens in case of single shot */ | |
1159 | if (empty && video->started && pipe->state == | |
1160 | VPFE_PIPELINE_STREAM_SINGLESHOT && | |
1161 | video->state == VPFE_VIDEO_BUFFER_NOT_QUEUED) { | |
1162 | spin_lock(&video->dma_queue_lock); | |
1163 | addr = vpfe_video_get_next_buffer(video); | |
1164 | video->ops->queue(vpfe_dev, addr); | |
1165 | ||
1166 | video->state = VPFE_VIDEO_BUFFER_QUEUED; | |
1167 | spin_unlock(&video->dma_queue_lock); | |
1168 | ||
1169 | /* enable h/w each time in single shot */ | |
1170 | if (vpfe_video_is_pipe_ready(pipe)) | |
1171 | vpfe_pipeline_set_stream(pipe, | |
1172 | VPFE_PIPELINE_STREAM_SINGLESHOT); | |
1173 | } | |
1174 | } | |
1175 | ||
1176 | /* vpfe_start_capture() - start streaming on all the subdevs */ | |
1177 | static int vpfe_start_capture(struct vpfe_video_device *video) | |
1178 | { | |
1179 | struct vpfe_pipeline *pipe = &video->pipe; | |
1180 | int ret = 0; | |
1181 | ||
1182 | video->started = 1; | |
1183 | if (vpfe_video_is_pipe_ready(pipe)) | |
1184 | ret = vpfe_pipeline_set_stream(pipe, pipe->state); | |
1185 | ||
1186 | return ret; | |
1187 | } | |
1188 | ||
1189 | static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count) | |
1190 | { | |
1191 | struct vpfe_fh *fh = vb2_get_drv_priv(vq); | |
1192 | struct vpfe_video_device *video = fh->video; | |
1193 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1194 | unsigned long addr; | |
1195 | int ret; | |
1196 | ||
1197 | ret = mutex_lock_interruptible(&video->lock); | |
1198 | if (ret) | |
1199 | goto streamoff; | |
1200 | ||
1201 | /* Get the next frame from the buffer queue */ | |
1202 | video->cur_frm = video->next_frm = | |
1203 | list_entry(video->dma_queue.next, struct vpfe_cap_buffer, list); | |
1204 | /* Remove buffer from the buffer queue */ | |
1205 | list_del(&video->cur_frm->list); | |
1206 | /* Mark state of the current frame to active */ | |
2d700715 | 1207 | video->cur_frm->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE; |
622897da MH |
1208 | /* Initialize field_id and started member */ |
1209 | video->field_id = 0; | |
2d700715 | 1210 | addr = vb2_dma_contig_plane_dma_addr(&video->cur_frm->vb.vb2_buf, 0); |
622897da MH |
1211 | video->ops->queue(vpfe_dev, addr); |
1212 | video->state = VPFE_VIDEO_BUFFER_QUEUED; | |
1213 | ||
1214 | ret = vpfe_start_capture(video); | |
8f7402a3 LP |
1215 | if (ret) { |
1216 | struct vpfe_cap_buffer *buf, *tmp; | |
1217 | ||
2d700715 JS |
1218 | vb2_buffer_done(&video->cur_frm->vb.vb2_buf, |
1219 | VB2_BUF_STATE_QUEUED); | |
8f7402a3 LP |
1220 | list_for_each_entry_safe(buf, tmp, &video->dma_queue, list) { |
1221 | list_del(&buf->list); | |
2d700715 JS |
1222 | vb2_buffer_done(&buf->vb.vb2_buf, |
1223 | VB2_BUF_STATE_QUEUED); | |
8f7402a3 | 1224 | } |
622897da | 1225 | goto unlock_out; |
8f7402a3 | 1226 | } |
622897da MH |
1227 | |
1228 | mutex_unlock(&video->lock); | |
1229 | ||
1230 | return ret; | |
1231 | unlock_out: | |
1232 | mutex_unlock(&video->lock); | |
1233 | streamoff: | |
1234 | ret = vb2_streamoff(&video->buffer_queue, video->buffer_queue.type); | |
1235 | return 0; | |
1236 | } | |
1237 | ||
1238 | static int vpfe_buffer_init(struct vb2_buffer *vb) | |
1239 | { | |
2d700715 JS |
1240 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
1241 | struct vpfe_cap_buffer *buf = container_of(vbuf, | |
622897da MH |
1242 | struct vpfe_cap_buffer, vb); |
1243 | ||
1244 | INIT_LIST_HEAD(&buf->list); | |
1245 | return 0; | |
1246 | } | |
1247 | ||
1248 | /* abort streaming and wait for last buffer */ | |
e37559b2 | 1249 | static void vpfe_stop_streaming(struct vb2_queue *vq) |
622897da MH |
1250 | { |
1251 | struct vpfe_fh *fh = vb2_get_drv_priv(vq); | |
1252 | struct vpfe_video_device *video = fh->video; | |
1253 | ||
622897da | 1254 | /* release all active buffers */ |
d891ae5e | 1255 | if (video->cur_frm == video->next_frm) { |
2d700715 JS |
1256 | vb2_buffer_done(&video->cur_frm->vb.vb2_buf, |
1257 | VB2_BUF_STATE_ERROR); | |
d891ae5e LP |
1258 | } else { |
1259 | if (video->cur_frm != NULL) | |
2d700715 | 1260 | vb2_buffer_done(&video->cur_frm->vb.vb2_buf, |
d891ae5e LP |
1261 | VB2_BUF_STATE_ERROR); |
1262 | if (video->next_frm != NULL) | |
2d700715 | 1263 | vb2_buffer_done(&video->next_frm->vb.vb2_buf, |
d891ae5e LP |
1264 | VB2_BUF_STATE_ERROR); |
1265 | } | |
1266 | ||
622897da MH |
1267 | while (!list_empty(&video->dma_queue)) { |
1268 | video->next_frm = list_entry(video->dma_queue.next, | |
1269 | struct vpfe_cap_buffer, list); | |
1270 | list_del(&video->next_frm->list); | |
2d700715 JS |
1271 | vb2_buffer_done(&video->next_frm->vb.vb2_buf, |
1272 | VB2_BUF_STATE_ERROR); | |
622897da | 1273 | } |
622897da MH |
1274 | } |
1275 | ||
1276 | static void vpfe_buf_cleanup(struct vb2_buffer *vb) | |
1277 | { | |
2d700715 | 1278 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
622897da MH |
1279 | struct vpfe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); |
1280 | struct vpfe_video_device *video = fh->video; | |
1281 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
2d700715 | 1282 | struct vpfe_cap_buffer *buf = container_of(vbuf, |
622897da MH |
1283 | struct vpfe_cap_buffer, vb); |
1284 | ||
1285 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_buf_cleanup\n"); | |
1286 | if (vb->state == VB2_BUF_STATE_ACTIVE) | |
1287 | list_del_init(&buf->list); | |
1288 | } | |
1289 | ||
1290 | static struct vb2_ops video_qops = { | |
1291 | .queue_setup = vpfe_buffer_queue_setup, | |
1292 | .buf_init = vpfe_buffer_init, | |
1293 | .buf_prepare = vpfe_buffer_prepare, | |
1294 | .start_streaming = vpfe_start_streaming, | |
1295 | .stop_streaming = vpfe_stop_streaming, | |
1296 | .buf_cleanup = vpfe_buf_cleanup, | |
1297 | .buf_queue = vpfe_buffer_queue, | |
1298 | }; | |
1299 | ||
1300 | /* | |
1301 | * vpfe_reqbufs() - supported REQBUF only once opening | |
1302 | * the device. | |
1303 | */ | |
1304 | static int vpfe_reqbufs(struct file *file, void *priv, | |
1305 | struct v4l2_requestbuffers *req_buf) | |
1306 | { | |
1307 | struct vpfe_video_device *video = video_drvdata(file); | |
1308 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1309 | struct vpfe_fh *fh = file->private_data; | |
1310 | struct vb2_queue *q; | |
1311 | int ret; | |
1312 | ||
1313 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); | |
1314 | ||
1315 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != req_buf->type && | |
1316 | V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) { | |
1317 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buffer type\n"); | |
1318 | return -EINVAL; | |
1319 | } | |
1320 | ||
1321 | ret = mutex_lock_interruptible(&video->lock); | |
1322 | if (ret) | |
1323 | return ret; | |
1324 | ||
1325 | if (video->io_usrs != 0) { | |
1326 | v4l2_err(&vpfe_dev->v4l2_dev, "Only one IO user allowed\n"); | |
1327 | ret = -EBUSY; | |
1328 | goto unlock_out; | |
1329 | } | |
1330 | video->memory = req_buf->memory; | |
1331 | ||
1332 | /* Initialize videobuf2 queue as per the buffer type */ | |
1333 | video->alloc_ctx = vb2_dma_contig_init_ctx(vpfe_dev->pdev); | |
1334 | if (IS_ERR(video->alloc_ctx)) { | |
1335 | v4l2_err(&vpfe_dev->v4l2_dev, "Failed to get the context\n"); | |
1336 | return PTR_ERR(video->alloc_ctx); | |
1337 | } | |
1338 | ||
1339 | q = &video->buffer_queue; | |
1340 | q->type = req_buf->type; | |
1341 | q->io_modes = VB2_MMAP | VB2_USERPTR; | |
1342 | q->drv_priv = fh; | |
b3379c62 | 1343 | q->min_buffers_needed = 1; |
622897da MH |
1344 | q->ops = &video_qops; |
1345 | q->mem_ops = &vb2_dma_contig_memops; | |
1346 | q->buf_struct_size = sizeof(struct vpfe_cap_buffer); | |
4f26aa17 | 1347 | q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; |
622897da MH |
1348 | |
1349 | ret = vb2_queue_init(q); | |
1350 | if (ret) { | |
1351 | v4l2_err(&vpfe_dev->v4l2_dev, "vb2_queue_init() failed\n"); | |
1352 | vb2_dma_contig_cleanup_ctx(vpfe_dev->pdev); | |
1353 | return ret; | |
1354 | } | |
1355 | ||
1356 | fh->io_allowed = 1; | |
1357 | video->io_usrs = 1; | |
1358 | INIT_LIST_HEAD(&video->dma_queue); | |
1359 | ret = vb2_reqbufs(&video->buffer_queue, req_buf); | |
1360 | ||
1361 | unlock_out: | |
1362 | mutex_unlock(&video->lock); | |
1363 | return ret; | |
1364 | } | |
1365 | ||
1366 | /* | |
1367 | * vpfe_querybuf() - query buffers for exchange | |
1368 | */ | |
1369 | static int vpfe_querybuf(struct file *file, void *priv, | |
1370 | struct v4l2_buffer *buf) | |
1371 | { | |
1372 | struct vpfe_video_device *video = video_drvdata(file); | |
1373 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1374 | ||
1375 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querybuf\n"); | |
1376 | ||
1377 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type && | |
1378 | V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { | |
1379 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | |
1380 | return -EINVAL; | |
1381 | } | |
1382 | ||
1383 | if (video->memory != V4L2_MEMORY_MMAP) { | |
1384 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid memory\n"); | |
1385 | return -EINVAL; | |
1386 | } | |
1387 | ||
1388 | /* Call vb2_querybuf to get information */ | |
1389 | return vb2_querybuf(&video->buffer_queue, buf); | |
1390 | } | |
1391 | ||
1392 | /* | |
1393 | * vpfe_qbuf() - queue buffers for capture or processing | |
1394 | */ | |
1395 | static int vpfe_qbuf(struct file *file, void *priv, | |
1396 | struct v4l2_buffer *p) | |
1397 | { | |
1398 | struct vpfe_video_device *video = video_drvdata(file); | |
1399 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1400 | struct vpfe_fh *fh = file->private_data; | |
1401 | ||
1402 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_qbuf\n"); | |
1403 | ||
1404 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != p->type && | |
1405 | V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) { | |
1406 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | |
1407 | return -EINVAL; | |
1408 | } | |
1409 | /* | |
1410 | * If this file handle is not allowed to do IO, | |
1411 | * return error | |
1412 | */ | |
1413 | if (!fh->io_allowed) { | |
1414 | v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); | |
1415 | return -EACCES; | |
1416 | } | |
1417 | ||
1418 | return vb2_qbuf(&video->buffer_queue, p); | |
1419 | } | |
1420 | ||
1421 | /* | |
1422 | * vpfe_dqbuf() - deque buffer which is done with processing | |
1423 | */ | |
1424 | static int vpfe_dqbuf(struct file *file, void *priv, | |
1425 | struct v4l2_buffer *buf) | |
1426 | { | |
1427 | struct vpfe_video_device *video = video_drvdata(file); | |
1428 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1429 | ||
1430 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_dqbuf\n"); | |
1431 | ||
1432 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf->type && | |
1433 | V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { | |
1434 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | |
1435 | return -EINVAL; | |
1436 | } | |
1437 | ||
1438 | return vb2_dqbuf(&video->buffer_queue, | |
1439 | buf, (file->f_flags & O_NONBLOCK)); | |
1440 | } | |
1441 | ||
1442 | /* | |
4bd3bb71 | 1443 | * vpfe_streamon() - start streaming |
622897da MH |
1444 | * @file: file pointer |
1445 | * @priv: void pointer | |
1446 | * @buf_type: enum v4l2_buf_type | |
1447 | * | |
1448 | * queue buffer onto hardware for capture/processing and | |
1449 | * start all the subdevs which are in media chain | |
1450 | * | |
1451 | * Return 0 on success, error code otherwise | |
1452 | */ | |
1453 | static int vpfe_streamon(struct file *file, void *priv, | |
1454 | enum v4l2_buf_type buf_type) | |
1455 | { | |
1456 | struct vpfe_video_device *video = video_drvdata(file); | |
1457 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1458 | struct vpfe_pipeline *pipe = &video->pipe; | |
1459 | struct vpfe_fh *fh = file->private_data; | |
1460 | struct vpfe_ext_subdev_info *sdinfo; | |
1461 | int ret = -EINVAL; | |
1462 | ||
1463 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); | |
1464 | ||
1465 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE != buf_type && | |
1466 | V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { | |
1467 | v4l2_err(&vpfe_dev->v4l2_dev, "Invalid buf type\n"); | |
1468 | return ret; | |
1469 | } | |
1470 | /* If file handle is not allowed IO, return error */ | |
1471 | if (!fh->io_allowed) { | |
1472 | v4l2_err(&vpfe_dev->v4l2_dev, "fh->io_allowed\n"); | |
1473 | return -EACCES; | |
1474 | } | |
1475 | sdinfo = video->current_ext_subdev; | |
1476 | /* If buffer queue is empty, return error */ | |
1477 | if (list_empty(&video->buffer_queue.queued_list)) { | |
1478 | v4l2_err(&vpfe_dev->v4l2_dev, "buffer queue is empty\n"); | |
1479 | return -EIO; | |
1480 | } | |
1481 | /* Validate the pipeline */ | |
1482 | if (V4L2_BUF_TYPE_VIDEO_CAPTURE == buf_type) { | |
1483 | ret = vpfe_video_validate_pipeline(pipe); | |
1484 | if (ret < 0) | |
1485 | return ret; | |
1486 | } | |
1487 | /* Call vb2_streamon to start streaming */ | |
1488 | return vb2_streamon(&video->buffer_queue, buf_type); | |
1489 | } | |
1490 | ||
1491 | /* | |
4bd3bb71 | 1492 | * vpfe_streamoff() - stop streaming |
622897da MH |
1493 | * @file: file pointer |
1494 | * @priv: void pointer | |
1495 | * @buf_type: enum v4l2_buf_type | |
1496 | * | |
1497 | * stop all the subdevs which are in media chain | |
1498 | * | |
1499 | * Return 0 on success, error code otherwise | |
1500 | */ | |
1501 | static int vpfe_streamoff(struct file *file, void *priv, | |
1502 | enum v4l2_buf_type buf_type) | |
1503 | { | |
1504 | struct vpfe_video_device *video = video_drvdata(file); | |
1505 | struct vpfe_device *vpfe_dev = video->vpfe_dev; | |
1506 | struct vpfe_fh *fh = file->private_data; | |
1507 | int ret = 0; | |
1508 | ||
1509 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); | |
1510 | ||
1511 | if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | |
1512 | buf_type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { | |
1513 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "Invalid buf type\n"); | |
1514 | return -EINVAL; | |
1515 | } | |
1516 | ||
1517 | /* If io is allowed for this file handle, return error */ | |
1518 | if (!fh->io_allowed) { | |
1519 | v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "fh->io_allowed\n"); | |
1520 | return -EACCES; | |
1521 | } | |
1522 | ||
1523 | /* If streaming is not started, return error */ | |
1524 | if (!video->started) { | |
1525 | v4l2_err(&vpfe_dev->v4l2_dev, "device is not started\n"); | |
1526 | return -EINVAL; | |
1527 | } | |
1528 | ||
1529 | ret = mutex_lock_interruptible(&video->lock); | |
1530 | if (ret) | |
1531 | return ret; | |
1532 | ||
1533 | vpfe_stop_capture(video); | |
1534 | ret = vb2_streamoff(&video->buffer_queue, buf_type); | |
1535 | mutex_unlock(&video->lock); | |
1536 | ||
1537 | return ret; | |
1538 | } | |
1539 | ||
1540 | /* vpfe capture ioctl operations */ | |
1541 | static const struct v4l2_ioctl_ops vpfe_ioctl_ops = { | |
1542 | .vidioc_querycap = vpfe_querycap, | |
1543 | .vidioc_g_fmt_vid_cap = vpfe_g_fmt, | |
1544 | .vidioc_s_fmt_vid_cap = vpfe_s_fmt, | |
1545 | .vidioc_try_fmt_vid_cap = vpfe_try_fmt, | |
1546 | .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt, | |
1547 | .vidioc_g_fmt_vid_out = vpfe_g_fmt, | |
1548 | .vidioc_s_fmt_vid_out = vpfe_s_fmt, | |
1549 | .vidioc_try_fmt_vid_out = vpfe_try_fmt, | |
1550 | .vidioc_enum_fmt_vid_out = vpfe_enum_fmt, | |
1551 | .vidioc_enum_input = vpfe_enum_input, | |
1552 | .vidioc_g_input = vpfe_g_input, | |
1553 | .vidioc_s_input = vpfe_s_input, | |
1554 | .vidioc_querystd = vpfe_querystd, | |
1555 | .vidioc_s_std = vpfe_s_std, | |
1556 | .vidioc_g_std = vpfe_g_std, | |
1557 | .vidioc_enum_dv_timings = vpfe_enum_dv_timings, | |
1558 | .vidioc_query_dv_timings = vpfe_query_dv_timings, | |
1559 | .vidioc_s_dv_timings = vpfe_s_dv_timings, | |
1560 | .vidioc_g_dv_timings = vpfe_g_dv_timings, | |
1561 | .vidioc_reqbufs = vpfe_reqbufs, | |
1562 | .vidioc_querybuf = vpfe_querybuf, | |
1563 | .vidioc_qbuf = vpfe_qbuf, | |
1564 | .vidioc_dqbuf = vpfe_dqbuf, | |
1565 | .vidioc_streamon = vpfe_streamon, | |
1566 | .vidioc_streamoff = vpfe_streamoff, | |
1567 | }; | |
1568 | ||
1569 | /* VPFE video init function */ | |
1570 | int vpfe_video_init(struct vpfe_video_device *video, const char *name) | |
1571 | { | |
1572 | const char *direction; | |
1573 | int ret; | |
1574 | ||
1575 | switch (video->type) { | |
1576 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | |
1577 | direction = "output"; | |
1578 | video->pad.flags = MEDIA_PAD_FL_SINK; | |
1579 | video->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | |
1580 | break; | |
1581 | ||
1582 | case V4L2_BUF_TYPE_VIDEO_OUTPUT: | |
1583 | direction = "input"; | |
1584 | video->pad.flags = MEDIA_PAD_FL_SOURCE; | |
1585 | video->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | |
1586 | break; | |
1587 | ||
1588 | default: | |
1589 | return -EINVAL; | |
1590 | } | |
1591 | /* Initialize field of video device */ | |
1592 | video->video_dev.release = video_device_release; | |
1593 | video->video_dev.fops = &vpfe_fops; | |
1594 | video->video_dev.ioctl_ops = &vpfe_ioctl_ops; | |
1595 | video->video_dev.minor = -1; | |
1596 | video->video_dev.tvnorms = 0; | |
1597 | snprintf(video->video_dev.name, sizeof(video->video_dev.name), | |
1598 | "DAVINCI VIDEO %s %s", name, direction); | |
1599 | ||
622897da MH |
1600 | spin_lock_init(&video->irqlock); |
1601 | spin_lock_init(&video->dma_queue_lock); | |
1602 | mutex_init(&video->lock); | |
1603 | ret = media_entity_init(&video->video_dev.entity, | |
1604 | 1, &video->pad, 0); | |
1605 | if (ret < 0) | |
1606 | return ret; | |
1607 | ||
1608 | video_set_drvdata(&video->video_dev, video); | |
1609 | ||
1610 | return 0; | |
1611 | } | |
1612 | ||
1613 | /* vpfe video device register function */ | |
1614 | int vpfe_video_register(struct vpfe_video_device *video, | |
1615 | struct v4l2_device *vdev) | |
1616 | { | |
1617 | int ret; | |
1618 | ||
1619 | video->video_dev.v4l2_dev = vdev; | |
1620 | ||
1621 | ret = video_register_device(&video->video_dev, VFL_TYPE_GRABBER, -1); | |
1622 | if (ret < 0) | |
1623 | pr_err("%s: could not register video device (%d)\n", | |
1624 | __func__, ret); | |
1625 | return ret; | |
1626 | } | |
1627 | ||
1628 | /* vpfe video device unregister function */ | |
1629 | void vpfe_video_unregister(struct vpfe_video_device *video) | |
1630 | { | |
1631 | if (video_is_registered(&video->video_dev)) { | |
622897da | 1632 | video_unregister_device(&video->video_dev); |
7bb151b2 | 1633 | media_entity_cleanup(&video->video_dev.entity); |
622897da MH |
1634 | } |
1635 | } |