added 2.6.29.6 aldebaran kernel
[nao-ulib.git] / kernel / 2.6.29.6-aldebaran-rt / drivers / media / video / lxv4l2 / lx.c
blob86bb737b5433801ee4b3aed2227193d757dfd40f
1 /* <LIC_AMD_STD>
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
19 * file called COPYING
20 * </LIC_AMD_STD> */
21 /* <CTL_AMD_STD>
22 * </CTL_AMD_STD> */
23 /* <DOC_AMD_STD>
24 * lx device level interface
25 * for v4l/2 linux driver
26 * interfaces to cimarron hardware api
27 * </DOC_AMD_STD> */
29 #include "v4l.h"
31 /* handled errors */
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 {
41 int width;
42 int height;
43 int progressive;
44 int rate;
45 int vip_version;
46 int port_size;
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 */
59 static struct {
60 int enables;
61 int task_buffers;
62 int vip_buffers;
63 int vip_odd_buffers;
64 int vip_even_buffers;
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 */
82 int
83 lx_capt_resume(VidDevice *dp,io_queue *io)
85 io_buf *op, *ep;
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;
90 dp->capt_stalled = 1;
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;
96 if( op == NULL ) {
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);
106 return 0;
108 ep = list_entry(io->rd_qbuf.next,io_buf,bfrq);
109 list_del_init(&ep->bfrq);
112 else
113 ep = op;
114 dp->capt_onxt = op; oidx = op->index;
115 dp->capt_enxt = ep; eidx = ep->index;
117 else
118 oidx = eidx = 0;
120 if( oidx != eidx ) {
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);
128 else {
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;
135 ++dp->capt_sequence;
136 ++dp->capt_jiffy_sequence;
137 return 1;
140 /** lx_capt_start - start capture
141 * calculate buffer offsets, load buffers, and enable interrupts
144 lx_capt_start(VidDevice *dp)
146 int ret;
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));
171 width = fmt->width;
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;
181 else
182 height /= 2;
183 y_imgsz = y_pitch*height;
184 uv_imgsz = uv_pitch*height;
185 if( v4l_fmt_is_420(capt_pixelformat) > 0 ) {
186 uv_imgsz /= 2;
187 dp->capt_420 = 1;
189 else
190 dp->capt_420 = 0;
191 imgsz = y_imgsz + 2*uv_imgsz;
192 oy_offset = ey_offset = 0;
193 dp->capt_toggle = capt_toggle_even;
194 switch( field ) {
195 case V4L2_FIELD_SEQ_TB: /* both fields seq 1 bfr, top-bottom */
196 ey_offset += imgsz;
197 break;
198 case V4L2_FIELD_SEQ_BT: /* same + bottom-top */
199 oy_offset += imgsz;
200 break;
201 case V4L2_FIELD_INTERLACED: /* both fields interlaced */
202 ey_offset += y_pitch;
203 y_pitch *= 2;
204 uv_pitch *= 2;
205 y_imgsz *= 2;
206 uv_imgsz *= 2;
207 break;
208 case V4L2_FIELD_TOP: /* top field only */
209 dp->capt_toggle = dp->capt_progressive != 0 ?
210 capt_toggle_vblank : capt_toggle_odd;
211 break;
212 case V4L2_FIELD_BOTTOM: /* bottom field only */
213 dp->capt_toggle = dp->capt_progressive != 0 ?
214 capt_toggle_vblank : capt_toggle_even;
215 break;
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;
220 break;
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 ) {
230 offset1 = y_imgsz;
231 offset2 = offset1 + uv_imgsz;
232 dp->capt_planar = 1;
234 else {
235 dp->capt_planar = 0;
237 switch( capt_pixelformat ) {
238 case V4L2_PIX_FMT_YVU420:
239 v_offset = offset1;
240 u_offset = offset2;
241 break;
242 case V4L2_PIX_FMT_YUV422P:
243 case V4L2_PIX_FMT_YUV420:
244 u_offset = offset1;
245 v_offset = offset2;
246 break;
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));
255 swbfr.enable = 1;
256 swbfr.stop = height;
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;
274 else {
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;
285 is_reported = 0;
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);
297 if(ret)
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);
302 if(ret)
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);
309 if(ret!=1)
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;
317 else
318 interrupts |= VIP_INT_START_VBLANK;
319 vip_set_interrupt_enable(interrupts, 1);
320 spin_unlock_irqrestore(&dp->lock, flags);
321 return 0;
324 /** lx_capt_stop - stop capture */
325 void
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);
331 vip_terminate();
332 return;
335 /** lx_capt_get_format - enumerate video formats */
337 lx_capt_get_format(VidDevice *dp,int index, struct v4l2_fmtdesc *fmt)
339 int i, n, idx;
340 unsigned int pixelformat;
341 memset(fmt,0,sizeof(*fmt));
342 fmt->index = index;
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;
348 switch( idx ) {
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;
354 default:
355 return -EINVAL;
357 fmt->pixelformat = pixelformat;
358 snprintf(&fmt->description[0],sizeof(fmt->description),
359 "%4.4s", (char*)&pixelformat);
360 #ifdef REV2
361 fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
362 #else
363 fmt->depth = 16;
364 #endif
365 return 0;
368 /** lx_capt_min_rect - return min capture geometry */
369 void
370 lx_capt_min_rect(VidDevice *dp,int *w, int *h)
372 *w = 320; *h = 240;
375 /** lx_capt_max_rect - return max capture geometry */
376 void
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 */
383 void
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)
394 int n;
395 switch( 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;
401 default:
402 return 0;
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 */
436 void
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;
444 width = fmt->width;
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);
457 else
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 )
466 uv_pitch /= 2;
467 fmt->width = width;
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 )
472 height /= 2;
473 fmt->sizeimage = fmt->bytesperline*height;
474 fmt->priv = 0;
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 )
483 return 0;
485 if( lx_capt_std_progressive(dp,dp->std_index) != 0 ) {
486 if( field != V4L2_FIELD_NONE )
487 return 0;
489 #ifdef REV2
490 else {
491 if( field == V4L2_FIELD_NONE )
492 return 0;
494 #endif
495 return 1;
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);
505 return y_pitch;
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);
515 return uv_pitch;
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)
532 int field;
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);
537 #ifdef REV2
538 field = v4l_vid_field_def(dp->ovly.field,field);
539 #endif
540 if( v4l_fld_is_laced(field) > 0 && v4l_flds_per_bfr(field) == 1 )
541 src_h /= 2;
542 if( df_set_video_scale(src_w,src_h,dst_w,dst_h,
543 DF_SCALEFLAG_CHANGEX | DF_SCALEFLAG_CHANGEY) != 0 )
544 return -EINVAL;
545 if( src_h > 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);
548 return 0;
551 /** lx_ovly_start - enable overlay */
553 lx_ovly_start(VidDevice *dp)
555 int i, n, ret;
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);
563 return 0;
566 /** lx_ovly_stop - disable overlay */
567 void
568 lx_ovly_stop(VidDevice *dp)
570 df_set_video_enable(0,0);
571 return;
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 */
593 void
594 lx_ovly_min_rect(VidDevice *dp,int *w, int *h)
596 *w = 1; *h = 1;
599 /** lx_ovly_max_rect - return max overlay geometry */
600 void
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)
610 int i, n, idx;
611 unsigned int pixelformat;
612 char *cp;
613 memset(fmt,0,sizeof(*fmt));
614 fmt->index = index;
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;
620 switch( idx ) {
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;
627 default:
628 return -EINVAL;
630 fmt->pixelformat = pixelformat;
631 snprintf(&fmt->description[0],sizeof(fmt->description),"%s", cp);
632 #ifdef REV2
633 fmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
634 #else
635 fmt->depth = 16;
636 #endif
637 return 0;
640 /** lx_ovly_hw_fmt - map pixelformat to cimarron format */
642 lx_ovly_hw_fmt(VidDevice *dp,int fmt)
644 int n, hw_fmt;
645 switch( 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;
652 default:
653 return -1;
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 */
662 void
663 lx_ovly_reset_dst_rect(VidDevice *dp,int py)
665 int x, y, w, h;
666 int xofs, yofs;
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)
689 int ret;
690 Rect *src = &dp->ovly_src;
691 Rect *dst = &dp->ovly_dst;
692 Rect orig = *dst;
693 dst->x = x; dst->y = y;
694 dst->w = w; dst->h = h;
695 dst->is_set = 1;
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;
700 return ret;
703 /** lx_ovly_set_offsets - update ovly buffer device parameters
704 * offsets are recalculated, device format reset
706 void
707 lx_ovly_set_offsets(VidDevice *dp)
709 int field, scale;
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;
717 #ifdef REV2
718 int width = dp->ovly.w.width;
719 int height = dp->ovly.w.height;
720 #else
721 int width = dp->ovly.width;
722 int height = dp->ovly.height;
723 #endif
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);
731 #ifdef REV2
732 field = v4l_vid_field_def(dp->ovly.field,field);
733 #endif
734 if( (scale=v4l_flds_per_bfr(field)) > 0 )
735 height /= scale;
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 */
740 uv_imgsz /= 2;
742 imgsz = y_imgsz + 2*uv_imgsz;
743 if( scale == 1 ) y /= 2;
744 oy_offset = y*y_pitch;
745 ey_offset = oy_offset;
746 switch( field ) {
747 case V4L2_FIELD_SEQ_BT: /* same + bottom-top */
748 if( lx_display_is_interlaced() != 0 )
749 oy_offset += imgsz;
750 break;
751 case V4L2_FIELD_SEQ_TB: /* both fields seq 1 bfr, top-bottom */
752 if( lx_display_is_interlaced() != 0 )
753 ey_offset += imgsz;
754 break;
755 case V4L2_FIELD_INTERLACED: /* both fields interlaced */
756 y_imgsz *= 2;
757 uv_imgsz *= 2;
758 ey_offset += y_pitch;
759 if( lx_display_is_interlaced() != 0 ) {
760 y_pitch *= 2;
761 uv_pitch *= 2;
763 break;
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 */
768 break;
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:
777 v_offset = offset1;
778 u_offset = offset2;
779 break;
780 case V4L2_PIX_FMT_YUV422P:
781 case V4L2_PIX_FMT_YUV420:
782 u_offset = offset1;
783 v_offset = offset2;
784 break;
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 ) {
798 #ifdef REV2
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);
803 #else
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);
808 #endif
809 is_reported = 1;
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;
849 return 0;
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;
867 src->is_set = 1;
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 */
872 return 0;
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)
878 int h, w;
879 #ifdef REV2
880 int x = win->w.left;
881 int y = win->w.top;
882 int width = win->w.width;
883 int height = win->w.height;
884 #else
885 int x = win->x;
886 int y = win->y;
887 int width = win->width;
888 int height = win->height;
889 #endif
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));
898 #ifdef REV2
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;
903 win->w.left = x;
904 win->w.top = y;
905 win->w.width = width;
906 win->w.height = height;
907 #else
908 win->x = x;
909 win->y = y;
910 win->width = width;
911 win->height = height;
912 #endif
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)
937 int x, y, w, wt;
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;
950 if( y < 0 ) y = 0;
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)
964 if( enable == 0 )
965 df_set_video_color_key(0,0,1);
966 else
967 df_set_video_color_key(key,mask,1);
970 int lx_set_alpha_window(struct v4l2_alpha_window *awin)
972 int enable, window;
973 window = awin->window;
974 if( awin->priority >= 0 ) {
975 DF_ALPHA_REGION_PARAMS dap;
976 dap.x = awin->x;
977 dap.y = awin->y;
978 dap.width = awin->w;
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 )
986 return -EINVAL;
987 enable = 1;
989 else
990 enable = 0;
991 if( df_set_alpha_window_enable(window,enable) != 0 )
992 return -EINVAL;
993 return 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;
1017 io_buf *bp;
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);
1027 status &= ~stat;
1028 switch( stat ) {
1029 case VIP_INT_FIFO_WRAP:
1030 DMSG(1,"VIP_INT_FIFO_WRAP\n");
1031 vip_reset();
1032 break;
1033 case VIP_INT_LONGLINE:
1034 DMSG(1,"VIP_INT_LONGLINE\n");
1035 vip_reset();
1036 break;
1037 case VIP_INT_ACTIVE_PIXELS:
1038 DMSG(1,"VIP_INT_ACTIVE_PIXELS\n");
1039 vip_reset();
1040 break;
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;
1046 goto xit;
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);
1058 goto xit;
1061 ++dp->capt_field;
1062 wake = skip = 0;
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;
1069 denom *= dt;
1070 do_div(denom,numer);
1071 sequence = denom;
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 ) {
1111 even_index = 0;
1112 if( lx_display_is_interlaced() != 0 ) {
1113 even_index = 1;
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;
1120 else {
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;
1166 #ifndef REV2
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;
1170 #endif
1171 bp->flags |= V4L2_BUF_FLAG_DONE;
1172 wake = 1;
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;
1181 #ifndef REV2
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;
1185 #endif
1186 bp->flags |= V4L2_BUF_FLAG_DONE;
1187 wake = 1;
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 ) {
1202 if( stalled == 0 )
1203 DMSG(4,"stalled\n");
1204 else if( even == 0 )
1205 ++dp->capt_dropped;
1209 else {
1210 DMSG(0,"capture active with no buffer!\n");
1211 lx_capt_stop(dp);
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 )
1218 ++dp->capt_frame;
1219 ++dp->capt_sequence;
1220 wake = 1;
1223 /* if buffer queued/captured, wake up waiting task */
1224 if( wake != 0 ) {
1225 if( waitqueue_active(&dp->capt_wait) != 0 )
1226 wake_up_interruptible(&dp->capt_wait);
1229 xit:
1230 vip_reset_interrupt_state(dev->irq_status);
1231 return IRQ_HANDLED;
1235 /** lx_capt_resume2 - queue capture buffers to vip */
1237 lx_capt_resume2(VidDevice *dp,io_queue *io)
1239 io_buf *op, *ep;
1240 int eidx, oidx, vip_buffers;
1241 int task;
1242 int task_buffers = vip_task_data[task].task_buffers;
1243 VIPINPUTBUFFER *vip_inpbfr;
1245 unsigned long flags;
1246 struct list_head *lp;
1247 io_buf *bp1;
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;
1259 if( op == NULL ) {
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);
1267 lp = &io->rd_dqbuf;
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
1272 else {
1273 spin_unlock_irqrestore(&io->lock,flags);
1274 return 0;
1277 lp = &io->rd_qbuf;
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);
1291 //return 0;
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);
1302 return 0;
1304 ep = list_entry(io->rd_qbuf.next,io_buf,bfrq);
1305 list_del_init(&ep->bfrq);
1308 else
1310 ep = op;
1312 dp->capt_onxt = op; oidx = op->index;
1313 dp->capt_enxt = ep; eidx = ep->index;
1315 else
1317 oidx = eidx = 0;
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);
1328 else {
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;
1338 return 1;
1343 #if 0
1344 /** lx_init - hookup interrupt and cimarron kernel resources */
1345 int lx_init(struct pci_dev *pci, const struct pci_device_id *pdp)
1347 int ret;
1348 V4LDevice *dev;
1350 dev = v4l_dev_init();
1351 if (dev == NULL)
1352 return -ENOMEM;
1354 if( irq < 0 ) {
1355 irq = dev->irq = pci->irq;
1356 printk("Found Geode LX VIP at IRQ %d\n", (int)dev->irq);
1357 } else {
1358 dev->irq = 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");
1367 return -ENODEV;
1370 df_set_video_palette(NULL);
1371 return 0;
1374 /** lx_exit - free interrupt */
1375 void lx_exit(struct pci_dev *pci)
1377 v4l_dev_cleanup();
1378 free_irq(lx_dev->irq, lx_dev);
1380 #endif
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},
1384 { 0, },
1387 /** lx_init - hookup interrupt and cimarron kernel resources */
1388 int lx_init(V4LDevice *dev)
1390 int ret;
1391 struct pci_dev *pci = NULL;
1392 const struct pci_device_id *pdp = NULL;
1394 #ifdef LINUX_2_6
1395 while( (pci=pci_get_device(PCI_VENDOR_ID_AMD, PCI_ANY_ID, pci)) != NULL )
1396 #else
1397 pci_for_each_dev(pci)
1398 #endif
1400 pdp = pci_match_id(&lx_pci_tbl[0], pci);
1401 if( pdp != NULL) break;
1403 if( pdp == NULL) {
1404 DMSG(0,"cant find video device\n");
1405 return -ENODEV;
1407 dev->pci = pci;
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");
1418 return -ENODEV;
1421 df_set_video_palette(NULL);
1422 return 0;
1425 /** lx_exit - free interrupt */
1426 void lx_exit(V4LDevice *dev)
1428 free_irq(dev->irq, dev);