diff options
Diffstat (limited to 'drivers/media/video/davinci/vpbe_display.c')
-rw-r--r-- | drivers/media/video/davinci/vpbe_display.c | 1860 |
1 files changed, 1860 insertions, 0 deletions
diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c new file mode 100644 index 00000000000..7f1d83a6d57 --- /dev/null +++ b/drivers/media/video/davinci/vpbe_display.c | |||
@@ -0,0 +1,1860 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ | ||
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 WITHOUT ANY WARRANTY of any | ||
9 | * kind, whether express or implied; without even the implied warranty | ||
10 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/wait.h> | ||
20 | #include <linux/time.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/mutex.h> | ||
25 | #include <linux/videodev2.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include <asm/pgtable.h> | ||
29 | #include <mach/cputype.h> | ||
30 | |||
31 | #include <media/v4l2-dev.h> | ||
32 | #include <media/v4l2-common.h> | ||
33 | #include <media/v4l2-ioctl.h> | ||
34 | #include <media/v4l2-device.h> | ||
35 | #include <media/davinci/vpbe_display.h> | ||
36 | #include <media/davinci/vpbe_types.h> | ||
37 | #include <media/davinci/vpbe.h> | ||
38 | #include <media/davinci/vpbe_venc.h> | ||
39 | #include <media/davinci/vpbe_osd.h> | ||
40 | #include "vpbe_venc_regs.h" | ||
41 | |||
42 | #define VPBE_DISPLAY_DRIVER "vpbe-v4l2" | ||
43 | |||
44 | static int debug; | ||
45 | |||
46 | #define VPBE_DISPLAY_SD_BUF_SIZE (720*576*2) | ||
47 | #define VPBE_DEFAULT_NUM_BUFS 3 | ||
48 | |||
49 | module_param(debug, int, 0644); | ||
50 | |||
51 | static int venc_is_second_field(struct vpbe_display *disp_dev) | ||
52 | { | ||
53 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
54 | int ret; | ||
55 | int val; | ||
56 | |||
57 | ret = v4l2_subdev_call(vpbe_dev->venc, | ||
58 | core, | ||
59 | ioctl, | ||
60 | VENC_GET_FLD, | ||
61 | &val); | ||
62 | if (ret < 0) { | ||
63 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
64 | "Error in getting Field ID 0\n"); | ||
65 | } | ||
66 | return val; | ||
67 | } | ||
68 | |||
69 | static void vpbe_isr_even_field(struct vpbe_display *disp_obj, | ||
70 | struct vpbe_layer *layer) | ||
71 | { | ||
72 | struct timespec timevalue; | ||
73 | |||
74 | if (layer->cur_frm == layer->next_frm) | ||
75 | return; | ||
76 | ktime_get_ts(&timevalue); | ||
77 | layer->cur_frm->ts.tv_sec = timevalue.tv_sec; | ||
78 | layer->cur_frm->ts.tv_usec = timevalue.tv_nsec / NSEC_PER_USEC; | ||
79 | layer->cur_frm->state = VIDEOBUF_DONE; | ||
80 | wake_up_interruptible(&layer->cur_frm->done); | ||
81 | /* Make cur_frm pointing to next_frm */ | ||
82 | layer->cur_frm = layer->next_frm; | ||
83 | } | ||
84 | |||
85 | static void vpbe_isr_odd_field(struct vpbe_display *disp_obj, | ||
86 | struct vpbe_layer *layer) | ||
87 | { | ||
88 | struct osd_state *osd_device = disp_obj->osd_device; | ||
89 | unsigned long addr; | ||
90 | |||
91 | spin_lock(&disp_obj->dma_queue_lock); | ||
92 | if (list_empty(&layer->dma_queue) || | ||
93 | (layer->cur_frm != layer->next_frm)) { | ||
94 | spin_unlock(&disp_obj->dma_queue_lock); | ||
95 | return; | ||
96 | } | ||
97 | /* | ||
98 | * one field is displayed configure | ||
99 | * the next frame if it is available | ||
100 | * otherwise hold on current frame | ||
101 | * Get next from the buffer queue | ||
102 | */ | ||
103 | layer->next_frm = list_entry( | ||
104 | layer->dma_queue.next, | ||
105 | struct videobuf_buffer, | ||
106 | queue); | ||
107 | /* Remove that from the buffer queue */ | ||
108 | list_del(&layer->next_frm->queue); | ||
109 | spin_unlock(&disp_obj->dma_queue_lock); | ||
110 | /* Mark state of the frame to active */ | ||
111 | layer->next_frm->state = VIDEOBUF_ACTIVE; | ||
112 | addr = videobuf_to_dma_contig(layer->next_frm); | ||
113 | osd_device->ops.start_layer(osd_device, | ||
114 | layer->layer_info.id, | ||
115 | addr, | ||
116 | disp_obj->cbcr_ofst); | ||
117 | } | ||
118 | |||
119 | /* interrupt service routine */ | ||
120 | static irqreturn_t venc_isr(int irq, void *arg) | ||
121 | { | ||
122 | struct vpbe_display *disp_dev = (struct vpbe_display *)arg; | ||
123 | struct vpbe_layer *layer; | ||
124 | static unsigned last_event; | ||
125 | unsigned event = 0; | ||
126 | int fid; | ||
127 | int i; | ||
128 | |||
129 | if ((NULL == arg) || (NULL == disp_dev->dev[0])) | ||
130 | return IRQ_HANDLED; | ||
131 | |||
132 | if (venc_is_second_field(disp_dev)) | ||
133 | event |= VENC_SECOND_FIELD; | ||
134 | else | ||
135 | event |= VENC_FIRST_FIELD; | ||
136 | |||
137 | if (event == (last_event & ~VENC_END_OF_FRAME)) { | ||
138 | /* | ||
139 | * If the display is non-interlaced, then we need to flag the | ||
140 | * end-of-frame event at every interrupt regardless of the | ||
141 | * value of the FIDST bit. We can conclude that the display is | ||
142 | * non-interlaced if the value of the FIDST bit is unchanged | ||
143 | * from the previous interrupt. | ||
144 | */ | ||
145 | event |= VENC_END_OF_FRAME; | ||
146 | } else if (event == VENC_SECOND_FIELD) { | ||
147 | /* end-of-frame for interlaced display */ | ||
148 | event |= VENC_END_OF_FRAME; | ||
149 | } | ||
150 | last_event = event; | ||
151 | |||
152 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { | ||
153 | layer = disp_dev->dev[i]; | ||
154 | /* If streaming is started in this layer */ | ||
155 | if (!layer->started) | ||
156 | continue; | ||
157 | |||
158 | if (layer->layer_first_int) { | ||
159 | layer->layer_first_int = 0; | ||
160 | continue; | ||
161 | } | ||
162 | /* Check the field format */ | ||
163 | if ((V4L2_FIELD_NONE == layer->pix_fmt.field) && | ||
164 | (event & VENC_END_OF_FRAME)) { | ||
165 | /* Progressive mode */ | ||
166 | |||
167 | vpbe_isr_even_field(disp_dev, layer); | ||
168 | vpbe_isr_odd_field(disp_dev, layer); | ||
169 | } else { | ||
170 | /* Interlaced mode */ | ||
171 | |||
172 | layer->field_id ^= 1; | ||
173 | if (event & VENC_FIRST_FIELD) | ||
174 | fid = 0; | ||
175 | else | ||
176 | fid = 1; | ||
177 | |||
178 | /* | ||
179 | * If field id does not match with store | ||
180 | * field id | ||
181 | */ | ||
182 | if (fid != layer->field_id) { | ||
183 | /* Make them in sync */ | ||
184 | layer->field_id = fid; | ||
185 | continue; | ||
186 | } | ||
187 | /* | ||
188 | * device field id and local field id are | ||
189 | * in sync. If this is even field | ||
190 | */ | ||
191 | if (0 == fid) | ||
192 | vpbe_isr_even_field(disp_dev, layer); | ||
193 | else /* odd field */ | ||
194 | vpbe_isr_odd_field(disp_dev, layer); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | return IRQ_HANDLED; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * vpbe_buffer_prepare() | ||
203 | * This is the callback function called from videobuf_qbuf() function | ||
204 | * the buffer is prepared and user space virtual address is converted into | ||
205 | * physical address | ||
206 | */ | ||
207 | static int vpbe_buffer_prepare(struct videobuf_queue *q, | ||
208 | struct videobuf_buffer *vb, | ||
209 | enum v4l2_field field) | ||
210 | { | ||
211 | struct vpbe_fh *fh = q->priv_data; | ||
212 | struct vpbe_layer *layer = fh->layer; | ||
213 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
214 | unsigned long addr; | ||
215 | int ret; | ||
216 | |||
217 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
218 | "vpbe_buffer_prepare\n"); | ||
219 | |||
220 | /* If buffer is not initialized, initialize it */ | ||
221 | if (VIDEOBUF_NEEDS_INIT == vb->state) { | ||
222 | vb->width = layer->pix_fmt.width; | ||
223 | vb->height = layer->pix_fmt.height; | ||
224 | vb->size = layer->pix_fmt.sizeimage; | ||
225 | vb->field = field; | ||
226 | |||
227 | ret = videobuf_iolock(q, vb, NULL); | ||
228 | if (ret < 0) { | ||
229 | v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \ | ||
230 | user address\n"); | ||
231 | return -EINVAL; | ||
232 | } | ||
233 | |||
234 | addr = videobuf_to_dma_contig(vb); | ||
235 | |||
236 | if (q->streaming) { | ||
237 | if (!IS_ALIGNED(addr, 8)) { | ||
238 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
239 | "buffer_prepare:offset is \ | ||
240 | not aligned to 32 bytes\n"); | ||
241 | return -EINVAL; | ||
242 | } | ||
243 | } | ||
244 | vb->state = VIDEOBUF_PREPARED; | ||
245 | } | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | /* | ||
250 | * vpbe_buffer_setup() | ||
251 | * This function allocates memory for the buffers | ||
252 | */ | ||
253 | static int vpbe_buffer_setup(struct videobuf_queue *q, | ||
254 | unsigned int *count, | ||
255 | unsigned int *size) | ||
256 | { | ||
257 | /* Get the file handle object and layer object */ | ||
258 | struct vpbe_fh *fh = q->priv_data; | ||
259 | struct vpbe_layer *layer = fh->layer; | ||
260 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
261 | |||
262 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n"); | ||
263 | |||
264 | *size = layer->pix_fmt.sizeimage; | ||
265 | |||
266 | /* Store number of buffers allocated in numbuffer member */ | ||
267 | if (*count < VPBE_DEFAULT_NUM_BUFS) | ||
268 | *count = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS; | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | /* | ||
274 | * vpbe_buffer_queue() | ||
275 | * This function adds the buffer to DMA queue | ||
276 | */ | ||
277 | static void vpbe_buffer_queue(struct videobuf_queue *q, | ||
278 | struct videobuf_buffer *vb) | ||
279 | { | ||
280 | /* Get the file handle object and layer object */ | ||
281 | struct vpbe_fh *fh = q->priv_data; | ||
282 | struct vpbe_layer *layer = fh->layer; | ||
283 | struct vpbe_display *disp = fh->disp_dev; | ||
284 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
285 | unsigned long flags; | ||
286 | |||
287 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
288 | "vpbe_buffer_queue\n"); | ||
289 | |||
290 | /* add the buffer to the DMA queue */ | ||
291 | spin_lock_irqsave(&disp->dma_queue_lock, flags); | ||
292 | list_add_tail(&vb->queue, &layer->dma_queue); | ||
293 | spin_unlock_irqrestore(&disp->dma_queue_lock, flags); | ||
294 | /* Change state of the buffer */ | ||
295 | vb->state = VIDEOBUF_QUEUED; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * vpbe_buffer_release() | ||
300 | * This function is called from the videobuf layer to free memory allocated to | ||
301 | * the buffers | ||
302 | */ | ||
303 | static void vpbe_buffer_release(struct videobuf_queue *q, | ||
304 | struct videobuf_buffer *vb) | ||
305 | { | ||
306 | /* Get the file handle object and layer object */ | ||
307 | struct vpbe_fh *fh = q->priv_data; | ||
308 | struct vpbe_layer *layer = fh->layer; | ||
309 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
310 | |||
311 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
312 | "vpbe_buffer_release\n"); | ||
313 | |||
314 | if (V4L2_MEMORY_USERPTR != layer->memory) | ||
315 | videobuf_dma_contig_free(q, vb); | ||
316 | |||
317 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
318 | } | ||
319 | |||
320 | static struct videobuf_queue_ops video_qops = { | ||
321 | .buf_setup = vpbe_buffer_setup, | ||
322 | .buf_prepare = vpbe_buffer_prepare, | ||
323 | .buf_queue = vpbe_buffer_queue, | ||
324 | .buf_release = vpbe_buffer_release, | ||
325 | }; | ||
326 | |||
327 | static | ||
328 | struct vpbe_layer* | ||
329 | _vpbe_display_get_other_win_layer(struct vpbe_display *disp_dev, | ||
330 | struct vpbe_layer *layer) | ||
331 | { | ||
332 | enum vpbe_display_device_id thiswin, otherwin; | ||
333 | thiswin = layer->device_id; | ||
334 | |||
335 | otherwin = (thiswin == VPBE_DISPLAY_DEVICE_0) ? | ||
336 | VPBE_DISPLAY_DEVICE_1 : VPBE_DISPLAY_DEVICE_0; | ||
337 | return disp_dev->dev[otherwin]; | ||
338 | } | ||
339 | |||
340 | static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev, | ||
341 | struct vpbe_layer *layer) | ||
342 | { | ||
343 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
344 | struct osd_state *osd_device = disp_dev->osd_device; | ||
345 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
346 | unsigned long addr; | ||
347 | int ret; | ||
348 | |||
349 | addr = videobuf_to_dma_contig(layer->cur_frm); | ||
350 | /* Set address in the display registers */ | ||
351 | osd_device->ops.start_layer(osd_device, | ||
352 | layer->layer_info.id, | ||
353 | addr, | ||
354 | disp_dev->cbcr_ofst); | ||
355 | |||
356 | ret = osd_device->ops.enable_layer(osd_device, | ||
357 | layer->layer_info.id, 0); | ||
358 | if (ret < 0) { | ||
359 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
360 | "Error in enabling osd window layer 0\n"); | ||
361 | return -1; | ||
362 | } | ||
363 | |||
364 | /* Enable the window */ | ||
365 | layer->layer_info.enable = 1; | ||
366 | if (cfg->pixfmt == PIXFMT_NV12) { | ||
367 | struct vpbe_layer *otherlayer = | ||
368 | _vpbe_display_get_other_win_layer(disp_dev, layer); | ||
369 | |||
370 | ret = osd_device->ops.enable_layer(osd_device, | ||
371 | otherlayer->layer_info.id, 1); | ||
372 | if (ret < 0) { | ||
373 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
374 | "Error in enabling osd window layer 1\n"); | ||
375 | return -1; | ||
376 | } | ||
377 | otherlayer->layer_info.enable = 1; | ||
378 | } | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static void | ||
383 | vpbe_disp_calculate_scale_factor(struct vpbe_display *disp_dev, | ||
384 | struct vpbe_layer *layer, | ||
385 | int expected_xsize, int expected_ysize) | ||
386 | { | ||
387 | struct display_layer_info *layer_info = &layer->layer_info; | ||
388 | struct v4l2_pix_format *pixfmt = &layer->pix_fmt; | ||
389 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
390 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
391 | int calculated_xsize; | ||
392 | int h_exp = 0; | ||
393 | int v_exp = 0; | ||
394 | int h_scale; | ||
395 | int v_scale; | ||
396 | |||
397 | v4l2_std_id standard_id = vpbe_dev->current_timings.timings.std_id; | ||
398 | |||
399 | /* | ||
400 | * Application initially set the image format. Current display | ||
401 | * size is obtained from the vpbe display controller. expected_xsize | ||
402 | * and expected_ysize are set through S_CROP ioctl. Based on this, | ||
403 | * driver will calculate the scale factors for vertical and | ||
404 | * horizontal direction so that the image is displayed scaled | ||
405 | * and expanded. Application uses expansion to display the image | ||
406 | * in a square pixel. Otherwise it is displayed using displays | ||
407 | * pixel aspect ratio.It is expected that application chooses | ||
408 | * the crop coordinates for cropped or scaled display. if crop | ||
409 | * size is less than the image size, it is displayed cropped or | ||
410 | * it is displayed scaled and/or expanded. | ||
411 | * | ||
412 | * to begin with, set the crop window same as expected. Later we | ||
413 | * will override with scaled window size | ||
414 | */ | ||
415 | |||
416 | cfg->xsize = pixfmt->width; | ||
417 | cfg->ysize = pixfmt->height; | ||
418 | layer_info->h_zoom = ZOOM_X1; /* no horizontal zoom */ | ||
419 | layer_info->v_zoom = ZOOM_X1; /* no horizontal zoom */ | ||
420 | layer_info->h_exp = H_EXP_OFF; /* no horizontal zoom */ | ||
421 | layer_info->v_exp = V_EXP_OFF; /* no horizontal zoom */ | ||
422 | |||
423 | if (pixfmt->width < expected_xsize) { | ||
424 | h_scale = vpbe_dev->current_timings.xres / pixfmt->width; | ||
425 | if (h_scale < 2) | ||
426 | h_scale = 1; | ||
427 | else if (h_scale >= 4) | ||
428 | h_scale = 4; | ||
429 | else | ||
430 | h_scale = 2; | ||
431 | cfg->xsize *= h_scale; | ||
432 | if (cfg->xsize < expected_xsize) { | ||
433 | if ((standard_id & V4L2_STD_525_60) || | ||
434 | (standard_id & V4L2_STD_625_50)) { | ||
435 | calculated_xsize = (cfg->xsize * | ||
436 | VPBE_DISPLAY_H_EXP_RATIO_N) / | ||
437 | VPBE_DISPLAY_H_EXP_RATIO_D; | ||
438 | if (calculated_xsize <= expected_xsize) { | ||
439 | h_exp = 1; | ||
440 | cfg->xsize = calculated_xsize; | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | if (h_scale == 2) | ||
445 | layer_info->h_zoom = ZOOM_X2; | ||
446 | else if (h_scale == 4) | ||
447 | layer_info->h_zoom = ZOOM_X4; | ||
448 | if (h_exp) | ||
449 | layer_info->h_exp = H_EXP_9_OVER_8; | ||
450 | } else { | ||
451 | /* no scaling, only cropping. Set display area to crop area */ | ||
452 | cfg->xsize = expected_xsize; | ||
453 | } | ||
454 | |||
455 | if (pixfmt->height < expected_ysize) { | ||
456 | v_scale = expected_ysize / pixfmt->height; | ||
457 | if (v_scale < 2) | ||
458 | v_scale = 1; | ||
459 | else if (v_scale >= 4) | ||
460 | v_scale = 4; | ||
461 | else | ||
462 | v_scale = 2; | ||
463 | cfg->ysize *= v_scale; | ||
464 | if (cfg->ysize < expected_ysize) { | ||
465 | if ((standard_id & V4L2_STD_625_50)) { | ||
466 | calculated_xsize = (cfg->ysize * | ||
467 | VPBE_DISPLAY_V_EXP_RATIO_N) / | ||
468 | VPBE_DISPLAY_V_EXP_RATIO_D; | ||
469 | if (calculated_xsize <= expected_ysize) { | ||
470 | v_exp = 1; | ||
471 | cfg->ysize = calculated_xsize; | ||
472 | } | ||
473 | } | ||
474 | } | ||
475 | if (v_scale == 2) | ||
476 | layer_info->v_zoom = ZOOM_X2; | ||
477 | else if (v_scale == 4) | ||
478 | layer_info->v_zoom = ZOOM_X4; | ||
479 | if (v_exp) | ||
480 | layer_info->h_exp = V_EXP_6_OVER_5; | ||
481 | } else { | ||
482 | /* no scaling, only cropping. Set display area to crop area */ | ||
483 | cfg->ysize = expected_ysize; | ||
484 | } | ||
485 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
486 | "crop display xsize = %d, ysize = %d\n", | ||
487 | cfg->xsize, cfg->ysize); | ||
488 | } | ||
489 | |||
490 | static void vpbe_disp_adj_position(struct vpbe_display *disp_dev, | ||
491 | struct vpbe_layer *layer, | ||
492 | int top, int left) | ||
493 | { | ||
494 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
495 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
496 | |||
497 | cfg->xpos = min((unsigned int)left, | ||
498 | vpbe_dev->current_timings.xres - cfg->xsize); | ||
499 | cfg->ypos = min((unsigned int)top, | ||
500 | vpbe_dev->current_timings.yres - cfg->ysize); | ||
501 | |||
502 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
503 | "new xpos = %d, ypos = %d\n", | ||
504 | cfg->xpos, cfg->ypos); | ||
505 | } | ||
506 | |||
507 | static void vpbe_disp_check_window_params(struct vpbe_display *disp_dev, | ||
508 | struct v4l2_rect *c) | ||
509 | { | ||
510 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
511 | |||
512 | if ((c->width == 0) || | ||
513 | ((c->width + c->left) > vpbe_dev->current_timings.xres)) | ||
514 | c->width = vpbe_dev->current_timings.xres - c->left; | ||
515 | |||
516 | if ((c->height == 0) || ((c->height + c->top) > | ||
517 | vpbe_dev->current_timings.yres)) | ||
518 | c->height = vpbe_dev->current_timings.yres - c->top; | ||
519 | |||
520 | /* window height must be even for interlaced display */ | ||
521 | if (vpbe_dev->current_timings.interlaced) | ||
522 | c->height &= (~0x01); | ||
523 | |||
524 | } | ||
525 | |||
526 | /** | ||
527 | * vpbe_try_format() | ||
528 | * If user application provides width and height, and have bytesperline set | ||
529 | * to zero, driver calculates bytesperline and sizeimage based on hardware | ||
530 | * limits. | ||
531 | */ | ||
532 | static int vpbe_try_format(struct vpbe_display *disp_dev, | ||
533 | struct v4l2_pix_format *pixfmt, int check) | ||
534 | { | ||
535 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
536 | int min_height = 1; | ||
537 | int min_width = 32; | ||
538 | int max_height; | ||
539 | int max_width; | ||
540 | int bpp; | ||
541 | |||
542 | if ((pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) && | ||
543 | (pixfmt->pixelformat != V4L2_PIX_FMT_NV12)) | ||
544 | /* choose default as V4L2_PIX_FMT_UYVY */ | ||
545 | pixfmt->pixelformat = V4L2_PIX_FMT_UYVY; | ||
546 | |||
547 | /* Check the field format */ | ||
548 | if ((pixfmt->field != V4L2_FIELD_INTERLACED) && | ||
549 | (pixfmt->field != V4L2_FIELD_NONE)) { | ||
550 | if (vpbe_dev->current_timings.interlaced) | ||
551 | pixfmt->field = V4L2_FIELD_INTERLACED; | ||
552 | else | ||
553 | pixfmt->field = V4L2_FIELD_NONE; | ||
554 | } | ||
555 | |||
556 | if (pixfmt->field == V4L2_FIELD_INTERLACED) | ||
557 | min_height = 2; | ||
558 | |||
559 | if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) | ||
560 | bpp = 1; | ||
561 | else | ||
562 | bpp = 2; | ||
563 | |||
564 | max_width = vpbe_dev->current_timings.xres; | ||
565 | max_height = vpbe_dev->current_timings.yres; | ||
566 | |||
567 | min_width /= bpp; | ||
568 | |||
569 | if (!pixfmt->width || (pixfmt->width < min_width) || | ||
570 | (pixfmt->width > max_width)) { | ||
571 | pixfmt->width = vpbe_dev->current_timings.xres; | ||
572 | } | ||
573 | |||
574 | if (!pixfmt->height || (pixfmt->height < min_height) || | ||
575 | (pixfmt->height > max_height)) { | ||
576 | pixfmt->height = vpbe_dev->current_timings.yres; | ||
577 | } | ||
578 | |||
579 | if (pixfmt->bytesperline < (pixfmt->width * bpp)) | ||
580 | pixfmt->bytesperline = pixfmt->width * bpp; | ||
581 | |||
582 | /* Make the bytesperline 32 byte aligned */ | ||
583 | pixfmt->bytesperline = ((pixfmt->width * bpp + 31) & ~31); | ||
584 | |||
585 | if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12) | ||
586 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height + | ||
587 | (pixfmt->bytesperline * pixfmt->height >> 1); | ||
588 | else | ||
589 | pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; | ||
590 | |||
591 | return 0; | ||
592 | } | ||
593 | |||
594 | static int vpbe_display_g_priority(struct file *file, void *priv, | ||
595 | enum v4l2_priority *p) | ||
596 | { | ||
597 | struct vpbe_fh *fh = file->private_data; | ||
598 | struct vpbe_layer *layer = fh->layer; | ||
599 | |||
600 | *p = v4l2_prio_max(&layer->prio); | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | static int vpbe_display_s_priority(struct file *file, void *priv, | ||
606 | enum v4l2_priority p) | ||
607 | { | ||
608 | struct vpbe_fh *fh = file->private_data; | ||
609 | struct vpbe_layer *layer = fh->layer; | ||
610 | int ret; | ||
611 | |||
612 | ret = v4l2_prio_change(&layer->prio, &fh->prio, p); | ||
613 | |||
614 | return ret; | ||
615 | } | ||
616 | |||
617 | static int vpbe_display_querycap(struct file *file, void *priv, | ||
618 | struct v4l2_capability *cap) | ||
619 | { | ||
620 | struct vpbe_fh *fh = file->private_data; | ||
621 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
622 | |||
623 | cap->version = VPBE_DISPLAY_VERSION_CODE; | ||
624 | cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; | ||
625 | strlcpy(cap->driver, VPBE_DISPLAY_DRIVER, sizeof(cap->driver)); | ||
626 | strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info)); | ||
627 | strlcpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card)); | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | static int vpbe_display_s_crop(struct file *file, void *priv, | ||
633 | struct v4l2_crop *crop) | ||
634 | { | ||
635 | struct vpbe_fh *fh = file->private_data; | ||
636 | struct vpbe_layer *layer = fh->layer; | ||
637 | struct vpbe_display *disp_dev = fh->disp_dev; | ||
638 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
639 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
640 | struct osd_state *osd_device = disp_dev->osd_device; | ||
641 | struct v4l2_rect *rect = &crop->c; | ||
642 | int ret; | ||
643 | |||
644 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
645 | "VIDIOC_S_CROP, layer id = %d\n", layer->device_id); | ||
646 | |||
647 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
648 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); | ||
649 | return -EINVAL; | ||
650 | } | ||
651 | |||
652 | if (rect->top < 0) | ||
653 | rect->top = 0; | ||
654 | if (rect->left < 0) | ||
655 | rect->left = 0; | ||
656 | |||
657 | vpbe_disp_check_window_params(disp_dev, rect); | ||
658 | |||
659 | osd_device->ops.get_layer_config(osd_device, | ||
660 | layer->layer_info.id, cfg); | ||
661 | |||
662 | vpbe_disp_calculate_scale_factor(disp_dev, layer, | ||
663 | rect->width, | ||
664 | rect->height); | ||
665 | vpbe_disp_adj_position(disp_dev, layer, rect->top, | ||
666 | rect->left); | ||
667 | ret = osd_device->ops.set_layer_config(osd_device, | ||
668 | layer->layer_info.id, cfg); | ||
669 | if (ret < 0) { | ||
670 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
671 | "Error in set layer config:\n"); | ||
672 | return -EINVAL; | ||
673 | } | ||
674 | |||
675 | /* apply zooming and h or v expansion */ | ||
676 | osd_device->ops.set_zoom(osd_device, | ||
677 | layer->layer_info.id, | ||
678 | layer->layer_info.h_zoom, | ||
679 | layer->layer_info.v_zoom); | ||
680 | ret = osd_device->ops.set_vid_expansion(osd_device, | ||
681 | layer->layer_info.h_exp, | ||
682 | layer->layer_info.v_exp); | ||
683 | if (ret < 0) { | ||
684 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
685 | "Error in set vid expansion:\n"); | ||
686 | return -EINVAL; | ||
687 | } | ||
688 | |||
689 | if ((layer->layer_info.h_zoom != ZOOM_X1) || | ||
690 | (layer->layer_info.v_zoom != ZOOM_X1) || | ||
691 | (layer->layer_info.h_exp != H_EXP_OFF) || | ||
692 | (layer->layer_info.v_exp != V_EXP_OFF)) | ||
693 | /* Enable expansion filter */ | ||
694 | osd_device->ops.set_interpolation_filter(osd_device, 1); | ||
695 | else | ||
696 | osd_device->ops.set_interpolation_filter(osd_device, 0); | ||
697 | |||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static int vpbe_display_g_crop(struct file *file, void *priv, | ||
702 | struct v4l2_crop *crop) | ||
703 | { | ||
704 | struct vpbe_fh *fh = file->private_data; | ||
705 | struct vpbe_layer *layer = fh->layer; | ||
706 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
707 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
708 | struct osd_state *osd_device = fh->disp_dev->osd_device; | ||
709 | struct v4l2_rect *rect = &crop->c; | ||
710 | int ret; | ||
711 | |||
712 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
713 | "VIDIOC_G_CROP, layer id = %d\n", | ||
714 | layer->device_id); | ||
715 | |||
716 | if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { | ||
717 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buf type\n"); | ||
718 | ret = -EINVAL; | ||
719 | } | ||
720 | osd_device->ops.get_layer_config(osd_device, | ||
721 | layer->layer_info.id, cfg); | ||
722 | rect->top = cfg->ypos; | ||
723 | rect->left = cfg->xpos; | ||
724 | rect->width = cfg->xsize; | ||
725 | rect->height = cfg->ysize; | ||
726 | |||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | static int vpbe_display_cropcap(struct file *file, void *priv, | ||
731 | struct v4l2_cropcap *cropcap) | ||
732 | { | ||
733 | struct vpbe_fh *fh = file->private_data; | ||
734 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
735 | |||
736 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n"); | ||
737 | |||
738 | cropcap->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
739 | cropcap->bounds.left = 0; | ||
740 | cropcap->bounds.top = 0; | ||
741 | cropcap->bounds.width = vpbe_dev->current_timings.xres; | ||
742 | cropcap->bounds.height = vpbe_dev->current_timings.yres; | ||
743 | cropcap->pixelaspect = vpbe_dev->current_timings.aspect; | ||
744 | cropcap->defrect = cropcap->bounds; | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | static int vpbe_display_g_fmt(struct file *file, void *priv, | ||
749 | struct v4l2_format *fmt) | ||
750 | { | ||
751 | struct vpbe_fh *fh = file->private_data; | ||
752 | struct vpbe_layer *layer = fh->layer; | ||
753 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
754 | |||
755 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
756 | "VIDIOC_G_FMT, layer id = %d\n", | ||
757 | layer->device_id); | ||
758 | |||
759 | /* If buffer type is video output */ | ||
760 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { | ||
761 | v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); | ||
762 | return -EINVAL; | ||
763 | } | ||
764 | /* Fill in the information about format */ | ||
765 | fmt->fmt.pix = layer->pix_fmt; | ||
766 | |||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | static int vpbe_display_enum_fmt(struct file *file, void *priv, | ||
771 | struct v4l2_fmtdesc *fmt) | ||
772 | { | ||
773 | struct vpbe_fh *fh = file->private_data; | ||
774 | struct vpbe_layer *layer = fh->layer; | ||
775 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
776 | unsigned int index = 0; | ||
777 | |||
778 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
779 | "VIDIOC_ENUM_FMT, layer id = %d\n", | ||
780 | layer->device_id); | ||
781 | if (fmt->index > 1) { | ||
782 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid format index\n"); | ||
783 | return -EINVAL; | ||
784 | } | ||
785 | |||
786 | /* Fill in the information about format */ | ||
787 | index = fmt->index; | ||
788 | memset(fmt, 0, sizeof(*fmt)); | ||
789 | fmt->index = index; | ||
790 | fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
791 | if (index == 0) { | ||
792 | strcpy(fmt->description, "YUV 4:2:2 - UYVY"); | ||
793 | fmt->pixelformat = V4L2_PIX_FMT_UYVY; | ||
794 | } else { | ||
795 | strcpy(fmt->description, "Y/CbCr 4:2:0"); | ||
796 | fmt->pixelformat = V4L2_PIX_FMT_NV12; | ||
797 | } | ||
798 | |||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | static int vpbe_display_s_fmt(struct file *file, void *priv, | ||
803 | struct v4l2_format *fmt) | ||
804 | { | ||
805 | struct vpbe_fh *fh = file->private_data; | ||
806 | struct vpbe_layer *layer = fh->layer; | ||
807 | struct vpbe_display *disp_dev = fh->disp_dev; | ||
808 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
809 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
810 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
811 | struct osd_state *osd_device = disp_dev->osd_device; | ||
812 | int ret; | ||
813 | |||
814 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
815 | "VIDIOC_S_FMT, layer id = %d\n", | ||
816 | layer->device_id); | ||
817 | |||
818 | /* If streaming is started, return error */ | ||
819 | if (layer->started) { | ||
820 | v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); | ||
821 | return -EBUSY; | ||
822 | } | ||
823 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { | ||
824 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n"); | ||
825 | return -EINVAL; | ||
826 | } | ||
827 | /* Check for valid pixel format */ | ||
828 | ret = vpbe_try_format(disp_dev, pixfmt, 1); | ||
829 | if (ret) | ||
830 | return ret; | ||
831 | |||
832 | /* YUV420 is requested, check availability of the | ||
833 | other video window */ | ||
834 | |||
835 | layer->pix_fmt = *pixfmt; | ||
836 | |||
837 | /* Get osd layer config */ | ||
838 | osd_device->ops.get_layer_config(osd_device, | ||
839 | layer->layer_info.id, cfg); | ||
840 | /* Store the pixel format in the layer object */ | ||
841 | cfg->xsize = pixfmt->width; | ||
842 | cfg->ysize = pixfmt->height; | ||
843 | cfg->line_length = pixfmt->bytesperline; | ||
844 | cfg->ypos = 0; | ||
845 | cfg->xpos = 0; | ||
846 | cfg->interlaced = vpbe_dev->current_timings.interlaced; | ||
847 | |||
848 | if (V4L2_PIX_FMT_UYVY == pixfmt->pixelformat) | ||
849 | cfg->pixfmt = PIXFMT_YCbCrI; | ||
850 | |||
851 | /* Change of the default pixel format for both video windows */ | ||
852 | if (V4L2_PIX_FMT_NV12 == pixfmt->pixelformat) { | ||
853 | struct vpbe_layer *otherlayer; | ||
854 | cfg->pixfmt = PIXFMT_NV12; | ||
855 | otherlayer = _vpbe_display_get_other_win_layer(disp_dev, | ||
856 | layer); | ||
857 | otherlayer->layer_info.config.pixfmt = PIXFMT_NV12; | ||
858 | } | ||
859 | |||
860 | /* Set the layer config in the osd window */ | ||
861 | ret = osd_device->ops.set_layer_config(osd_device, | ||
862 | layer->layer_info.id, cfg); | ||
863 | if (ret < 0) { | ||
864 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
865 | "Error in S_FMT params:\n"); | ||
866 | return -EINVAL; | ||
867 | } | ||
868 | |||
869 | /* Readback and fill the local copy of current pix format */ | ||
870 | osd_device->ops.get_layer_config(osd_device, | ||
871 | layer->layer_info.id, cfg); | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int vpbe_display_try_fmt(struct file *file, void *priv, | ||
877 | struct v4l2_format *fmt) | ||
878 | { | ||
879 | struct vpbe_fh *fh = file->private_data; | ||
880 | struct vpbe_display *disp_dev = fh->disp_dev; | ||
881 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
882 | struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; | ||
883 | |||
884 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n"); | ||
885 | |||
886 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) { | ||
887 | v4l2_err(&vpbe_dev->v4l2_dev, "invalid type\n"); | ||
888 | return -EINVAL; | ||
889 | } | ||
890 | |||
891 | /* Check for valid field format */ | ||
892 | return vpbe_try_format(disp_dev, pixfmt, 0); | ||
893 | |||
894 | } | ||
895 | |||
896 | /** | ||
897 | * vpbe_display_s_std - Set the given standard in the encoder | ||
898 | * | ||
899 | * Sets the standard if supported by the current encoder. Return the status. | ||
900 | * 0 - success & -EINVAL on error | ||
901 | */ | ||
902 | static int vpbe_display_s_std(struct file *file, void *priv, | ||
903 | v4l2_std_id *std_id) | ||
904 | { | ||
905 | struct vpbe_fh *fh = priv; | ||
906 | struct vpbe_layer *layer = fh->layer; | ||
907 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
908 | int ret; | ||
909 | |||
910 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n"); | ||
911 | |||
912 | /* If streaming is started, return error */ | ||
913 | if (layer->started) { | ||
914 | v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); | ||
915 | return -EBUSY; | ||
916 | } | ||
917 | if (NULL != vpbe_dev->ops.s_std) { | ||
918 | ret = vpbe_dev->ops.s_std(vpbe_dev, std_id); | ||
919 | if (ret) { | ||
920 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
921 | "Failed to set standard for sub devices\n"); | ||
922 | return -EINVAL; | ||
923 | } | ||
924 | } else { | ||
925 | return -EINVAL; | ||
926 | } | ||
927 | |||
928 | return 0; | ||
929 | } | ||
930 | |||
931 | /** | ||
932 | * vpbe_display_g_std - Get the standard in the current encoder | ||
933 | * | ||
934 | * Get the standard in the current encoder. Return the status. 0 - success | ||
935 | * -EINVAL on error | ||
936 | */ | ||
937 | static int vpbe_display_g_std(struct file *file, void *priv, | ||
938 | v4l2_std_id *std_id) | ||
939 | { | ||
940 | struct vpbe_fh *fh = priv; | ||
941 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
942 | |||
943 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n"); | ||
944 | |||
945 | /* Get the standard from the current encoder */ | ||
946 | if (vpbe_dev->current_timings.timings_type & VPBE_ENC_STD) { | ||
947 | *std_id = vpbe_dev->current_timings.timings.std_id; | ||
948 | return 0; | ||
949 | } | ||
950 | |||
951 | return -EINVAL; | ||
952 | } | ||
953 | |||
954 | /** | ||
955 | * vpbe_display_enum_output - enumerate outputs | ||
956 | * | ||
957 | * Enumerates the outputs available at the vpbe display | ||
958 | * returns the status, -EINVAL if end of output list | ||
959 | */ | ||
960 | static int vpbe_display_enum_output(struct file *file, void *priv, | ||
961 | struct v4l2_output *output) | ||
962 | { | ||
963 | struct vpbe_fh *fh = priv; | ||
964 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
965 | int ret; | ||
966 | |||
967 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n"); | ||
968 | |||
969 | /* Enumerate outputs */ | ||
970 | |||
971 | if (NULL == vpbe_dev->ops.enum_outputs) | ||
972 | return -EINVAL; | ||
973 | |||
974 | ret = vpbe_dev->ops.enum_outputs(vpbe_dev, output); | ||
975 | if (ret) { | ||
976 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
977 | "Failed to enumerate outputs\n"); | ||
978 | return -EINVAL; | ||
979 | } | ||
980 | |||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | /** | ||
985 | * vpbe_display_s_output - Set output to | ||
986 | * the output specified by the index | ||
987 | */ | ||
988 | static int vpbe_display_s_output(struct file *file, void *priv, | ||
989 | unsigned int i) | ||
990 | { | ||
991 | struct vpbe_fh *fh = priv; | ||
992 | struct vpbe_layer *layer = fh->layer; | ||
993 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
994 | int ret; | ||
995 | |||
996 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n"); | ||
997 | /* If streaming is started, return error */ | ||
998 | if (layer->started) { | ||
999 | v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); | ||
1000 | return -EBUSY; | ||
1001 | } | ||
1002 | if (NULL == vpbe_dev->ops.set_output) | ||
1003 | return -EINVAL; | ||
1004 | |||
1005 | ret = vpbe_dev->ops.set_output(vpbe_dev, i); | ||
1006 | if (ret) { | ||
1007 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1008 | "Failed to set output for sub devices\n"); | ||
1009 | return -EINVAL; | ||
1010 | } | ||
1011 | |||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
1015 | /** | ||
1016 | * vpbe_display_g_output - Get output from subdevice | ||
1017 | * for a given by the index | ||
1018 | */ | ||
1019 | static int vpbe_display_g_output(struct file *file, void *priv, | ||
1020 | unsigned int *i) | ||
1021 | { | ||
1022 | struct vpbe_fh *fh = priv; | ||
1023 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1024 | |||
1025 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n"); | ||
1026 | /* Get the standard from the current encoder */ | ||
1027 | *i = vpbe_dev->current_out_index; | ||
1028 | |||
1029 | return 0; | ||
1030 | } | ||
1031 | |||
1032 | /** | ||
1033 | * vpbe_display_enum_dv_presets - Enumerate the dv presets | ||
1034 | * | ||
1035 | * enum the preset in the current encoder. Return the status. 0 - success | ||
1036 | * -EINVAL on error | ||
1037 | */ | ||
1038 | static int | ||
1039 | vpbe_display_enum_dv_presets(struct file *file, void *priv, | ||
1040 | struct v4l2_dv_enum_preset *preset) | ||
1041 | { | ||
1042 | struct vpbe_fh *fh = priv; | ||
1043 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1044 | int ret; | ||
1045 | |||
1046 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_PRESETS\n"); | ||
1047 | |||
1048 | /* Enumerate outputs */ | ||
1049 | if (NULL == vpbe_dev->ops.enum_dv_presets) | ||
1050 | return -EINVAL; | ||
1051 | |||
1052 | ret = vpbe_dev->ops.enum_dv_presets(vpbe_dev, preset); | ||
1053 | if (ret) { | ||
1054 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1055 | "Failed to enumerate dv presets info\n"); | ||
1056 | return -EINVAL; | ||
1057 | } | ||
1058 | |||
1059 | return 0; | ||
1060 | } | ||
1061 | |||
1062 | /** | ||
1063 | * vpbe_display_s_dv_preset - Set the dv presets | ||
1064 | * | ||
1065 | * Set the preset in the current encoder. Return the status. 0 - success | ||
1066 | * -EINVAL on error | ||
1067 | */ | ||
1068 | static int | ||
1069 | vpbe_display_s_dv_preset(struct file *file, void *priv, | ||
1070 | struct v4l2_dv_preset *preset) | ||
1071 | { | ||
1072 | struct vpbe_fh *fh = priv; | ||
1073 | struct vpbe_layer *layer = fh->layer; | ||
1074 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1075 | int ret; | ||
1076 | |||
1077 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_PRESETS\n"); | ||
1078 | |||
1079 | |||
1080 | /* If streaming is started, return error */ | ||
1081 | if (layer->started) { | ||
1082 | v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n"); | ||
1083 | return -EBUSY; | ||
1084 | } | ||
1085 | |||
1086 | /* Set the given standard in the encoder */ | ||
1087 | if (NULL != vpbe_dev->ops.s_dv_preset) | ||
1088 | return -EINVAL; | ||
1089 | |||
1090 | ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset); | ||
1091 | if (ret) { | ||
1092 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1093 | "Failed to set the dv presets info\n"); | ||
1094 | return -EINVAL; | ||
1095 | } | ||
1096 | /* set the current norm to zero to be consistent. If STD is used | ||
1097 | * v4l2 layer will set the norm properly on successful s_std call | ||
1098 | */ | ||
1099 | layer->video_dev.current_norm = 0; | ||
1100 | |||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | /** | ||
1105 | * vpbe_display_g_dv_preset - Set the dv presets | ||
1106 | * | ||
1107 | * Get the preset in the current encoder. Return the status. 0 - success | ||
1108 | * -EINVAL on error | ||
1109 | */ | ||
1110 | static int | ||
1111 | vpbe_display_g_dv_preset(struct file *file, void *priv, | ||
1112 | struct v4l2_dv_preset *dv_preset) | ||
1113 | { | ||
1114 | struct vpbe_fh *fh = priv; | ||
1115 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1116 | |||
1117 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_PRESETS\n"); | ||
1118 | |||
1119 | /* Get the given standard in the encoder */ | ||
1120 | |||
1121 | if (vpbe_dev->current_timings.timings_type & | ||
1122 | VPBE_ENC_DV_PRESET) { | ||
1123 | dv_preset->preset = | ||
1124 | vpbe_dev->current_timings.timings.dv_preset; | ||
1125 | } else { | ||
1126 | return -EINVAL; | ||
1127 | } | ||
1128 | |||
1129 | return 0; | ||
1130 | } | ||
1131 | |||
1132 | static int vpbe_display_streamoff(struct file *file, void *priv, | ||
1133 | enum v4l2_buf_type buf_type) | ||
1134 | { | ||
1135 | struct vpbe_fh *fh = file->private_data; | ||
1136 | struct vpbe_layer *layer = fh->layer; | ||
1137 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1138 | struct osd_state *osd_device = fh->disp_dev->osd_device; | ||
1139 | int ret; | ||
1140 | |||
1141 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1142 | "VIDIOC_STREAMOFF,layer id = %d\n", | ||
1143 | layer->device_id); | ||
1144 | |||
1145 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { | ||
1146 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1147 | return -EINVAL; | ||
1148 | } | ||
1149 | |||
1150 | /* If io is allowed for this file handle, return error */ | ||
1151 | if (!fh->io_allowed) { | ||
1152 | v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); | ||
1153 | return -EACCES; | ||
1154 | } | ||
1155 | |||
1156 | /* If streaming is not started, return error */ | ||
1157 | if (!layer->started) { | ||
1158 | v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer" | ||
1159 | " id = %d\n", layer->device_id); | ||
1160 | return -EINVAL; | ||
1161 | } | ||
1162 | |||
1163 | osd_device->ops.disable_layer(osd_device, | ||
1164 | layer->layer_info.id); | ||
1165 | layer->started = 0; | ||
1166 | ret = videobuf_streamoff(&layer->buffer_queue); | ||
1167 | |||
1168 | return ret; | ||
1169 | } | ||
1170 | |||
1171 | static int vpbe_display_streamon(struct file *file, void *priv, | ||
1172 | enum v4l2_buf_type buf_type) | ||
1173 | { | ||
1174 | struct vpbe_fh *fh = file->private_data; | ||
1175 | struct vpbe_layer *layer = fh->layer; | ||
1176 | struct vpbe_display *disp_dev = fh->disp_dev; | ||
1177 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1178 | struct osd_state *osd_device = disp_dev->osd_device; | ||
1179 | int ret; | ||
1180 | |||
1181 | osd_device->ops.disable_layer(osd_device, | ||
1182 | layer->layer_info.id); | ||
1183 | |||
1184 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n", | ||
1185 | layer->device_id); | ||
1186 | |||
1187 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) { | ||
1188 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1189 | return -EINVAL; | ||
1190 | } | ||
1191 | |||
1192 | /* If file handle is not allowed IO, return error */ | ||
1193 | if (!fh->io_allowed) { | ||
1194 | v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); | ||
1195 | return -EACCES; | ||
1196 | } | ||
1197 | /* If Streaming is already started, return error */ | ||
1198 | if (layer->started) { | ||
1199 | v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n"); | ||
1200 | return -EBUSY; | ||
1201 | } | ||
1202 | |||
1203 | /* | ||
1204 | * Call videobuf_streamon to start streaming | ||
1205 | * in videobuf | ||
1206 | */ | ||
1207 | ret = videobuf_streamon(&layer->buffer_queue); | ||
1208 | if (ret) { | ||
1209 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1210 | "error in videobuf_streamon\n"); | ||
1211 | return ret; | ||
1212 | } | ||
1213 | /* If buffer queue is empty, return error */ | ||
1214 | if (list_empty(&layer->dma_queue)) { | ||
1215 | v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n"); | ||
1216 | goto streamoff; | ||
1217 | } | ||
1218 | /* Get the next frame from the buffer queue */ | ||
1219 | layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, | ||
1220 | struct videobuf_buffer, queue); | ||
1221 | /* Remove buffer from the buffer queue */ | ||
1222 | list_del(&layer->cur_frm->queue); | ||
1223 | /* Mark state of the current frame to active */ | ||
1224 | layer->cur_frm->state = VIDEOBUF_ACTIVE; | ||
1225 | /* Initialize field_id and started member */ | ||
1226 | layer->field_id = 0; | ||
1227 | |||
1228 | /* Set parameters in OSD and VENC */ | ||
1229 | ret = vpbe_set_osd_display_params(disp_dev, layer); | ||
1230 | if (ret < 0) | ||
1231 | goto streamoff; | ||
1232 | |||
1233 | /* | ||
1234 | * if request format is yuv420 semiplanar, need to | ||
1235 | * enable both video windows | ||
1236 | */ | ||
1237 | layer->started = 1; | ||
1238 | |||
1239 | layer->layer_first_int = 1; | ||
1240 | |||
1241 | return ret; | ||
1242 | streamoff: | ||
1243 | ret = videobuf_streamoff(&layer->buffer_queue); | ||
1244 | return ret; | ||
1245 | } | ||
1246 | |||
1247 | static int vpbe_display_dqbuf(struct file *file, void *priv, | ||
1248 | struct v4l2_buffer *buf) | ||
1249 | { | ||
1250 | struct vpbe_fh *fh = file->private_data; | ||
1251 | struct vpbe_layer *layer = fh->layer; | ||
1252 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1253 | int ret; | ||
1254 | |||
1255 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1256 | "VIDIOC_DQBUF, layer id = %d\n", | ||
1257 | layer->device_id); | ||
1258 | |||
1259 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { | ||
1260 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1261 | return -EINVAL; | ||
1262 | } | ||
1263 | /* If this file handle is not allowed to do IO, return error */ | ||
1264 | if (!fh->io_allowed) { | ||
1265 | v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); | ||
1266 | return -EACCES; | ||
1267 | } | ||
1268 | if (file->f_flags & O_NONBLOCK) | ||
1269 | /* Call videobuf_dqbuf for non blocking mode */ | ||
1270 | ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1); | ||
1271 | else | ||
1272 | /* Call videobuf_dqbuf for blocking mode */ | ||
1273 | ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0); | ||
1274 | |||
1275 | return ret; | ||
1276 | } | ||
1277 | |||
1278 | static int vpbe_display_qbuf(struct file *file, void *priv, | ||
1279 | struct v4l2_buffer *p) | ||
1280 | { | ||
1281 | struct vpbe_fh *fh = file->private_data; | ||
1282 | struct vpbe_layer *layer = fh->layer; | ||
1283 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1284 | |||
1285 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1286 | "VIDIOC_QBUF, layer id = %d\n", | ||
1287 | layer->device_id); | ||
1288 | |||
1289 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) { | ||
1290 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1291 | return -EINVAL; | ||
1292 | } | ||
1293 | |||
1294 | /* If this file handle is not allowed to do IO, return error */ | ||
1295 | if (!fh->io_allowed) { | ||
1296 | v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n"); | ||
1297 | return -EACCES; | ||
1298 | } | ||
1299 | |||
1300 | return videobuf_qbuf(&layer->buffer_queue, p); | ||
1301 | } | ||
1302 | |||
1303 | static int vpbe_display_querybuf(struct file *file, void *priv, | ||
1304 | struct v4l2_buffer *buf) | ||
1305 | { | ||
1306 | struct vpbe_fh *fh = file->private_data; | ||
1307 | struct vpbe_layer *layer = fh->layer; | ||
1308 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1309 | int ret; | ||
1310 | |||
1311 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1312 | "VIDIOC_QUERYBUF, layer id = %d\n", | ||
1313 | layer->device_id); | ||
1314 | |||
1315 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) { | ||
1316 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1317 | return -EINVAL; | ||
1318 | } | ||
1319 | |||
1320 | /* Call videobuf_querybuf to get information */ | ||
1321 | ret = videobuf_querybuf(&layer->buffer_queue, buf); | ||
1322 | |||
1323 | return ret; | ||
1324 | } | ||
1325 | |||
1326 | static int vpbe_display_reqbufs(struct file *file, void *priv, | ||
1327 | struct v4l2_requestbuffers *req_buf) | ||
1328 | { | ||
1329 | struct vpbe_fh *fh = file->private_data; | ||
1330 | struct vpbe_layer *layer = fh->layer; | ||
1331 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1332 | int ret; | ||
1333 | |||
1334 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n"); | ||
1335 | |||
1336 | if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) { | ||
1337 | v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); | ||
1338 | return -EINVAL; | ||
1339 | } | ||
1340 | |||
1341 | /* If io users of the layer is not zero, return error */ | ||
1342 | if (0 != layer->io_usrs) { | ||
1343 | v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n"); | ||
1344 | return -EBUSY; | ||
1345 | } | ||
1346 | /* Initialize videobuf queue as per the buffer type */ | ||
1347 | videobuf_queue_dma_contig_init(&layer->buffer_queue, | ||
1348 | &video_qops, | ||
1349 | vpbe_dev->pdev, | ||
1350 | &layer->irqlock, | ||
1351 | V4L2_BUF_TYPE_VIDEO_OUTPUT, | ||
1352 | layer->pix_fmt.field, | ||
1353 | sizeof(struct videobuf_buffer), | ||
1354 | fh, NULL); | ||
1355 | |||
1356 | /* Set io allowed member of file handle to TRUE */ | ||
1357 | fh->io_allowed = 1; | ||
1358 | /* Increment io usrs member of layer object to 1 */ | ||
1359 | layer->io_usrs = 1; | ||
1360 | /* Store type of memory requested in layer object */ | ||
1361 | layer->memory = req_buf->memory; | ||
1362 | /* Initialize buffer queue */ | ||
1363 | INIT_LIST_HEAD(&layer->dma_queue); | ||
1364 | /* Allocate buffers */ | ||
1365 | ret = videobuf_reqbufs(&layer->buffer_queue, req_buf); | ||
1366 | |||
1367 | return ret; | ||
1368 | } | ||
1369 | |||
1370 | /* | ||
1371 | * vpbe_display_mmap() | ||
1372 | * It is used to map kernel space buffers into user spaces | ||
1373 | */ | ||
1374 | static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma) | ||
1375 | { | ||
1376 | /* Get the layer object and file handle object */ | ||
1377 | struct vpbe_fh *fh = filep->private_data; | ||
1378 | struct vpbe_layer *layer = fh->layer; | ||
1379 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1380 | |||
1381 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n"); | ||
1382 | |||
1383 | return videobuf_mmap_mapper(&layer->buffer_queue, vma); | ||
1384 | } | ||
1385 | |||
1386 | /* vpbe_display_poll(): It is used for select/poll system call | ||
1387 | */ | ||
1388 | static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait) | ||
1389 | { | ||
1390 | struct vpbe_fh *fh = filep->private_data; | ||
1391 | struct vpbe_layer *layer = fh->layer; | ||
1392 | struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; | ||
1393 | unsigned int err = 0; | ||
1394 | |||
1395 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n"); | ||
1396 | if (layer->started) | ||
1397 | err = videobuf_poll_stream(filep, &layer->buffer_queue, wait); | ||
1398 | return err; | ||
1399 | } | ||
1400 | |||
1401 | /* | ||
1402 | * vpbe_display_open() | ||
1403 | * It creates object of file handle structure and stores it in private_data | ||
1404 | * member of filepointer | ||
1405 | */ | ||
1406 | static int vpbe_display_open(struct file *file) | ||
1407 | { | ||
1408 | struct vpbe_fh *fh = NULL; | ||
1409 | struct vpbe_layer *layer = video_drvdata(file); | ||
1410 | struct vpbe_display *disp_dev = layer->disp_dev; | ||
1411 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
1412 | struct osd_state *osd_device = disp_dev->osd_device; | ||
1413 | int err; | ||
1414 | |||
1415 | /* Allocate memory for the file handle object */ | ||
1416 | fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL); | ||
1417 | if (fh == NULL) { | ||
1418 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1419 | "unable to allocate memory for file handle object\n"); | ||
1420 | return -ENOMEM; | ||
1421 | } | ||
1422 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1423 | "vpbe display open plane = %d\n", | ||
1424 | layer->device_id); | ||
1425 | |||
1426 | /* store pointer to fh in private_data member of filep */ | ||
1427 | file->private_data = fh; | ||
1428 | fh->layer = layer; | ||
1429 | fh->disp_dev = disp_dev; | ||
1430 | |||
1431 | if (!layer->usrs) { | ||
1432 | |||
1433 | /* First claim the layer for this device */ | ||
1434 | err = osd_device->ops.request_layer(osd_device, | ||
1435 | layer->layer_info.id); | ||
1436 | if (err < 0) { | ||
1437 | /* Couldn't get layer */ | ||
1438 | v4l2_err(&vpbe_dev->v4l2_dev, | ||
1439 | "Display Manager failed to allocate layer\n"); | ||
1440 | kfree(fh); | ||
1441 | return -EINVAL; | ||
1442 | } | ||
1443 | } | ||
1444 | /* Increment layer usrs counter */ | ||
1445 | layer->usrs++; | ||
1446 | /* Set io_allowed member to false */ | ||
1447 | fh->io_allowed = 0; | ||
1448 | /* Initialize priority of this instance to default priority */ | ||
1449 | fh->prio = V4L2_PRIORITY_UNSET; | ||
1450 | v4l2_prio_open(&layer->prio, &fh->prio); | ||
1451 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, | ||
1452 | "vpbe display device opened successfully\n"); | ||
1453 | return 0; | ||
1454 | } | ||
1455 | |||
1456 | /* | ||
1457 | * vpbe_display_release() | ||
1458 | * This function deletes buffer queue, frees the buffers and the davinci | ||
1459 | * display file * handle | ||
1460 | */ | ||
1461 | static int vpbe_display_release(struct file *file) | ||
1462 | { | ||
1463 | /* Get the layer object and file handle object */ | ||
1464 | struct vpbe_fh *fh = file->private_data; | ||
1465 | struct vpbe_layer *layer = fh->layer; | ||
1466 | struct osd_layer_config *cfg = &layer->layer_info.config; | ||
1467 | struct vpbe_display *disp_dev = fh->disp_dev; | ||
1468 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
1469 | struct osd_state *osd_device = disp_dev->osd_device; | ||
1470 | |||
1471 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n"); | ||
1472 | |||
1473 | /* if this instance is doing IO */ | ||
1474 | if (fh->io_allowed) { | ||
1475 | /* Reset io_usrs member of layer object */ | ||
1476 | layer->io_usrs = 0; | ||
1477 | |||
1478 | osd_device->ops.disable_layer(osd_device, | ||
1479 | layer->layer_info.id); | ||
1480 | layer->started = 0; | ||
1481 | /* Free buffers allocated */ | ||
1482 | videobuf_queue_cancel(&layer->buffer_queue); | ||
1483 | videobuf_mmap_free(&layer->buffer_queue); | ||
1484 | } | ||
1485 | |||
1486 | /* Decrement layer usrs counter */ | ||
1487 | layer->usrs--; | ||
1488 | /* If this file handle has initialize encoder device, reset it */ | ||
1489 | if (!layer->usrs) { | ||
1490 | if (cfg->pixfmt == PIXFMT_NV12) { | ||
1491 | struct vpbe_layer *otherlayer; | ||
1492 | otherlayer = | ||
1493 | _vpbe_display_get_other_win_layer(disp_dev, layer); | ||
1494 | osd_device->ops.disable_layer(osd_device, | ||
1495 | otherlayer->layer_info.id); | ||
1496 | osd_device->ops.release_layer(osd_device, | ||
1497 | otherlayer->layer_info.id); | ||
1498 | } | ||
1499 | osd_device->ops.disable_layer(osd_device, | ||
1500 | layer->layer_info.id); | ||
1501 | osd_device->ops.release_layer(osd_device, | ||
1502 | layer->layer_info.id); | ||
1503 | } | ||
1504 | /* Close the priority */ | ||
1505 | v4l2_prio_close(&layer->prio, fh->prio); | ||
1506 | file->private_data = NULL; | ||
1507 | |||
1508 | /* Free memory allocated to file handle object */ | ||
1509 | kfree(fh); | ||
1510 | |||
1511 | disp_dev->cbcr_ofst = 0; | ||
1512 | |||
1513 | return 0; | ||
1514 | } | ||
1515 | |||
1516 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1517 | static int vpbe_display_g_register(struct file *file, void *priv, | ||
1518 | struct v4l2_dbg_register *reg) | ||
1519 | { | ||
1520 | struct v4l2_dbg_match *match = ®->match; | ||
1521 | |||
1522 | if (match->type >= 2) { | ||
1523 | v4l2_subdev_call(vpbe_dev->venc, | ||
1524 | core, | ||
1525 | g_register, | ||
1526 | reg); | ||
1527 | } | ||
1528 | |||
1529 | return 0; | ||
1530 | } | ||
1531 | |||
1532 | static int vpbe_display_s_register(struct file *file, void *priv, | ||
1533 | struct v4l2_dbg_register *reg) | ||
1534 | { | ||
1535 | return 0; | ||
1536 | } | ||
1537 | #endif | ||
1538 | |||
1539 | /* vpbe capture ioctl operations */ | ||
1540 | static const struct v4l2_ioctl_ops vpbe_ioctl_ops = { | ||
1541 | .vidioc_querycap = vpbe_display_querycap, | ||
1542 | .vidioc_g_fmt_vid_out = vpbe_display_g_fmt, | ||
1543 | .vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt, | ||
1544 | .vidioc_s_fmt_vid_out = vpbe_display_s_fmt, | ||
1545 | .vidioc_try_fmt_vid_out = vpbe_display_try_fmt, | ||
1546 | .vidioc_reqbufs = vpbe_display_reqbufs, | ||
1547 | .vidioc_querybuf = vpbe_display_querybuf, | ||
1548 | .vidioc_qbuf = vpbe_display_qbuf, | ||
1549 | .vidioc_dqbuf = vpbe_display_dqbuf, | ||
1550 | .vidioc_streamon = vpbe_display_streamon, | ||
1551 | .vidioc_streamoff = vpbe_display_streamoff, | ||
1552 | .vidioc_cropcap = vpbe_display_cropcap, | ||
1553 | .vidioc_g_crop = vpbe_display_g_crop, | ||
1554 | .vidioc_s_crop = vpbe_display_s_crop, | ||
1555 | .vidioc_g_priority = vpbe_display_g_priority, | ||
1556 | .vidioc_s_priority = vpbe_display_s_priority, | ||
1557 | .vidioc_s_std = vpbe_display_s_std, | ||
1558 | .vidioc_g_std = vpbe_display_g_std, | ||
1559 | .vidioc_enum_output = vpbe_display_enum_output, | ||
1560 | .vidioc_s_output = vpbe_display_s_output, | ||
1561 | .vidioc_g_output = vpbe_display_g_output, | ||
1562 | .vidioc_s_dv_preset = vpbe_display_s_dv_preset, | ||
1563 | .vidioc_g_dv_preset = vpbe_display_g_dv_preset, | ||
1564 | .vidioc_enum_dv_presets = vpbe_display_enum_dv_presets, | ||
1565 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1566 | .vidioc_g_register = vpbe_display_g_register, | ||
1567 | .vidioc_s_register = vpbe_display_s_register, | ||
1568 | #endif | ||
1569 | }; | ||
1570 | |||
1571 | static struct v4l2_file_operations vpbe_fops = { | ||
1572 | .owner = THIS_MODULE, | ||
1573 | .open = vpbe_display_open, | ||
1574 | .release = vpbe_display_release, | ||
1575 | .unlocked_ioctl = video_ioctl2, | ||
1576 | .mmap = vpbe_display_mmap, | ||
1577 | .poll = vpbe_display_poll | ||
1578 | }; | ||
1579 | |||
1580 | static int vpbe_device_get(struct device *dev, void *data) | ||
1581 | { | ||
1582 | struct platform_device *pdev = to_platform_device(dev); | ||
1583 | struct vpbe_display *vpbe_disp = data; | ||
1584 | |||
1585 | if (strcmp("vpbe_controller", pdev->name) == 0) | ||
1586 | vpbe_disp->vpbe_dev = platform_get_drvdata(pdev); | ||
1587 | |||
1588 | if (strcmp("vpbe-osd", pdev->name) == 0) | ||
1589 | vpbe_disp->osd_device = platform_get_drvdata(pdev); | ||
1590 | |||
1591 | return 0; | ||
1592 | } | ||
1593 | |||
1594 | static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev, | ||
1595 | struct platform_device *pdev) | ||
1596 | { | ||
1597 | struct vpbe_layer *vpbe_display_layer = NULL; | ||
1598 | struct video_device *vbd = NULL; | ||
1599 | |||
1600 | /* Allocate memory for four plane display objects */ | ||
1601 | |||
1602 | disp_dev->dev[i] = | ||
1603 | kzalloc(sizeof(struct vpbe_layer), GFP_KERNEL); | ||
1604 | |||
1605 | /* If memory allocation fails, return error */ | ||
1606 | if (!disp_dev->dev[i]) { | ||
1607 | printk(KERN_ERR "ran out of memory\n"); | ||
1608 | return -ENOMEM; | ||
1609 | } | ||
1610 | spin_lock_init(&disp_dev->dev[i]->irqlock); | ||
1611 | mutex_init(&disp_dev->dev[i]->opslock); | ||
1612 | |||
1613 | /* Get the pointer to the layer object */ | ||
1614 | vpbe_display_layer = disp_dev->dev[i]; | ||
1615 | vbd = &vpbe_display_layer->video_dev; | ||
1616 | /* Initialize field of video device */ | ||
1617 | vbd->release = video_device_release_empty; | ||
1618 | vbd->fops = &vpbe_fops; | ||
1619 | vbd->ioctl_ops = &vpbe_ioctl_ops; | ||
1620 | vbd->minor = -1; | ||
1621 | vbd->v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev; | ||
1622 | vbd->lock = &vpbe_display_layer->opslock; | ||
1623 | |||
1624 | if (disp_dev->vpbe_dev->current_timings.timings_type & | ||
1625 | VPBE_ENC_STD) { | ||
1626 | vbd->tvnorms = (V4L2_STD_525_60 | V4L2_STD_625_50); | ||
1627 | vbd->current_norm = | ||
1628 | disp_dev->vpbe_dev-> | ||
1629 | current_timings.timings.std_id; | ||
1630 | } else | ||
1631 | vbd->current_norm = 0; | ||
1632 | |||
1633 | snprintf(vbd->name, sizeof(vbd->name), | ||
1634 | "DaVinci_VPBE Display_DRIVER_V%d.%d.%d", | ||
1635 | (VPBE_DISPLAY_VERSION_CODE >> 16) & 0xff, | ||
1636 | (VPBE_DISPLAY_VERSION_CODE >> 8) & 0xff, | ||
1637 | (VPBE_DISPLAY_VERSION_CODE) & 0xff); | ||
1638 | |||
1639 | vpbe_display_layer->device_id = i; | ||
1640 | |||
1641 | vpbe_display_layer->layer_info.id = | ||
1642 | ((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1); | ||
1643 | |||
1644 | /* Initialize prio member of layer object */ | ||
1645 | v4l2_prio_init(&vpbe_display_layer->prio); | ||
1646 | |||
1647 | return 0; | ||
1648 | } | ||
1649 | |||
1650 | static __devinit int register_device(struct vpbe_layer *vpbe_display_layer, | ||
1651 | struct vpbe_display *disp_dev, | ||
1652 | struct platform_device *pdev) { | ||
1653 | int err; | ||
1654 | |||
1655 | v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, | ||
1656 | "Trying to register VPBE display device.\n"); | ||
1657 | v4l2_info(&disp_dev->vpbe_dev->v4l2_dev, | ||
1658 | "layer=%x,layer->video_dev=%x\n", | ||
1659 | (int)vpbe_display_layer, | ||
1660 | (int)&vpbe_display_layer->video_dev); | ||
1661 | |||
1662 | err = video_register_device(&vpbe_display_layer->video_dev, | ||
1663 | VFL_TYPE_GRABBER, | ||
1664 | -1); | ||
1665 | if (err) | ||
1666 | return -ENODEV; | ||
1667 | |||
1668 | vpbe_display_layer->disp_dev = disp_dev; | ||
1669 | /* set the driver data in platform device */ | ||
1670 | platform_set_drvdata(pdev, disp_dev); | ||
1671 | video_set_drvdata(&vpbe_display_layer->video_dev, | ||
1672 | vpbe_display_layer); | ||
1673 | |||
1674 | return 0; | ||
1675 | } | ||
1676 | |||
1677 | |||
1678 | |||
1679 | /* | ||
1680 | * vpbe_display_probe() | ||
1681 | * This function creates device entries by register itself to the V4L2 driver | ||
1682 | * and initializes fields of each layer objects | ||
1683 | */ | ||
1684 | static __devinit int vpbe_display_probe(struct platform_device *pdev) | ||
1685 | { | ||
1686 | struct vpbe_layer *vpbe_display_layer; | ||
1687 | struct vpbe_display *disp_dev; | ||
1688 | struct resource *res = NULL; | ||
1689 | int k; | ||
1690 | int i; | ||
1691 | int err; | ||
1692 | int irq; | ||
1693 | |||
1694 | printk(KERN_DEBUG "vpbe_display_probe\n"); | ||
1695 | /* Allocate memory for vpbe_display */ | ||
1696 | disp_dev = kzalloc(sizeof(struct vpbe_display), GFP_KERNEL); | ||
1697 | if (!disp_dev) { | ||
1698 | printk(KERN_ERR "ran out of memory\n"); | ||
1699 | return -ENOMEM; | ||
1700 | } | ||
1701 | |||
1702 | spin_lock_init(&disp_dev->dma_queue_lock); | ||
1703 | /* | ||
1704 | * Scan all the platform devices to find the vpbe | ||
1705 | * controller device and get the vpbe_dev object | ||
1706 | */ | ||
1707 | err = bus_for_each_dev(&platform_bus_type, NULL, disp_dev, | ||
1708 | vpbe_device_get); | ||
1709 | if (err < 0) | ||
1710 | return err; | ||
1711 | /* Initialize the vpbe display controller */ | ||
1712 | if (NULL != disp_dev->vpbe_dev->ops.initialize) { | ||
1713 | err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev, | ||
1714 | disp_dev->vpbe_dev); | ||
1715 | if (err) { | ||
1716 | v4l2_err(&disp_dev->vpbe_dev->v4l2_dev, | ||
1717 | "Error initing vpbe\n"); | ||
1718 | err = -ENOMEM; | ||
1719 | goto probe_out; | ||
1720 | } | ||
1721 | } | ||
1722 | |||
1723 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { | ||
1724 | if (init_vpbe_layer(i, disp_dev, pdev)) { | ||
1725 | err = -ENODEV; | ||
1726 | goto probe_out; | ||
1727 | } | ||
1728 | } | ||
1729 | |||
1730 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1731 | if (!res) { | ||
1732 | v4l2_err(&disp_dev->vpbe_dev->v4l2_dev, | ||
1733 | "Unable to get VENC interrupt resource\n"); | ||
1734 | err = -ENODEV; | ||
1735 | goto probe_out; | ||
1736 | } | ||
1737 | |||
1738 | irq = res->start; | ||
1739 | if (request_irq(irq, venc_isr, IRQF_DISABLED, VPBE_DISPLAY_DRIVER, | ||
1740 | disp_dev)) { | ||
1741 | v4l2_err(&disp_dev->vpbe_dev->v4l2_dev, | ||
1742 | "Unable to request interrupt\n"); | ||
1743 | err = -ENODEV; | ||
1744 | goto probe_out; | ||
1745 | } | ||
1746 | |||
1747 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { | ||
1748 | if (register_device(disp_dev->dev[i], disp_dev, pdev)) { | ||
1749 | err = -ENODEV; | ||
1750 | goto probe_out; | ||
1751 | } | ||
1752 | } | ||
1753 | |||
1754 | printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n"); | ||
1755 | return 0; | ||
1756 | |||
1757 | probe_out: | ||
1758 | free_irq(res->start, disp_dev); | ||
1759 | for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) { | ||
1760 | /* Get the pointer to the layer object */ | ||
1761 | vpbe_display_layer = disp_dev->dev[k]; | ||
1762 | /* Unregister video device */ | ||
1763 | if (vpbe_display_layer) { | ||
1764 | video_unregister_device( | ||
1765 | &vpbe_display_layer->video_dev); | ||
1766 | kfree(disp_dev->dev[k]); | ||
1767 | } | ||
1768 | } | ||
1769 | kfree(disp_dev); | ||
1770 | return err; | ||
1771 | } | ||
1772 | |||
1773 | /* | ||
1774 | * vpbe_display_remove() | ||
1775 | * It un-register hardware layer from V4L2 driver | ||
1776 | */ | ||
1777 | static int vpbe_display_remove(struct platform_device *pdev) | ||
1778 | { | ||
1779 | struct vpbe_layer *vpbe_display_layer; | ||
1780 | struct vpbe_display *disp_dev = platform_get_drvdata(pdev); | ||
1781 | struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; | ||
1782 | struct resource *res; | ||
1783 | int i; | ||
1784 | |||
1785 | v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_remove\n"); | ||
1786 | |||
1787 | /* unregister irq */ | ||
1788 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
1789 | free_irq(res->start, disp_dev); | ||
1790 | |||
1791 | /* deinitialize the vpbe display controller */ | ||
1792 | if (NULL != vpbe_dev->ops.deinitialize) | ||
1793 | vpbe_dev->ops.deinitialize(&pdev->dev, vpbe_dev); | ||
1794 | /* un-register device */ | ||
1795 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { | ||
1796 | /* Get the pointer to the layer object */ | ||
1797 | vpbe_display_layer = disp_dev->dev[i]; | ||
1798 | /* Unregister video device */ | ||
1799 | video_unregister_device(&vpbe_display_layer->video_dev); | ||
1800 | |||
1801 | } | ||
1802 | for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) { | ||
1803 | kfree(disp_dev->dev[i]); | ||
1804 | disp_dev->dev[i] = NULL; | ||
1805 | } | ||
1806 | |||
1807 | return 0; | ||
1808 | } | ||
1809 | |||
1810 | static struct platform_driver vpbe_display_driver = { | ||
1811 | .driver = { | ||
1812 | .name = VPBE_DISPLAY_DRIVER, | ||
1813 | .owner = THIS_MODULE, | ||
1814 | .bus = &platform_bus_type, | ||
1815 | }, | ||
1816 | .probe = vpbe_display_probe, | ||
1817 | .remove = __devexit_p(vpbe_display_remove), | ||
1818 | }; | ||
1819 | |||
1820 | /* | ||
1821 | * vpbe_display_init() | ||
1822 | * This function registers device and driver to the kernel, requests irq | ||
1823 | * handler and allocates memory for layer objects | ||
1824 | */ | ||
1825 | static __devinit int vpbe_display_init(void) | ||
1826 | { | ||
1827 | int err; | ||
1828 | |||
1829 | printk(KERN_DEBUG "vpbe_display_init\n"); | ||
1830 | |||
1831 | /* Register driver to the kernel */ | ||
1832 | err = platform_driver_register(&vpbe_display_driver); | ||
1833 | if (0 != err) | ||
1834 | return err; | ||
1835 | |||
1836 | printk(KERN_DEBUG "vpbe_display_init:" | ||
1837 | "VPBE V4L2 Display Driver V1.0 loaded\n"); | ||
1838 | return 0; | ||
1839 | } | ||
1840 | |||
1841 | /* | ||
1842 | * vpbe_display_cleanup() | ||
1843 | * This function un-registers device and driver to the kernel, frees requested | ||
1844 | * irq handler and de-allocates memory allocated for layer objects. | ||
1845 | */ | ||
1846 | static void vpbe_display_cleanup(void) | ||
1847 | { | ||
1848 | printk(KERN_DEBUG "vpbe_display_cleanup\n"); | ||
1849 | |||
1850 | /* platform driver unregister */ | ||
1851 | platform_driver_unregister(&vpbe_display_driver); | ||
1852 | } | ||
1853 | |||
1854 | /* Function for module initialization and cleanup */ | ||
1855 | module_init(vpbe_display_init); | ||
1856 | module_exit(vpbe_display_cleanup); | ||
1857 | |||
1858 | MODULE_DESCRIPTION("TI DM644x/DM355/DM365 VPBE Display controller"); | ||
1859 | MODULE_LICENSE("GPL"); | ||
1860 | MODULE_AUTHOR("Texas Instruments"); | ||