2 * Copyright (c) 2005 Advanced Micro Devices, Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * The full GNU General Public License is included in this distribution in the
24 * lx device level interface
25 * for v4l/2 linux driver
26 * interfaces to cimarron hardware api
32 #define ERR_INT_ENABLES \
33 ( VIP_INT_FIFO_WRAP | VIP_INT_ACTIVE_PIXELS | \
34 VIP_INT_LONGLINE | VIP_INT_CLOCK_INPUT )
37 static int is_reported
= 1;
39 /* device parameters by standard index */
40 static struct s_std_parms
{
47 } lx_std_parms
[STD_IDS_SZ
] = {
48 [STD_SD_NTSC
] = { 720, 480, 0, 30, 1, 8 },
49 [STD_SD_PAL
] = { 720, 576, 0, 25, 1, 8 },
50 [STD_HD_480P
] = { 720, 480, 1, 60, 2, 16 },
51 [STD_HD_525P
] = { 720, 576, 1, 60, 2, 16 },
52 [STD_HD_720P
] = { 1280, 720, 1, 60, 2, 16 },
53 [STD_HD_1080I
] = { 1920, 1080, 0, 60, 2, 16 },
54 [STD_HD_VGA
] = { 640, 480, 1, 30, 1, 8 },
55 [STD_HD_QVGA
] = { 320, 240, 1, 30, 1, 8 },
58 /* cimarron buffer parameters by task id */
65 } vip_task_data
[CAPT_TASK_SZ
] = {
66 [CAPT_TASK_A
] = { VIP_ENABLE_TASKA
, VIP_BUFFER_TASK_A
, VIP_BUFFER_A
,
67 VIP_BUFFER_A_ODD
, VIP_BUFFER_A_EVEN
},
68 [CAPT_TASK_B
] = { VIP_ENABLE_TASKB
, VIP_BUFFER_TASK_B
, VIP_BUFFER_B
,
69 VIP_BUFFER_B_ODD
, VIP_BUFFER_B_EVEN
},
72 /* just finished a field when starting other field */
73 static unsigned long capt_bfr_mask
[capt_toggle_sz
] = {
74 [capt_toggle_none
] = 0,
75 [capt_toggle_odd
] = VIP_INT_START_EVEN
,
76 [capt_toggle_even
] = VIP_INT_START_ODD
,
77 [capt_toggle_both
] = VIP_INT_START_ODD
,
78 [capt_toggle_vblank
] = VIP_INT_START_VBLANK
,
81 /** lx_capt_resume - queue capture buffers to vip */
83 lx_capt_resume(VidDevice
*dp
,io_queue
*io
)
86 int eidx
, oidx
, vip_buffers
;
87 int task
= dp
->capt_vip_task
;
88 int task_buffers
= vip_task_data
[task
].task_buffers
;
89 VIPINPUTBUFFER
*vip_inpbfr
= &dp
->vip_inpbfr
;
91 task
= dp
->capt_vip_task
;
92 task_buffers
= vip_task_data
[task
].task_buffers
;
94 if( dp
->capt_addr_is_set
== 0 ) {
95 op
= dp
->capt_toggle
== capt_toggle_odd
? dp
->capt_elch
: dp
->capt_onxt
;
97 if( list_empty(&io
->rd_qbuf
) != 0 ) return 0;
98 op
= list_entry(io
->rd_qbuf
.next
,io_buf
,bfrq
);
99 list_del_init(&op
->bfrq
);
101 if( dp
->capt_toggle
== capt_toggle_both
||
102 dp
->capt_toggle
== capt_toggle_odd
) {
103 if( (ep
=dp
->capt_enxt
) == NULL
) {
104 if( list_empty(&io
->rd_qbuf
) != 0 ) {
105 list_add(&op
->bfrq
,&io
->rd_qbuf
);
108 ep
= list_entry(io
->rd_qbuf
.next
,io_buf
,bfrq
);
109 list_del_init(&ep
->bfrq
);
114 dp
->capt_onxt
= op
; oidx
= op
->index
;
115 dp
->capt_enxt
= ep
; eidx
= ep
->index
;
121 vip_inpbfr
->current_buffer
= eidx
;
122 vip_buffers
= vip_task_data
[task
].vip_even_buffers
;
123 vip_toggle_video_offsets(vip_buffers
,vip_inpbfr
);
124 vip_inpbfr
->current_buffer
= oidx
;
125 vip_buffers
= vip_task_data
[task
].vip_odd_buffers
;
126 vip_toggle_video_offsets(vip_buffers
,vip_inpbfr
);
129 vip_inpbfr
->current_buffer
= oidx
;
130 vip_buffers
= vip_task_data
[task
].vip_buffers
;
131 vip_toggle_video_offsets(vip_buffers
,vip_inpbfr
);
133 dp
->capt_stalled
= 0;
136 ++dp
->capt_jiffy_sequence
;
140 /** lx_capt_start - start capture
141 * calculate buffer offsets, load buffers, and enable interrupts
144 lx_capt_start(VidDevice
*dp
)
147 int imgsz
, width
, height
, y_pitch
, uv_pitch
;
148 int vip_buffers
, y_imgsz
, uv_imgsz
;
149 int interrupts
, field
;
150 int i
; io_queue
*io
; io_buf
*bp
;
151 unsigned long oy_offset
, ey_offset
, flags
;
152 unsigned long offset1
, offset2
, u_offset
, v_offset
;
153 struct v4l2_pix_format
*fmt
= &dp
->capt
;
154 unsigned int capt_pixelformat
= fmt
->pixelformat
;
155 int task
= dp
->capt_vip_task
;
156 int task_buffers
= vip_task_data
[task
].task_buffers
;
157 VIPSETMODEBUFFER vip_mode
;
158 VIPSUBWINDOWBUFFER swbfr
;
159 VIPINPUTBUFFER_ADDR
*vip_inpadr
;
160 VIPINPUTBUFFER
*vip_inpbfr
= &dp
->vip_inpbfr
;
161 FilePriv
*fp
= &dp
->fp
;
163 memset(&vip_mode
,0,sizeof(vip_mode
));
164 vip_mode
.stream_enables
= vip_task_data
[task
].enables
;
165 if( dp
->capt_inverted
!= 0 ) vip_mode
.flags
|= VIP_MODEFLAG_INVERTPOLARITY
;
166 vip_mode
.operating_mode
= dp
->capt_vip_version
== 1 ? VIP_MODE_VIP1_8BIT
:
167 (dp
->capt_port_size
== 8 ? VIP_MODE_VIP2_8BIT
: VIP_MODE_VIP2_16BIT
);
169 memset(vip_inpbfr
,0,sizeof(*vip_inpbfr
));
172 height
= fmt
->height
;
173 y_pitch
= lx_capt_ypitch(dp
,capt_pixelformat
,width
);
174 uv_pitch
= lx_capt_uvpitch(dp
,capt_pixelformat
,width
);
175 offset1
= offset2
= u_offset
= v_offset
= 0;
176 /* default is capt format, if not in spec */
177 field
= v4l_vid_field(&dp
->capt
);
178 field
= v4l_vid_field_def(field
,dp
->capt_dft_field
);
179 if( lx_capt_std_progressive(dp
,dp
->std_index
) != 0 )
180 vip_mode
.flags
|= VIP_MODEFLAG_PROGRESSIVE
;
183 y_imgsz
= y_pitch
*height
;
184 uv_imgsz
= uv_pitch
*height
;
185 if( v4l_fmt_is_420(capt_pixelformat
) > 0 ) {
191 imgsz
= y_imgsz
+ 2*uv_imgsz
;
192 oy_offset
= ey_offset
= 0;
193 dp
->capt_toggle
= capt_toggle_even
;
195 case V4L2_FIELD_SEQ_TB
: /* both fields seq 1 bfr, top-bottom */
198 case V4L2_FIELD_SEQ_BT
: /* same + bottom-top */
201 case V4L2_FIELD_INTERLACED
: /* both fields interlaced */
202 ey_offset
+= y_pitch
;
208 case V4L2_FIELD_TOP
: /* top field only */
209 dp
->capt_toggle
= dp
->capt_progressive
!= 0 ?
210 capt_toggle_vblank
: capt_toggle_odd
;
212 case V4L2_FIELD_BOTTOM
: /* bottom field only */
213 dp
->capt_toggle
= dp
->capt_progressive
!= 0 ?
214 capt_toggle_vblank
: capt_toggle_even
;
216 case V4L2_FIELD_ALTERNATE
: /* both fields alternating 2 buffers */
217 case V4L2_FIELD_NONE
: /* counts as progressive */
218 dp
->capt_toggle
= dp
->capt_progressive
!= 0 ?
219 capt_toggle_vblank
: capt_toggle_both
;
222 if( dp
->capt_progressive
!= 0 ) {
223 if( dp
->capt_toggle
!= capt_toggle_vblank
) {
224 DMSG(1,"lx_capt_start:std field fmt progressive/"
225 "field(%d) fmt mismatched\n",field
);
226 dp
->capt_toggle
= capt_toggle_vblank
;
229 if( v4l_fmt_is_planar(capt_pixelformat
) > 0 ) {
231 offset2
= offset1
+ uv_imgsz
;
237 switch( capt_pixelformat
) {
238 case V4L2_PIX_FMT_YVU420
:
242 case V4L2_PIX_FMT_YUV422P
:
243 case V4L2_PIX_FMT_YUV420
:
249 dp
->capt_ey_offset
= ey_offset
;
250 dp
->capt_oy_offset
= oy_offset
;
251 dp
->capt_u_offset
= u_offset
;
252 dp
->capt_v_offset
= v_offset
;
254 memset(&swbfr
,0,sizeof(swbfr
));
257 vip_set_subwindow_enable(&swbfr
);
259 vip_mode
.planar_capture
= dp
->capt_420
!= 0 ?
260 VIP_420CAPTURE_ALTERNATINGLINES
: VIP_420CAPTURE_EVERYLINE
;
261 if( dp
->capt_planar
!= 0 ) {
262 vip_mode
.flags
|= VIP_MODEFLAG_PLANARCAPTURE
;
263 vip_inpbfr
->flags
|= VIP_INPUTFLAG_PLANAR
;
266 vip_inpadr
= &vip_inpbfr
->offsets
[task_buffers
];
267 if( dp
->capt_addr_is_set
== 0 ) {
268 if( (io
=fp
->io
) == NULL
) return -EINVAL
; /* must have buffer(s) */
269 for( i
=io
->mbfrs
,bp
=&io
->bfrs
[0]; --i
>=0; ++bp
) {
270 vip_inpadr
->odd_base
[bp
->index
] = bp
->phys_addr
+ oy_offset
;
271 vip_inpadr
->even_base
[bp
->index
] = bp
->phys_addr
+ ey_offset
;
275 vip_inpadr
->odd_base
[0] = dp
->capt_phys_addr
+ oy_offset
;
276 vip_inpadr
->even_base
[0] = dp
->capt_phys_addr
+ ey_offset
;
278 vip_inpadr
->y_pitch
= y_pitch
;
279 vip_inpadr
->uv_pitch
= uv_pitch
;
280 vip_inpadr
->odd_uoffset
= u_offset
;
281 vip_inpadr
->even_uoffset
= u_offset
;
282 vip_inpadr
->odd_voffset
= v_offset
;
283 vip_inpadr
->even_voffset
= v_offset
;
286 DMSG(1," capt %4.4s %dx%d oy %lx ey %lx u %lx v %lx"
287 " yp %x uvp %x tgl %d prg %d plnr %d 420 %d\n",
288 (char*)&fmt
->pixelformat
, fmt
->width
, fmt
->height
,
289 vip_inpadr
->odd_base
[0], vip_inpadr
->even_base
[0],
290 u_offset
, v_offset
, y_pitch
, uv_pitch
,
291 dp
->capt_toggle
, dp
->capt_progressive
,
292 dp
->capt_planar
, dp
->capt_420
);
294 vip_max_address_enable(DEFAULT_MAX_ADDRESS
, 0);
295 spin_lock_irqsave(&dp
->lock
, flags
);
296 ret
= vip_initialize(&vip_mode
);
298 DMSG(3,"lx_capt_start: vip_initialize returned %d (%d:OK)\n", ret
, CIM_STATUS_OK
);
300 vip_buffers
= vip_task_data
[task
].vip_buffers
;
301 ret
= vip_configure_capture_buffers(vip_buffers
,vip_inpbfr
);
303 DMSG(3,"lx_capt_start: vip_configure_capture_buffers returned %d (%d:OK)\n", ret
, CIM_STATUS_OK
);
305 dp
->capt_obfr
= dp
->capt_ebfr
= NULL
;
306 dp
->capt_onxt
= dp
->capt_enxt
= NULL
;
307 dp
->ovly_obfr
= dp
->ovly_ebfr
= NULL
;
308 ret
= lx_capt_resume(dp
,fp
->io
);
310 DMSG(3,"lx_capt_start: lx_capt_resume returned %d (1:OK)\n", ret
);
311 dp
->capt_no_clocks
= 0;
312 vip_set_capture_state(VIP_STARTCAPTUREATNEXTFRAME
);
314 interrupts
= ERR_INT_ENABLES
;
315 if( dp
->capt_progressive
== 0 )
316 interrupts
|= VIP_INT_START_ODD
| VIP_INT_START_EVEN
;
318 interrupts
|= VIP_INT_START_VBLANK
;
319 vip_set_interrupt_enable(interrupts
, 1);
320 spin_unlock_irqrestore(&dp
->lock
, flags
);
324 /** lx_capt_stop - stop capture */
326 lx_capt_stop(VidDevice
*dp
)
328 vip_set_interrupt_enable(VIP_ALL_INTERRUPTS
, 0);
329 vip_set_capture_state(VIP_STOPCAPTURE
);
330 vip_set_genlock_enable(0);
335 /** lx_capt_get_format - enumerate video formats */
337 lx_capt_get_format(VidDevice
*dp
,int index
, struct v4l2_fmtdesc
*fmt
)
340 unsigned int pixelformat
;
341 memset(fmt
,0,sizeof(*fmt
));
343 n
= dp
->capt_formats
;
344 for( idx
=0,i
=sizeof(n
)*8; --i
>=0; n
>>=1,++idx
) {
345 if( (n
&1) == 0 ) continue;
346 if( --index
< 0 ) break;
349 case 0: pixelformat
= V4L2_PIX_FMT_UYVY
; break;
350 case 1: pixelformat
= V4L2_PIX_FMT_YUYV
; break;
351 case 2: pixelformat
= V4L2_PIX_FMT_YUV420
; break;
352 case 3: pixelformat
= V4L2_PIX_FMT_YVU420
; break;
353 case 4: pixelformat
= V4L2_PIX_FMT_YUV422P
; break;
357 fmt
->pixelformat
= pixelformat
;
358 snprintf(&fmt
->description
[0],sizeof(fmt
->description
),
359 "%4.4s", (char*)&pixelformat
);
361 fmt
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE
;
368 /** lx_capt_min_rect - return min capture geometry */
370 lx_capt_min_rect(VidDevice
*dp
,int *w
, int *h
)
375 /** lx_capt_max_rect - return max capture geometry */
377 lx_capt_max_rect(VidDevice
*dp
,int *w
, int *h
)
379 *w
= 1920; *h
= 1080;
382 /** lx_capt_std_geom - return capture geometry by std_index */
384 lx_capt_std_geom(VidDevice
*dp
,int idx
, int *w
, int *h
)
386 *w
= lx_std_parms
[idx
].width
;
387 *h
= lx_std_parms
[idx
].height
;
390 /** lx_capt_is_supported_format - test whether format is supported and enabled */
392 lx_capt_is_supported_format(VidDevice
*dp
,int fmt
)
396 case V4L2_PIX_FMT_UYVY
: n
= 0; break;
397 case V4L2_PIX_FMT_YUYV
: n
= 1; break;
398 case V4L2_PIX_FMT_YUV420
: n
= 2; break;
399 case V4L2_PIX_FMT_YVU420
: n
= 3; break;
400 case V4L2_PIX_FMT_YUV422P
: n
= 4; break;
404 return (dp
->capt_formats
>> n
) & 1;
407 /** lx_capt_max_framerate - return max capture (nearest int) framerate */
409 lx_capt_max_framerate(VidDevice
*dp
,int idx
)
411 return lx_std_parms
[idx
].rate
;
414 /** lx_capt_std_progressive - test standard is progressinve by std_index */
416 lx_capt_std_progressive(VidDevice
*dp
,int idx
)
418 return lx_std_parms
[idx
].progressive
;
421 /** lx_capt_std_vip_version - vip version by std_index */
423 lx_capt_std_vip_version(VidDevice
*dp
,int idx
)
425 return lx_std_parms
[idx
].vip_version
;
428 /** lx_capt_std_port_size - vip port size by std_index */
430 lx_capt_std_port_size(VidDevice
*dp
,int idx
)
432 return lx_std_parms
[idx
].port_size
;
435 /** lx_capt_validate_format - validate format parameters, modify to valid */
437 lx_capt_validate_format(VidDevice
*dp
, struct v4l2_pix_format
*fmt
)
439 int n
, h
, w
, width
, height
, progressive
;
440 int y_pitch
, uv_pitch
;
441 int field
, colorspace
;
442 if( lx_capt_is_supported_format(dp
,fmt
->pixelformat
) == 0 )
443 fmt
->pixelformat
= V4L_DEFAULT_PIX_FMT
;
445 height
= fmt
->height
;
446 lx_capt_min_rect(dp
,&w
,&h
);
447 if( width
< w
) width
= w
;
448 if( height
< h
) height
= h
;
449 lx_capt_max_rect(dp
,&w
,&h
);
450 if( width
> w
) width
= w
;
451 if( height
> h
) height
= h
;
452 progressive
= lx_capt_std_progressive(dp
,dp
->std_index
);
453 if( progressive
== 0 ) {
454 field
= v4l_vid_field(fmt
);
455 field
= v4l_vid_field_def(field
,dp
->capt_dft_field
);
458 field
= V4L2_FIELD_NONE
;
459 v4l_vid_set_field(fmt
,field
);
460 colorspace
= v4l_vid_colorspace(fmt
);
461 colorspace
= v4l_vid_colorspace_def(colorspace
,V4L2_COLORSPACE_SMPTE170M
);
462 v4l_vid_set_colorspace(fmt
,colorspace
);
463 y_pitch
= lx_capt_ypitch(dp
,fmt
->pixelformat
,width
);
464 uv_pitch
= lx_capt_uvpitch(dp
,fmt
->pixelformat
,width
);
465 if( v4l_fmt_is_420(fmt
->pixelformat
) > 0 )
468 fmt
->height
= height
;
469 fmt
->bytesperline
= y_pitch
+ 2*uv_pitch
;
470 n
= v4l_flds_per_bfr(field
);
471 if( (n
== 0 && progressive
== 0) || n
== 1 )
473 fmt
->sizeimage
= fmt
->bytesperline
*height
;
477 /** lx_capt_is_field_valid - test field valid for format/std */
479 lx_capt_is_field_valid(VidDevice
*dp
,unsigned int pixfmt
,int field
)
481 if( v4l_fmt_is_planar(pixfmt
) > 0 ) {
482 if( v4l_flds_per_bfr(field
) == 2 )
485 if( lx_capt_std_progressive(dp
,dp
->std_index
) != 0 ) {
486 if( field
!= V4L2_FIELD_NONE
)
491 if( field
== V4L2_FIELD_NONE
)
498 /** lx_capt_ypitch - return capture y_image pitch */
500 lx_capt_ypitch(VidDevice
*dp
,unsigned int pixelformat
,int width
)
502 int y_pitch
= v4l_vid_ypitch(pixelformat
,width
);
503 if( v4l_fmt_is_planar(pixelformat
) > 0 )
504 y_pitch
= (y_pitch
+Y_CAPT_PLNR_GRAIN
-1) & ~(Y_CAPT_PLNR_GRAIN
-1);
508 /** lx_capt_uvpitch - return capture uv_image pitch */
510 lx_capt_uvpitch(VidDevice
*dp
,unsigned int pixelformat
,int width
)
512 int uv_pitch
= v4l_vid_uvpitch(pixelformat
,width
);
513 if( v4l_fmt_is_planar(pixelformat
) > 0 )
514 uv_pitch
= (uv_pitch
+UV_CAPT_PLNR_GRAIN
-1) & ~(UV_CAPT_PLNR_GRAIN
-1);
518 /** lx_lx_display_is_interlaced - test for interlaced output (tv) mode */
519 #define DC3_IRQ_FILT_CTL 0x00000094 /* VBlank interrupt and filters */
520 #define DC3_IRQFILT_INTL_EN 0x00000800 /* interlace enabled */
521 int lx_display_is_interlaced(void)
523 unsigned int irq_filt_ctl
;
524 irq_filt_ctl
= *(volatile unsigned int *)(cim_get_vg_ptr()+DC3_IRQ_FILT_CTL
);
525 return (irq_filt_ctl
& DC3_IRQFILT_INTL_EN
) != 0 ? 1 : 0;
528 /** lx_ovly_set_scale - set overlay scaling */
530 lx_ovly_set_scale(VidDevice
*dp
,int src_w
,int src_h
,int dst_w
,int dst_h
)
533 if( dst_w
<= 0 || dst_h
<= 0 ) return -EINVAL
;
534 /* default is capt format, if not in spec */
535 field
= v4l_vid_field(&dp
->capt
);
536 field
= v4l_vid_field_def(field
,dp
->capt_dft_field
);
538 field
= v4l_vid_field_def(dp
->ovly
.field
,field
);
540 if( v4l_fld_is_laced(field
) > 0 && v4l_flds_per_bfr(field
) == 1 )
542 if( df_set_video_scale(src_w
,src_h
,dst_w
,dst_h
,
543 DF_SCALEFLAG_CHANGEX
| DF_SCALEFLAG_CHANGEY
) != 0 )
546 dp
->ovly_bob_dy
= dst_h
/ (2*src_h
);
547 DMSG(3,"lx_ovly_set_scale src %dx%d dst %dx%d\n",src_w
,src_h
,dst_w
,dst_h
);
551 /** lx_ovly_start - enable overlay */
553 lx_ovly_start(VidDevice
*dp
)
556 ret
= lx_ovly_set_scale(dp
,dp
->ovly_src
.w
,dp
->ovly_src
.h
,dp
->ovly_dst
.w
,dp
->ovly_dst
.h
);
557 if( ret
!= 0 ) return ret
;
558 df_set_video_filter_coefficients(NULL
, 1);
559 /* if any alpha windows active, must disable per pixel alpha blending */
560 for( n
=i
=0; i
<3; ++i
)
561 n
+= df_get_alpha_window_enable(i
);
562 df_set_video_enable(1,n
==0 ? 0 : DF_ENABLEFLAG_NOCOLORKEY
);
566 /** lx_ovly_stop - disable overlay */
568 lx_ovly_stop(VidDevice
*dp
)
570 df_set_video_enable(0,0);
574 /** lx_ovly_is_supported_format - test format supported by hw */
576 lx_ovly_is_supported_format(VidDevice
*dp
,int fmt
)
578 return lx_ovly_hw_fmt(dp
,fmt
) >= 0 ? 1 : 0;
581 /** lx_ovly_is_supported_depth - test depth supported by hw
582 * this function is obsolete and broken. There is no
583 * such thing as depth since pixels are "macropixels" and
584 * potentially spread over parameter spaces
587 lx_ovly_is_supported_depth(VidDevice
*dp
,int depth
)
589 return depth
== 16 ? 1 : 0;
592 /** lx_ovly_min_rect - return min overlay geometry */
594 lx_ovly_min_rect(VidDevice
*dp
,int *w
, int *h
)
599 /** lx_ovly_max_rect - return max overlay geometry */
601 lx_ovly_max_rect(VidDevice
*dp
,int *w
, int *h
)
603 *w
= 2*1920; *h
= 2*1080;
606 /** lx_ovly_get_format - enumerate video formats */
608 lx_ovly_get_format(VidDevice
*dp
,int index
, struct v4l2_fmtdesc
*fmt
)
611 unsigned int pixelformat
;
613 memset(fmt
,0,sizeof(*fmt
));
615 n
= dp
->ovly_formats
;
616 for( idx
=0,i
=sizeof(n
)*8; --i
>=0; n
>>=1,++idx
) {
617 if( (n
&1) == 0 ) continue;
618 if( --index
< 0 ) break;
621 case 0: pixelformat
= V4L2_PIX_FMT_UYVY
; cp
= "UYVY"; break;
622 case 1: pixelformat
= V4L2_PIX_FMT_YUYV
; cp
= "YUY2"; break;
623 case 2: pixelformat
= V4L2_PIX_FMT_YUV420
; cp
= "YUV 4:2:0"; break;
624 case 3: pixelformat
= V4L2_PIX_FMT_YVU420
; cp
= "YVU 4:2:0"; break;
625 case 4: pixelformat
= V4L2_PIX_FMT_RGB565
; cp
= "RGB 16bit"; break;
626 // case 5: pixelformat = V4L2_PIX_FMT_YUV422P; cp = "YUV 4:2:2"; break;
630 fmt
->pixelformat
= pixelformat
;
631 snprintf(&fmt
->description
[0],sizeof(fmt
->description
),"%s", cp
);
633 fmt
->type
= V4L2_BUF_TYPE_VIDEO_OVERLAY
;
640 /** lx_ovly_hw_fmt - map pixelformat to cimarron format */
642 lx_ovly_hw_fmt(VidDevice
*dp
,int fmt
)
646 case V4L2_PIX_FMT_YUYV
: hw_fmt
= DF_VIDFMT_YUYV
; n
= 0; break;
647 case V4L2_PIX_FMT_UYVY
: hw_fmt
= DF_VIDFMT_UYVY
; n
= 1; break;
648 case V4L2_PIX_FMT_YUV420
: hw_fmt
= DF_VIDFMT_Y0Y1Y2Y3
; n
= 2; break;
649 case V4L2_PIX_FMT_YVU420
: hw_fmt
= DF_VIDFMT_Y0Y1Y2Y3
; n
= 3; break;
650 case V4L2_PIX_FMT_RGB565
: hw_fmt
= DF_VIDFMT_RGB
; n
= 4; break;
651 // case V4L2_PIX_FMT_YUV422P: hw_fmt = DF_VIDFMT_YUYV; n = 5; break;
655 return ((dp
->ovly_formats
>>n
)&1) != 0 ? hw_fmt
: -1;
658 /** lx_ovly_reset_dst_rect - apply current ovly cimaaron position data */
659 /* unfortunately, this routine is needed to set the src x, because it
660 uses df_set_video_postion. So it will be called in cases both of
661 src/dst geometry updates */
663 lx_ovly_reset_dst_rect(VidDevice
*dp
,int py
)
667 Rect
*src
= &dp
->ovly_src
;
668 Rect
*dst
= &dp
->ovly_dst
;
669 DF_VIDEO_POSITION pos
;
670 memset(&pos
,0,sizeof(pos
));
671 if( (xofs
=-dst
->x
) < 0 ) xofs
= 0;
672 if( (yofs
=-dst
->y
) < 0 ) yofs
= 0;
673 x
= dst
->x
+ xofs
; y
= dst
->y
+ yofs
;
674 w
= dst
->w
- xofs
; h
= dst
->h
- yofs
;
675 /* only works to multple of 4, unless on left edge */
676 pos
.left_clip
= src
->x
+ xofs
*src
->w
/dst
->w
;
677 /* if displaying on the left edge, start video early to clip video grain */
678 pos
.dst_clip
= x
== 0 ? (pos
.left_clip
&3)*dst
->w
/src
->w
: 0;
679 pos
.flags
|= DF_POSFLAG_DIRECTCLIP
;
680 pos
.x
= x
; pos
.y
= y
+py
;
681 pos
.width
= w
; pos
.height
= h
;
682 df_set_video_position(&pos
);
685 /** lx_ovly_set_dst_rect - update ovly dst rect, apply and scale */
687 lx_ovly_set_dst_rect(VidDevice
*dp
,int x
, int y
, int w
, int h
)
690 Rect
*src
= &dp
->ovly_src
;
691 Rect
*dst
= &dp
->ovly_dst
;
693 dst
->x
= x
; dst
->y
= y
;
694 dst
->w
= w
; dst
->h
= h
;
696 ret
= lx_ovly_set_src_rect(dp
,src
->x
,src
->y
,src
->w
,src
->h
);
697 DMSG(4,"lx_ovly_set_dst_rect src %d,%d %dx%d dst %d,%d %dx%d = %d\n",
698 src
->x
,src
->y
,src
->w
,src
->h
,dst
->x
,dst
->y
,dst
->w
,dst
->h
,ret
);
699 if( ret
!= 0 ) *dst
= orig
;
703 /** lx_ovly_set_offsets - update ovly buffer device parameters
704 * offsets are recalculated, device format reset
707 lx_ovly_set_offsets(VidDevice
*dp
)
710 unsigned long imgsz
, offset1
, offset2
, y_imgsz
, uv_imgsz
;
711 unsigned long u_offset
, v_offset
, oy_offset
, ey_offset
;
712 unsigned int ovly_pixelformat
= dp
->ovly_pixelformat
;
713 Rect
*src
= &dp
->ovly_src
;
714 Rect
*dst
= &dp
->ovly_dst
;
715 int dy
= dst
->y
>= 0 ? 0 : (-dst
->y
*src
->h
)/dst
->h
;
716 int y
= dp
->ovly_src
.y
+ dy
;
718 int width
= dp
->ovly
.w
.width
;
719 int height
= dp
->ovly
.w
.height
;
721 int width
= dp
->ovly
.width
;
722 int height
= dp
->ovly
.height
;
724 unsigned long y_pitch
= lx_ovly_ypitch(dp
,width
);
725 unsigned long uv_pitch
= lx_ovly_uvpitch(dp
,width
);
726 int video_format
= lx_ovly_hw_fmt(dp
,ovly_pixelformat
);
727 offset1
= offset2
= u_offset
= v_offset
= 0;
728 /* default is capt format, if not in spec */
729 field
= v4l_vid_field(&dp
->capt
);
730 field
= v4l_vid_field_def(field
,dp
->capt_dft_field
);
732 field
= v4l_vid_field_def(dp
->ovly
.field
,field
);
734 if( (scale
=v4l_flds_per_bfr(field
)) > 0 )
736 y_imgsz
= y_pitch
*height
;
737 uv_imgsz
= uv_pitch
*height
;
738 if( v4l_fmt_is_420(ovly_pixelformat
) > 0 ) {
739 y
&= ~1; /* design limitation */
742 imgsz
= y_imgsz
+ 2*uv_imgsz
;
743 if( scale
== 1 ) y
/= 2;
744 oy_offset
= y
*y_pitch
;
745 ey_offset
= oy_offset
;
747 case V4L2_FIELD_SEQ_BT
: /* same + bottom-top */
748 if( lx_display_is_interlaced() != 0 )
751 case V4L2_FIELD_SEQ_TB
: /* both fields seq 1 bfr, top-bottom */
752 if( lx_display_is_interlaced() != 0 )
755 case V4L2_FIELD_INTERLACED
: /* both fields interlaced */
758 ey_offset
+= y_pitch
;
759 if( lx_display_is_interlaced() != 0 ) {
764 case V4L2_FIELD_TOP
: /* top field only */
765 case V4L2_FIELD_BOTTOM
: /* bottom field only */
766 case V4L2_FIELD_ALTERNATE
: /* both fields alternating 2 buffers */
767 case V4L2_FIELD_NONE
: /* counts as progressive */
770 if( v4l_fmt_is_planar(ovly_pixelformat
) > 0 ) {
771 if( v4l_fmt_is_420(ovly_pixelformat
) > 0 ) y
/= 2;
772 offset1
= y_imgsz
+ y
*uv_pitch
;
773 offset2
= y_imgsz
+ uv_imgsz
+ y
*uv_pitch
;
775 switch( ovly_pixelformat
) {
776 case V4L2_PIX_FMT_YVU420
:
780 case V4L2_PIX_FMT_YUV422P
:
781 case V4L2_PIX_FMT_YUV420
:
787 dp
->ovly_format
= video_format
;
788 dp
->ovly_ey_offset
= ey_offset
;
789 dp
->ovly_oy_offset
= oy_offset
;
790 dp
->ovly_u_offset
= u_offset
;
791 dp
->ovly_v_offset
= v_offset
;
792 dp
->ovly_y_pitch
= y_pitch
;
793 dp
->ovly_uv_pitch
= uv_pitch
;
794 dp
->ovly_width
= width
;
795 dp
->ovly_height
= height
;
797 if( is_reported
== 0 ) {
799 DMSG(1,"lx_ovly_set_offsets bfr %d,%d %dx%d src %d,%d %dx%d dst %d,%d %dx%d\n",
800 dp
->ovly
.w
.left
,dp
->ovly
.w
.top
,dp
->ovly
.w
.width
,dp
->ovly
.w
.height
,
801 dp
->ovly_src
.x
,dp
->ovly_src
.y
,dp
->ovly_src
.w
,dp
->ovly_src
.h
,
802 dp
->ovly_dst
.x
,dp
->ovly_dst
.y
,dp
->ovly_dst
.w
,dp
->ovly_dst
.h
);
804 DMSG(1,"lx_ovly_set_offsets bfr %d,%d %dx%d src %d,%d %dx%d dst %d,%d %dx%d\n",
805 dp
->ovly
.x
,dp
->ovly
.y
,dp
->ovly
.width
,dp
->ovly
.height
,
806 dp
->ovly_src
.x
,dp
->ovly_src
.y
,dp
->ovly_src
.w
,dp
->ovly_src
.h
,
807 dp
->ovly_dst
.x
,dp
->ovly_dst
.y
,dp
->ovly_dst
.w
,dp
->ovly_dst
.h
);
813 /** lx_ovly_set_bfr - device offsets/format updated
814 * phys address used to specify ovly buffer base
817 lx_ovly_set_bfr(VidDevice
*dp
,unsigned long phys_addr
)
819 int flags
, colorspace
;
820 DF_VIDEO_SOURCE_PARAMS odd
, even
;
821 unsigned long fb_base
, offset
;
822 DMSG(5," addr %08lx fmt %d %dx%d oy %x ey %x u %x v %x yp %x uvp %x\n",
823 phys_addr
, dp
->ovly_format
, dp
->ovly_width
,dp
->ovly_height
,
824 dp
->ovly_oy_offset
,dp
->ovly_ey_offset
, dp
->ovly_u_offset
,dp
->ovly_v_offset
,
825 dp
->ovly_y_pitch
, dp
->ovly_uv_pitch
);
827 fb_base
= cim_get_fb_base();
828 if( phys_addr
< fb_base
) return -EINVAL
;
829 offset
= phys_addr
- fb_base
;
830 if( offset
>= cim_get_fb_size() ) return -EINVAL
;
832 colorspace
= dp
->ovly_colorspace
;
833 flags
= colorspace
== V4L2_COLORSPACE_REC709
? DF_SOURCEFLAG_HDTVSOURCE
: 0;
834 flags
|= DF_SOURCEFLAG_IMPLICITSCALING
;
836 odd
.video_format
= even
.video_format
= dp
->ovly_format
;
837 odd
.y_offset
= dp
->ovly_oy_offset
+ offset
;
838 even
.y_offset
= dp
->ovly_ey_offset
+ offset
;
839 odd
.u_offset
= even
.u_offset
= dp
->ovly_u_offset
+ offset
;
840 odd
.v_offset
= even
.v_offset
= dp
->ovly_v_offset
+ offset
;
841 odd
.y_pitch
= even
.y_pitch
= dp
->ovly_y_pitch
;
842 odd
.uv_pitch
= even
.uv_pitch
= dp
->ovly_uv_pitch
;
843 odd
.width
= even
.width
= dp
->ovly_width
;
844 odd
.height
= even
.height
= dp
->ovly_height
;
845 odd
.flags
= even
.flags
= flags
;
847 df_configure_video_source(&odd
,&even
);
848 dp
->ovly_phys_addr
= phys_addr
;
852 /** lx_ovly_set_src_rect - update ovly src rect, recalc offsets and scale */
854 lx_ovly_set_src_rect(VidDevice
*dp
,int x
,int y
,int w
,int h
)
856 int width
, height
, ret
;
857 Rect
*src
= &dp
->ovly_src
;
858 Rect
*dst
= &dp
->ovly_dst
;
859 lx_ovly_min_rect(dp
,&width
,&height
);
860 if( w
< width
) w
= width
;
861 if( h
< height
) h
= height
;
862 DMSG(1,"lx_ovly_set_src_rect(%d,%d %dx%d)\n",x
,y
,w
,h
);
863 ret
= lx_ovly_set_scale(dp
,w
,h
,dst
->w
,dst
->h
);
864 if( ret
!= 0 ) return ret
;
865 src
->x
= x
; src
->y
= y
;
866 src
->w
= w
; src
->h
= h
;
868 lx_ovly_set_offsets(dp
); /* set src y coord */
869 if( dp
->ovly_addr_is_set
!= 0 )
870 lx_ovly_set_bfr(dp
,dp
->ovly_phys_addr
);
871 lx_ovly_reset_dst_rect(dp
,0); /* set dst rect, set src x coord */
875 /** lx_ovly_validate_format - validate format parameters, modify to valid */
876 void lx_ovly_validate_window(VidDevice
*dp
,unsigned int pixfmt
, struct v4l2_window
*win
)
882 int width
= win
->w
.width
;
883 int height
= win
->w
.height
;
887 int width
= win
->width
;
888 int height
= win
->height
;
890 int key
= win
->chromakey
;
891 lx_ovly_min_rect(dp
,&w
,&h
);
892 if( width
< w
) width
= w
;
893 if( height
< h
) height
= h
;
894 lx_ovly_max_rect(dp
,&w
,&h
);
895 if( width
> w
) width
= w
;
896 if( height
> h
) height
= h
;
897 memset(win
,0,sizeof(*win
));
899 if( lx_capt_std_progressive(dp
,dp
->std_index
) != 0 )
900 win
->field
= V4L2_FIELD_NONE
;
901 else if( win
->field
== V4L2_FIELD_NONE
|| win
->field
== V4L2_FIELD_ANY
)
902 win
->field
= V4L2_FIELD_INTERLACED
;
905 win
->w
.width
= width
;
906 win
->w
.height
= height
;
911 win
->height
= height
;
913 win
->chromakey
= key
;
916 /** lx_ovly_ypitch - return overlay y_image pitch */
917 int lx_ovly_ypitch(VidDevice
*dp
,int width
)
919 return v4l_vid_ypitch(dp
->ovly_pixelformat
,width
);
922 /** lx_ovly_uvpitch - return overlay uv_image pitch */
923 int lx_ovly_uvpitch(VidDevice
*dp
,int width
)
925 return v4l_vid_uvpitch(dp
->ovly_pixelformat
,width
);
928 /* report hardware characteristics */
929 int lx_ovly_has_chomakey(void) { return 1; }
930 int lx_ovly_has_clipping(void) { return 0; }
931 int lx_ovly_has_scaleup(void) { return 1; }
932 int lx_ovly_has_scaledn(void) { return 1; }
934 /** lx_ovly_palette - reload video pallete using control params */
935 void lx_ovly_palette(VidDevice
*dp
)
938 unsigned int red
, blue
;
939 unsigned long palette
[256];
940 int contrast
= (32768-dp
->ovly_contrast
) * 2;
941 int blackLvl
= dp
->ovly_blackLvl
- 32768;
942 int brightness
= (dp
->ovly_brightness
* (dp
->ovly_brightness
/128)) / 256;
943 int redGain
= (dp
->ovly_redGain
* (dp
->ovly_redGain
/128)) / 256;
944 int blueGain
= (dp
->ovly_blueGain
* (dp
->ovly_blueGain
/128)) / 256;
945 for( x
=0; x
<256; ++x
) {
946 wt
= (x
*(256-x
))/(256/4);
947 wt
= (wt
*contrast
)/32768;
948 w
= (x
*(256-wt
) + 128*wt
) / 256;
949 y
= ((brightness
*w
)/128 + blackLvl
) / 256;
951 if( y
> 255 ) y
= 255;
952 red
= (y
*redGain
)/32768;
953 if( red
> 255 ) red
= 255;
954 blue
= (y
*blueGain
)/32768;
955 if( blue
> 255 ) blue
= 255;
956 palette
[x
] = (red
<<16) + (y
<<8) + blue
;
958 df_set_video_palette(&palette
[0]);
961 /** lx_ovly_chromakey - disable/enable overlay color/chroma key */
962 void lx_ovly_chromakey(VidDevice
*dp
,int key
,int mask
,int enable
)
965 df_set_video_color_key(0,0,1);
967 df_set_video_color_key(key
,mask
,1);
970 int lx_set_alpha_window(struct v4l2_alpha_window
*awin
)
973 window
= awin
->window
;
974 if( awin
->priority
>= 0 ) {
975 DF_ALPHA_REGION_PARAMS dap
;
979 dap
.height
= awin
->h
;
980 dap
.alpha_value
= awin
->alpha
;
981 dap
.priority
= awin
->priority
;
982 dap
.color
= awin
->color
;
983 dap
.flags
= awin
->flags
;
984 dap
.delta
= awin
->delta
;
985 if( df_configure_alpha_window(window
,&dap
) != 0 )
991 if( df_set_alpha_window_enable(window
,enable
) != 0 )
996 /* not yet implemented */
997 int lx_vbi_start(VbiDevice
*dp
) { return 0; }
998 void lx_vbi_stop(VbiDevice
*dp
) { return; }
999 long lx_vbi_write(VbiDevice
*fp
,char *buf
,unsigned long count
,int nonblock
) { return 0; }
1000 long lx_vbi_read(VbiDevice
*fp
,char *buf
,unsigned long count
,int nonblock
) { return 0; }
1001 int lx_vbi_poll(VbiDevice
*fp
, struct file
*file
, poll_table
*wait
) { return 0; }
1002 int lx_vbi_get_buf_size(FilePriv
*fp
) { return 0; }
1004 /** lx_interrupt - vip interrupt handler */
1005 static irqreturn_t
lx_interrupt(int irq
, void *dev_id
)
1007 unsigned long status
= vip_get_interrupt_state();
1008 unsigned long offset
, y_offset
, u_offset
, v_offset
;
1009 unsigned long sequence
, dt
; jiffiez_t jiffy_time
;
1010 long numer
; long long denom
;
1011 int stalled
, dy
, wake
, even
, active
, skip
;
1012 int even_index
, show_even
, show_odd
, latched
;
1013 V4LDevice
*dev
= (V4LDevice
*)dev_id
;
1014 VidDevice
*dp
= &dev
->vid
;
1015 FilePriv
*fp
= &dp
->fp
;
1016 io_queue
*io
= fp
->io
;
1019 DMSG(9,"lx_interrupt: enter irq handler with status %lu\n", status
);
1020 status
&= VIP_ALL_INTERRUPTS
;
1021 if( status
== 0 ) return IRQ_NONE
; /* spurious/shared */
1022 dev
->irq_status
= status
;
1024 /* report any unexpected status */
1025 while( status
!= 0 ) {
1026 unsigned long stat
= status
& ~(status
-1);
1029 case VIP_INT_FIFO_WRAP
:
1030 DMSG(1,"VIP_INT_FIFO_WRAP\n");
1033 case VIP_INT_LONGLINE
:
1034 DMSG(1,"VIP_INT_LONGLINE\n");
1037 case VIP_INT_ACTIVE_PIXELS
:
1038 DMSG(1,"VIP_INT_ACTIVE_PIXELS\n");
1041 case VIP_INT_CLOCK_INPUT
:
1042 DMSG(1,"VIP_INT_CLOCK_INPUT\n");
1043 vip_set_interrupt_enable(ERR_INT_ENABLES
,0);
1044 vip_set_capture_state(VIP_STOPCAPTURE
);
1045 dp
->capt_no_clocks
= 1;
1050 active
= VIP_INT_START_EVEN
| VIP_INT_START_ODD
| VIP_INT_START_VBLANK
;
1051 if( (active
&= dev
->irq_status
) == 0 ) goto xit
;
1053 if( dp
->capt_no_clocks
!= 0 ) {
1054 DMSG(9,"lx_interrupt: capt_no_clocks = %d\n", (int)dp
->capt_no_clocks
);
1055 dp
->capt_no_clocks
= 0;
1056 vip_set_interrupt_enable(ERR_INT_ENABLES
,1);
1057 vip_set_capture_state(VIP_STARTCAPTUREATNEXTFIELD
);
1063 latched
= vip_is_buffer_update_latched() != 0 ? 1 : 0;
1064 even
= (dev
->irq_status
& VIP_INT_START_EVEN
) != 0 ? 1 : 0;
1065 jiffy_time
= jiffiez
;
1066 if( dp
->capt_num
!= 0 && dp
->capt_denom
!= 0 ) {
1067 numer
= dp
->capt_num
; denom
= dp
->capt_denom
;
1068 dt
= jiffy_time
- dp
->capt_jiffy_start
;
1070 do_div(denom
,numer
);
1072 /* if seq_no ahead of rate spec, drop frame */
1073 if( dp
->capt_jiffy_sequence
> sequence
) skip
= 1;
1074 DMSG(9," seq %d dt(%lu)=%llu-%llu, cseq(%lu)=(%lu*%d)/%d) jseq(%lu) skip(%d)\n",
1075 dp
->capt_sequence
,dt
,(unsigned long long)jiffy_time
,
1076 (unsigned long long)dp
->capt_jiffy_start
,
1077 sequence
,dt
,dp
->capt_denom
,dp
->capt_num
,dp
->capt_jiffy_sequence
,skip
);
1079 DMSG(8," frame %d seq %d obfr %d ebfr %d onxt %d enxt %d t %d e %d l %d\n",
1080 dp
->capt_frame
,dp
->capt_sequence
,
1081 dp
->capt_obfr
?dp
->capt_obfr
->index
:-1,
1082 dp
->capt_ebfr
?dp
->capt_ebfr
->index
:-1,
1083 dp
->capt_onxt
?dp
->capt_onxt
->index
:-1,
1084 dp
->capt_enxt
?dp
->capt_enxt
->index
:-1,
1085 dp
->capt_toggle
,even
,latched
);
1086 if( dp
->capt_addr_is_set
== 0 ) {
1087 if( io
!= NULL
) { /* queued/flipped io */
1088 if( latched
!= 0 ) {
1089 /* if loaded and latched */
1090 if( dp
->capt_onxt
!= NULL
&& dp
->capt_obfr
== NULL
) {
1091 /* propagate odd buffers */
1092 dp
->capt_obfr
= dp
->capt_olch
;
1093 dp
->ovly_obfr
= dp
->capt_olch
;
1094 dp
->capt_olch
= dp
->capt_onxt
;
1095 if( (bp
=dp
->capt_olch
) != NULL
)
1096 bp
->jiffies
= jiffy_time
;
1097 dp
->capt_onxt
= NULL
;
1099 if( dp
->capt_enxt
!= NULL
&& dp
->capt_ebfr
== NULL
) {
1100 /* propagate even buffers */
1101 dp
->capt_ebfr
= dp
->capt_elch
;
1102 dp
->ovly_ebfr
= dp
->capt_elch
;
1103 dp
->capt_elch
= dp
->capt_enxt
;
1104 if( (bp
=dp
->capt_elch
) != NULL
)
1105 bp
->jiffies
= jiffy_time
;
1106 dp
->capt_enxt
= NULL
;
1109 /* if autoflipping, display finished buffer */
1110 if( io
->io_type
== io_flipped
) {
1112 if( lx_display_is_interlaced() != 0 ) {
1114 show_even
= show_odd
= 1;
1116 else if( dp
->ovly_obfr
!= dp
->ovly_ebfr
) {
1117 show_even
= even
!= 0 ? 1 : 0;
1118 show_odd
= 1 - show_even
;
1121 show_odd
= 1; show_even
= 0;
1122 dp
->ovly_ebfr
= NULL
;
1124 if( show_odd
!= 0 && (bp
=dp
->ovly_obfr
) != NULL
) {
1125 dp
->ovly_obfr
= NULL
;
1126 offset
= bp
->offset
+ vid_mem_ofst();
1127 y_offset
= offset
+ dp
->ovly_oy_offset
;
1128 u_offset
= offset
+ dp
->ovly_u_offset
;
1129 v_offset
= offset
+ dp
->ovly_v_offset
;
1130 df_set_video_offsets(0,y_offset
,u_offset
,v_offset
);
1132 if( show_even
!= 0 && (bp
=dp
->ovly_ebfr
) != NULL
) {
1133 dp
->ovly_ebfr
= NULL
;
1134 offset
= bp
->offset
+ vid_mem_ofst();
1135 y_offset
= offset
+ dp
->ovly_ey_offset
;
1136 u_offset
= offset
+ dp
->ovly_u_offset
;
1137 v_offset
= offset
+ dp
->ovly_v_offset
;
1138 df_set_video_offsets(even_index
,y_offset
,u_offset
,v_offset
);
1140 /* if autoflipping, and "bob"ing */
1141 if( dp
->ovly_bobbing
!= 0 ) {
1142 dy
= even
!= 0 ? dp
->ovly_bob_dy
: 0;
1143 lx_ovly_reset_dst_rect(dp
,dy
);
1145 if( (bp
=dp
->capt_obfr
) != NULL
) {
1146 dp
->capt_obfr
= NULL
;
1147 if( dp
->capt_toggle
!= capt_toggle_both
)
1148 dp
->capt_ebfr
= NULL
;
1149 list_add_tail(&bp
->bfrq
,&io
->rd_qbuf
);
1151 if( (bp
=dp
->capt_ebfr
) != NULL
) {
1152 dp
->capt_ebfr
= NULL
;
1153 list_add_tail(&bp
->bfrq
,&io
->rd_qbuf
);
1156 /* if buffer deliverable */
1157 if( (dev
->irq_status
&capt_bfr_mask
[dp
->capt_toggle
]) != 0 ) {
1158 if( (bp
=dp
->capt_obfr
) != NULL
) {
1159 dp
->capt_obfr
= NULL
;
1160 if( dp
->capt_toggle
!= capt_toggle_both
)
1161 dp
->capt_ebfr
= NULL
;
1162 /* if not autoflipping, deliver buffer */
1163 if( io
->io_type
!= io_flipped
) {
1164 list_add_tail(&bp
->bfrq
,&io
->rd_dqbuf
);
1165 bp
->flags
&= ~V4L2_BUF_FLAG_QUEUED
;
1167 bp
->flags
&= ~(V4L2_BUF_FLAG_TOPFIELD
|V4L2_BUF_FLAG_BOTFIELD
);
1168 if( dp
->capt_toggle
== capt_toggle_both
)
1169 bp
->flags
|= V4L2_BUF_FLAG_TOPFIELD
;
1171 bp
->flags
|= V4L2_BUF_FLAG_DONE
;
1175 if( (bp
=dp
->capt_ebfr
) != NULL
) {
1176 dp
->capt_ebfr
= NULL
;
1177 /* if not autoflipping, deliver buffer */
1178 if( io
->io_type
!= io_flipped
) {
1179 list_add_tail(&bp
->bfrq
,&io
->rd_dqbuf
);
1180 bp
->flags
&= ~V4L2_BUF_FLAG_QUEUED
;
1182 bp
->flags
&= ~(V4L2_BUF_FLAG_TOPFIELD
|V4L2_BUF_FLAG_BOTFIELD
);
1183 if( dp
->capt_toggle
== capt_toggle_both
)
1184 bp
->flags
|= V4L2_BUF_FLAG_BOTFIELD
;
1186 bp
->flags
|= V4L2_BUF_FLAG_DONE
;
1191 /* if end of frame */
1192 if( even
!= 0 || dp
->capt_toggle
== capt_toggle_vblank
) {
1193 if( latched
!= 0 && skip
!= 0 ) ++dp
->capt_skipped
;
1194 ++dp
->capt_frame
; /* update stats */
1196 /* printk("capt e %d o %d\n",
1197 dp->ovly_ebfr!=NULL?dp->ovly_ebfr->index:-1,
1198 dp->ovly_obfr!=NULL?dp->ovly_obfr->index:-1); */
1199 if( skip
== 0 ) { /* if not downsampling, load next buffers */
1200 stalled
= dp
->capt_stalled
;
1201 if( lx_capt_resume2(dp
,io
) == 0 ) {
1203 DMSG(4,"stalled\n");
1204 else if( even
== 0 )
1210 DMSG(0,"capture active with no buffer!\n");
1214 else { /* point and shoot buffer capture */
1215 if( vip_is_buffer_update_latched() != 0 )
1216 lx_capt_resume(dp
,io
);
1217 if( even
!= 0 || dp
->capt_toggle
== capt_toggle_vblank
)
1219 ++dp
->capt_sequence
;
1223 /* if buffer queued/captured, wake up waiting task */
1225 if( waitqueue_active(&dp
->capt_wait
) != 0 )
1226 wake_up_interruptible(&dp
->capt_wait
);
1230 vip_reset_interrupt_state(dev
->irq_status
);
1235 /** lx_capt_resume2 - queue capture buffers to vip */
1237 lx_capt_resume2(VidDevice
*dp
,io_queue
*io
)
1240 int eidx
, oidx
, vip_buffers
;
1242 int task_buffers
= vip_task_data
[task
].task_buffers
;
1243 VIPINPUTBUFFER
*vip_inpbfr
;
1245 unsigned long flags
;
1246 struct list_head
*lp
;
1248 if(dp
==NULL
) return 0;
1249 if(io
==NULL
) return 0;
1250 task
= dp
->capt_vip_task
;
1251 vip_inpbfr
= &dp
->vip_inpbfr
;
1253 dp
->capt_stalled
= 1;
1254 task
= dp
->capt_vip_task
;
1255 task_buffers
= vip_task_data
[task
].task_buffers
;
1257 if( dp
->capt_addr_is_set
== 0 ) {
1258 op
= dp
->capt_toggle
== capt_toggle_odd
? dp
->capt_elch
: dp
->capt_onxt
;
1260 if( list_empty(&io
->rd_qbuf
) != 0 )
1262 // there are no more buffers into the input list for grabbing images,
1263 // so requeue first output buffer into input list
1265 spin_lock_irqsave(&io
->lock
, flags
);
1268 if( ! list_empty(lp
) ) {
1269 bp1
= list_entry(lp
->next
,io_buf
,bfrq
); // get the struct for this entry / list_entry ( ptr, type, member) &struct list_head pointer/ type of the struct this is embedded in/ name of the list_struct within the struct.
1270 list_del_init(&bp1
->bfrq
); //deletes entry from list and reinitialize it
1273 spin_unlock_irqrestore(&io
->lock
,flags
);
1278 list_move_tail(&bp1
->bfrq
,lp
);
1280 bp1
->sequence
= io
->sequence
++;
1281 bp1
->flags
&= ~V4L2_BUF_FLAG_DONE
;
1282 bp1
->flags
|= V4L2_BUF_FLAG_QUEUED
;
1284 if( dp
->capt_stalled
!= 0 )
1286 DMSG(3,"------------ v4l_qbfr : capt != 0 && dp->capt_stalled != 0\n");
1287 //v4l_capt_unstall(dp);
1290 spin_unlock_irqrestore(&io
->lock
,flags
);
1294 op
= list_entry(io
->rd_qbuf
.next
,io_buf
,bfrq
);
1295 list_del_init(&op
->bfrq
);
1297 if( dp
->capt_toggle
== capt_toggle_both
||
1298 dp
->capt_toggle
== capt_toggle_odd
) {
1299 if( (ep
=dp
->capt_enxt
) == NULL
) {
1300 if( list_empty(&io
->rd_qbuf
) != 0 ) {
1301 list_add(&op
->bfrq
,&io
->rd_qbuf
);
1304 ep
= list_entry(io
->rd_qbuf
.next
,io_buf
,bfrq
);
1305 list_del_init(&ep
->bfrq
);
1312 dp
->capt_onxt
= op
; oidx
= op
->index
;
1313 dp
->capt_enxt
= ep
; eidx
= ep
->index
;
1320 if( oidx
!= eidx
) {
1321 vip_inpbfr
->current_buffer
= eidx
;
1322 vip_buffers
= vip_task_data
[task
].vip_even_buffers
;
1323 vip_toggle_video_offsets(vip_buffers
,vip_inpbfr
);
1324 vip_inpbfr
->current_buffer
= oidx
;
1325 vip_buffers
= vip_task_data
[task
].vip_odd_buffers
;
1326 vip_toggle_video_offsets(vip_buffers
,vip_inpbfr
);
1329 vip_inpbfr
->current_buffer
= oidx
;
1330 vip_buffers
= vip_task_data
[task
].vip_buffers
;
1331 vip_toggle_video_offsets(vip_buffers
,vip_inpbfr
);
1333 dp
->capt_stalled
= 0;
1335 ++dp
->capt_sequence
;
1336 ++dp
->capt_jiffy_sequence
;
1344 /** lx_init - hookup interrupt and cimarron kernel resources */
1345 int lx_init(struct pci_dev
*pci
, const struct pci_device_id
*pdp
)
1350 dev
= v4l_dev_init();
1355 irq
= dev
->irq
= pci
->irq
;
1356 printk("Found Geode LX VIP at IRQ %d\n", (int)dev
->irq
);
1359 printk("Forcing Geode LX VIP IRQ to %d\n", (int)dev
->irq
);
1362 ret
= request_irq(dev
->irq
, lx_interrupt
, IRQF_SHARED
, v4l_name(), dev
);
1363 if( ret
!= 0 ) return ret
;
1365 if( cim_get_vip_ptr() == NULL
) {
1366 DMSG(0,"cant access cimarron video memory\n");
1370 df_set_video_palette(NULL
);
1374 /** lx_exit - free interrupt */
1375 void lx_exit(struct pci_dev
*pci
)
1378 free_irq(lx_dev
->irq
, lx_dev
);
1382 static struct pci_device_id lx_pci_tbl
[] = {
1383 { PCI_VENDOR_ID_AMD
, PCI_DEVICE_ID_LX3_VIDEO
, PCI_ANY_ID
, PCI_ANY_ID
, 0, 0, 0},
1387 /** lx_init - hookup interrupt and cimarron kernel resources */
1388 int lx_init(V4LDevice
*dev
)
1391 struct pci_dev
*pci
= NULL
;
1392 const struct pci_device_id
*pdp
= NULL
;
1395 while( (pci
=pci_get_device(PCI_VENDOR_ID_AMD
, PCI_ANY_ID
, pci
)) != NULL
)
1397 pci_for_each_dev(pci
)
1400 pdp
= pci_match_id(&lx_pci_tbl
[0], pci
);
1401 if( pdp
!= NULL
) break;
1404 DMSG(0,"cant find video device\n");
1409 if( dev
->irq
< 0 ) {
1410 dev
->irq
= pci
->irq
;
1411 printk("Found Geode LX VIP at IRQ %d\n", (int)dev
->irq
);
1413 ret
= request_irq(dev
->irq
, lx_interrupt
, IRQF_SHARED
, v4l_name(), dev
);
1414 if( ret
!= 0 ) return ret
;
1416 if( cim_get_vip_ptr() == NULL
) {
1417 DMSG(0,"cant access cimarron video memory\n");
1421 df_set_video_palette(NULL
);
1425 /** lx_exit - free interrupt */
1426 void lx_exit(V4LDevice
*dev
)
1428 free_irq(dev
->irq
, dev
);