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