]> err.no Git - linux-2.6/blob - drivers/media/video/ivtv/ivtv-yuv.c
V4L/DVB (6081): ivtv: Fix static structure initialization
[linux-2.6] / drivers / media / video / ivtv / ivtv-yuv.c
1 /*
2     yuv support
3
4     Copyright (C) 2007  Ian Armstrong <ian@iarmst.demon.co.uk>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "ivtv-driver.h"
22 #include "ivtv-queue.h"
23 #include "ivtv-udma.h"
24 #include "ivtv-irq.h"
25 #include "ivtv-yuv.h"
26
27 static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
28                                  struct ivtv_dma_frame *args)
29 {
30         struct ivtv_dma_page_info y_dma;
31         struct ivtv_dma_page_info uv_dma;
32
33         int i;
34         int y_pages, uv_pages;
35
36         unsigned long y_buffer_offset, uv_buffer_offset;
37         int y_decode_height, uv_decode_height, y_size;
38         int frame = atomic_read(&itv->yuv_info.next_fill_frame);
39
40         y_buffer_offset = IVTV_DEC_MEM_START + yuv_offset[frame];
41         uv_buffer_offset = y_buffer_offset + IVTV_YUV_BUFFER_UV_OFFSET;
42
43         y_decode_height = uv_decode_height = args->src.height + args->src.top;
44
45         if (y_decode_height < 512-16)
46                 y_buffer_offset += 720 * 16;
47
48         if (y_decode_height & 15)
49                 y_decode_height = (y_decode_height + 16) & ~15;
50
51         if (uv_decode_height & 31)
52                 uv_decode_height = (uv_decode_height + 32) & ~31;
53
54         y_size = 720 * y_decode_height;
55
56         /* Still in USE */
57         if (dma->SG_length || dma->page_count) {
58                 IVTV_DEBUG_WARN("prep_user_dma: SG_length %d page_count %d still full?\n",
59                                 dma->SG_length, dma->page_count);
60                 return -EBUSY;
61         }
62
63         ivtv_udma_get_page_info (&y_dma, (unsigned long)args->y_source, 720 * y_decode_height);
64         ivtv_udma_get_page_info (&uv_dma, (unsigned long)args->uv_source, 360 * uv_decode_height);
65
66         /* Get user pages for DMA Xfer */
67         down_read(&current->mm->mmap_sem);
68         y_pages = get_user_pages(current, current->mm, y_dma.uaddr, y_dma.page_count, 0, 1, &dma->map[0], NULL);
69         uv_pages = get_user_pages(current, current->mm, uv_dma.uaddr, uv_dma.page_count, 0, 1, &dma->map[y_pages], NULL);
70         up_read(&current->mm->mmap_sem);
71
72         dma->page_count = y_dma.page_count + uv_dma.page_count;
73
74         if (y_pages + uv_pages != dma->page_count) {
75                 IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
76                                 y_pages + uv_pages, dma->page_count);
77
78                 for (i = 0; i < dma->page_count; i++) {
79                         put_page(dma->map[i]);
80                 }
81                 dma->page_count = 0;
82                 return -EINVAL;
83         }
84
85         /* Fill & map SG List */
86         if (ivtv_udma_fill_sg_list (dma, &uv_dma, ivtv_udma_fill_sg_list (dma, &y_dma, 0)) < 0) {
87                 IVTV_DEBUG_WARN("could not allocate bounce buffers for highmem userspace buffers\n");
88                 for (i = 0; i < dma->page_count; i++) {
89                         put_page(dma->map[i]);
90                 }
91                 dma->page_count = 0;
92                 return -ENOMEM;
93         }
94         dma->SG_length = pci_map_sg(itv->dev, dma->SGlist, dma->page_count, PCI_DMA_TODEVICE);
95
96         /* Fill SG Array with new values */
97         ivtv_udma_fill_sg_array (dma, y_buffer_offset, uv_buffer_offset, y_size);
98
99         /* If we've offset the y plane, ensure top area is blanked */
100         if (args->src.height + args->src.top < 512-16) {
101                 if (itv->yuv_info.blanking_dmaptr) {
102                         dma->SGarray[dma->SG_length].size = cpu_to_le32(720*16);
103                         dma->SGarray[dma->SG_length].src = cpu_to_le32(itv->yuv_info.blanking_dmaptr);
104                         dma->SGarray[dma->SG_length].dst = cpu_to_le32(IVTV_DEC_MEM_START + yuv_offset[frame]);
105                         dma->SG_length++;
106                 }
107         }
108
109         /* Tag SG Array with Interrupt Bit */
110         dma->SGarray[dma->SG_length - 1].size |= cpu_to_le32(0x80000000);
111
112         ivtv_udma_sync_for_device(itv);
113         return 0;
114 }
115
116 /* We rely on a table held in the firmware - Quick check. */
117 int ivtv_yuv_filter_check(struct ivtv *itv)
118 {
119         int i, offset_y, offset_uv;
120
121         for (i=0, offset_y = 16, offset_uv = 4; i<16; i++, offset_y += 24, offset_uv += 12) {
122                 if ((read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + offset_y) != i << 16) ||
123                     (read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + offset_uv) != i << 16)) {
124                         IVTV_WARN ("YUV filter table not found in firmware.\n");
125                         return -1;
126                 }
127         }
128         return 0;
129 }
130
131 static void ivtv_yuv_filter(struct ivtv *itv, int h_filter, int v_filter_1, int v_filter_2)
132 {
133         int filter_index, filter_line;
134
135         /* If any filter is -1, then don't update it */
136         if (h_filter > -1) {
137                 if (h_filter > 4) h_filter = 4;
138                 filter_index = h_filter * 384;
139                 filter_line = 0;
140                 while (filter_line < 16) {
141                         write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02804);
142                         write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0281c);
143                         filter_index += 4;
144                         write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02808);
145                         write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02820);
146                         filter_index += 4;
147                         write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0280c);
148                         write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02824);
149                         filter_index += 4;
150                         write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02810);
151                         write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02828);
152                         filter_index += 4;
153                         write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x02814);
154                         write_reg(read_dec(IVTV_YUV_HORIZONTAL_FILTER_OFFSET + filter_index), 0x0282c);
155                         filter_index += 8;
156                         write_reg(0, 0x02818);
157                         write_reg(0, 0x02830);
158                         filter_line ++;
159                 }
160                 IVTV_DEBUG_YUV("h_filter -> %d\n",h_filter);
161         }
162
163         if (v_filter_1 > -1) {
164                 if (v_filter_1 > 4) v_filter_1 = 4;
165                 filter_index = v_filter_1 * 192;
166                 filter_line = 0;
167                 while (filter_line < 16) {
168                         write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02900);
169                         filter_index += 4;
170                         write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02904);
171                         filter_index += 8;
172                         write_reg(0, 0x02908);
173                         filter_line ++;
174                 }
175                 IVTV_DEBUG_YUV("v_filter_1 -> %d\n",v_filter_1);
176         }
177
178         if (v_filter_2 > -1) {
179                 if (v_filter_2 > 4) v_filter_2 = 4;
180                 filter_index = v_filter_2 * 192;
181                 filter_line = 0;
182                 while (filter_line < 16) {
183                         write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x0290c);
184                         filter_index += 4;
185                         write_reg(read_dec(IVTV_YUV_VERTICAL_FILTER_OFFSET + filter_index), 0x02910);
186                         filter_index += 8;
187                         write_reg(0, 0x02914);
188                         filter_line ++;
189                 }
190                 IVTV_DEBUG_YUV("v_filter_2 -> %d\n",v_filter_2);
191         }
192 }
193
194 static void ivtv_yuv_handle_horizontal(struct ivtv *itv, struct yuv_frame_info *window)
195 {
196         u32 reg_2834, reg_2838, reg_283c;
197         u32 reg_2844, reg_2854, reg_285c;
198         u32 reg_2864, reg_2874, reg_2890;
199         u32 reg_2870, reg_2870_base, reg_2870_offset;
200         int x_cutoff;
201         int h_filter;
202         u32 master_width;
203
204         IVTV_DEBUG_WARN( "Need to adjust to width %d src_w %d dst_w %d src_x %d dst_x %d\n",
205                          window->tru_w, window->src_w, window->dst_w,window->src_x, window->dst_x);
206
207         /* How wide is the src image */
208         x_cutoff  = window->src_w + window->src_x;
209
210         /* Set the display width */
211         reg_2834 = window->dst_w;
212         reg_2838 = reg_2834;
213
214         /* Set the display position */
215         reg_2890 = window->dst_x;
216
217         /* Index into the image horizontally */
218         reg_2870 = 0;
219
220         /* 2870 is normally fudged to align video coords with osd coords.
221            If running full screen, it causes an unwanted left shift
222            Remove the fudge if we almost fill the screen.
223            Gradually adjust the offset to avoid the video 'snapping'
224            left/right if it gets dragged through this region.
225            Only do this if osd is full width. */
226         if (window->vis_w == 720) {
227                 if ((window->tru_x - window->pan_x > -1) && (window->tru_x - window->pan_x <= 40) && (window->dst_w >= 680)){
228                         reg_2870 = 10 - (window->tru_x - window->pan_x) / 4;
229                 }
230                 else if ((window->tru_x - window->pan_x < 0) && (window->tru_x - window->pan_x >= -20) && (window->dst_w >= 660)) {
231                         reg_2870 = (10 + (window->tru_x - window->pan_x) / 2);
232                 }
233
234                 if (window->dst_w >= window->src_w)
235                         reg_2870 = reg_2870 << 16 | reg_2870;
236                 else
237                         reg_2870 = ((reg_2870 & ~1) << 15) | (reg_2870 & ~1);
238         }
239
240         if (window->dst_w < window->src_w)
241                 reg_2870 = 0x000d000e - reg_2870;
242         else
243                 reg_2870 = 0x0012000e - reg_2870;
244
245         /* We're also using 2870 to shift the image left (src_x & negative dst_x) */
246         reg_2870_offset = (window->src_x*((window->dst_w << 21)/window->src_w))>>19;
247
248         if (window->dst_w >= window->src_w) {
249                 x_cutoff &= ~1;
250                 master_width = (window->src_w * 0x00200000) / (window->dst_w);
251                 if (master_width * window->dst_w != window->src_w * 0x00200000) master_width ++;
252                 reg_2834 = (reg_2834 << 16) | x_cutoff;
253                 reg_2838 = (reg_2838 << 16) | x_cutoff;
254                 reg_283c = master_width >> 2;
255                 reg_2844 = master_width >> 2;
256                 reg_2854 = master_width;
257                 reg_285c = master_width >> 1;
258                 reg_2864 = master_width >> 1;
259
260                 /* We also need to factor in the scaling
261                    (src_w - dst_w) / (src_w / 4) */
262                 if (window->dst_w > window->src_w)
263                         reg_2870_base = ((window->dst_w - window->src_w)<<16) / (window->src_w <<14);
264                 else
265                         reg_2870_base = 0;
266
267                 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 2) + (reg_2870_base << 17 | reg_2870_base);
268                 reg_2874 = 0;
269         }
270         else if (window->dst_w < window->src_w / 2) {
271                 master_width = (window->src_w * 0x00080000) / window->dst_w;
272                 if (master_width * window->dst_w != window->src_w * 0x00080000) master_width ++;
273                 reg_2834 = (reg_2834 << 16) | x_cutoff;
274                 reg_2838 = (reg_2838 << 16) | x_cutoff;
275                 reg_283c = master_width >> 2;
276                 reg_2844 = master_width >> 1;
277                 reg_2854 = master_width;
278                 reg_285c = master_width >> 1;
279                 reg_2864 = master_width >> 1;
280                 reg_2870 += (((reg_2870_offset << 15) & 0xFFFF0000) | reg_2870_offset);
281                 reg_2870 += (5 - (((window->src_w + window->src_w / 2) - 1) / window->dst_w)) << 16;
282                 reg_2874 = 0x00000012;
283         }
284         else {
285                 master_width = (window->src_w * 0x00100000) / window->dst_w;
286                 if (master_width * window->dst_w != window->src_w * 0x00100000) master_width ++;
287                 reg_2834 = (reg_2834 << 16) | x_cutoff;
288                 reg_2838 = (reg_2838 << 16) | x_cutoff;
289                 reg_283c = master_width >> 2;
290                 reg_2844 = master_width >> 1;
291                 reg_2854 = master_width;
292                 reg_285c = master_width >> 1;
293                 reg_2864 = master_width >> 1;
294                 reg_2870 += (((reg_2870_offset << 14) & 0xFFFF0000) | reg_2870_offset >> 1);
295                 reg_2870 += (5 - (((window->src_w * 3) - 1) / window->dst_w)) << 16;
296                 reg_2874 = 0x00000001;
297         }
298
299         /* Select the horizontal filter */
300         if (window->src_w == window->dst_w) {
301                 /* An exact size match uses filter 0 */
302                 h_filter = 0;
303         }
304         else {
305                 /* Figure out which filter to use */
306                 h_filter = ((window->src_w << 16) / window->dst_w) >> 15;
307                 h_filter = (h_filter >> 1) + (h_filter & 1);
308                 /* Only an exact size match can use filter 0 */
309                 if (h_filter == 0) h_filter = 1;
310         }
311
312         write_reg(reg_2834, 0x02834);
313         write_reg(reg_2838, 0x02838);
314         IVTV_DEBUG_YUV("Update reg 0x2834 %08x->%08x 0x2838 %08x->%08x\n",itv->yuv_info.reg_2834, reg_2834, itv->yuv_info.reg_2838, reg_2838);
315
316         write_reg(reg_283c, 0x0283c);
317         write_reg(reg_2844, 0x02844);
318
319         IVTV_DEBUG_YUV("Update reg 0x283c %08x->%08x 0x2844 %08x->%08x\n",itv->yuv_info.reg_283c, reg_283c, itv->yuv_info.reg_2844, reg_2844);
320
321         write_reg(0x00080514, 0x02840);
322         write_reg(0x00100514, 0x02848);
323         IVTV_DEBUG_YUV("Update reg 0x2840 %08x->%08x 0x2848 %08x->%08x\n",itv->yuv_info.reg_2840, 0x00080514, itv->yuv_info.reg_2848, 0x00100514);
324
325         write_reg(reg_2854, 0x02854);
326         IVTV_DEBUG_YUV("Update reg 0x2854 %08x->%08x \n",itv->yuv_info.reg_2854, reg_2854);
327
328         write_reg(reg_285c, 0x0285c);
329         write_reg(reg_2864, 0x02864);
330         IVTV_DEBUG_YUV("Update reg 0x285c %08x->%08x 0x2864 %08x->%08x\n",itv->yuv_info.reg_285c, reg_285c, itv->yuv_info.reg_2864, reg_2864);
331
332         write_reg(reg_2874, 0x02874);
333         IVTV_DEBUG_YUV("Update reg 0x2874 %08x->%08x\n",itv->yuv_info.reg_2874, reg_2874);
334
335         write_reg(reg_2870, 0x02870);
336         IVTV_DEBUG_YUV("Update reg 0x2870 %08x->%08x\n",itv->yuv_info.reg_2870, reg_2870);
337
338         write_reg( reg_2890,0x02890);
339         IVTV_DEBUG_YUV("Update reg 0x2890 %08x->%08x\n",itv->yuv_info.reg_2890, reg_2890);
340
341         /* Only update the filter if we really need to */
342         if (h_filter != itv->yuv_info.h_filter) {
343                 ivtv_yuv_filter (itv,h_filter,-1,-1);
344                 itv->yuv_info.h_filter = h_filter;
345         }
346 }
347
348 static void ivtv_yuv_handle_vertical(struct ivtv *itv, struct yuv_frame_info *window)
349 {
350         u32 master_height;
351         u32 reg_2918, reg_291c, reg_2920, reg_2928;
352         u32 reg_2930, reg_2934, reg_293c;
353         u32 reg_2940, reg_2944, reg_294c;
354         u32 reg_2950, reg_2954, reg_2958, reg_295c;
355         u32 reg_2960, reg_2964, reg_2968, reg_296c;
356         u32 reg_289c;
357         u32 src_y_major_y, src_y_minor_y;
358         u32 src_y_major_uv, src_y_minor_uv;
359         u32 reg_2964_base, reg_2968_base;
360         int v_filter_1, v_filter_2;
361
362         IVTV_DEBUG_WARN("Need to adjust to height %d src_h %d dst_h %d src_y %d dst_y %d\n",
363                 window->tru_h, window->src_h, window->dst_h,window->src_y, window->dst_y);
364
365         /* What scaling mode is being used... */
366         if (window->interlaced_y) {
367                 IVTV_DEBUG_YUV("Scaling mode Y: Interlaced\n");
368         }
369         else {
370                 IVTV_DEBUG_YUV("Scaling mode Y: Progressive\n");
371         }
372
373         if (window->interlaced_uv) {
374                 IVTV_DEBUG_YUV("Scaling mode UV: Interlaced\n");
375         }
376         else {
377                 IVTV_DEBUG_YUV("Scaling mode UV: Progressive\n");
378         }
379
380         /* What is the source video being treated as... */
381         if (itv->yuv_info.frame_interlaced) {
382                 IVTV_DEBUG_WARN("Source video: Interlaced\n");
383         }
384         else {
385                 IVTV_DEBUG_WARN("Source video: Non-interlaced\n");
386         }
387
388         /* We offset into the image using two different index methods, so split
389            the y source coord into two parts. */
390         if (window->src_y < 8) {
391                 src_y_minor_uv = window->src_y;
392                 src_y_major_uv = 0;
393         }
394         else {
395                 src_y_minor_uv = 8;
396                 src_y_major_uv = window->src_y - 8;
397         }
398
399         src_y_minor_y = src_y_minor_uv;
400         src_y_major_y = src_y_major_uv;
401
402         if (window->offset_y) src_y_minor_y += 16;
403
404         if (window->interlaced_y)
405                 reg_2918 = (window->dst_h << 16) | (window->src_h + src_y_minor_y);
406         else
407                 reg_2918 = (window->dst_h << 16) | ((window->src_h + src_y_minor_y) << 1);
408
409         if (window->interlaced_uv)
410                 reg_291c = (window->dst_h << 16) | ((window->src_h + src_y_minor_uv) >> 1);
411         else
412                 reg_291c = (window->dst_h << 16) | (window->src_h + src_y_minor_uv);
413
414         reg_2964_base = (src_y_minor_y * ((window->dst_h << 16)/window->src_h)) >> 14;
415         reg_2968_base = (src_y_minor_uv * ((window->dst_h << 16)/window->src_h)) >> 14;
416
417         if (window->dst_h / 2 >= window->src_h && !window->interlaced_y) {
418                 master_height = (window->src_h * 0x00400000) / window->dst_h;
419                 if ((window->src_h * 0x00400000) - (master_height * window->dst_h) >= window->dst_h / 2) master_height ++;
420                 reg_2920 = master_height >> 2;
421                 reg_2928 = master_height >> 3;
422                 reg_2930 = master_height;
423                 reg_2940 = master_height >> 1;
424                 reg_2964_base >>= 3;
425                 reg_2968_base >>= 3;
426                 reg_296c = 0x00000000;
427         }
428         else if (window->dst_h >= window->src_h) {
429                 master_height = (window->src_h * 0x00400000) / window->dst_h;
430                 master_height = (master_height >> 1) + (master_height & 1);
431                 reg_2920 = master_height >> 2;
432                 reg_2928 = master_height >> 2;
433                 reg_2930 = master_height;
434                 reg_2940 = master_height >> 1;
435                 reg_296c = 0x00000000;
436                 if (window->interlaced_y) {
437                         reg_2964_base >>= 3;
438                 }
439                 else {
440                         reg_296c ++;
441                         reg_2964_base >>= 2;
442                 }
443                 if (window->interlaced_uv) reg_2928 >>= 1;
444                 reg_2968_base >>= 3;
445         }
446         else if (window->dst_h >= window->src_h / 2) {
447                 master_height = (window->src_h * 0x00200000) / window->dst_h;
448                 master_height = (master_height >> 1) + (master_height & 1);
449                 reg_2920 = master_height >> 2;
450                 reg_2928 = master_height >> 2;
451                 reg_2930 = master_height;
452                 reg_2940 = master_height;
453                 reg_296c = 0x00000101;
454                 if (window->interlaced_y) {
455                         reg_2964_base >>= 2;
456                 }
457                 else {
458                         reg_296c ++;
459                         reg_2964_base >>= 1;
460                 }
461                 if (window->interlaced_uv) reg_2928 >>= 1;
462                 reg_2968_base >>= 2;
463         }
464         else {
465                 master_height = (window->src_h * 0x00100000) / window->dst_h;
466                 master_height = (master_height >> 1) + (master_height & 1);
467                 reg_2920 = master_height >> 2;
468                 reg_2928 = master_height >> 2;
469                 reg_2930 = master_height;
470                 reg_2940 = master_height;
471                 reg_2964_base >>= 1;
472                 reg_2968_base >>= 2;
473                 reg_296c = 0x00000102;
474         }
475
476         /* FIXME These registers change depending on scaled / unscaled output
477            We really need to work out what they should be */
478         if (window->src_h == window->dst_h){
479                 reg_2934 = 0x00020000;
480                 reg_293c = 0x00100000;
481                 reg_2944 = 0x00040000;
482                 reg_294c = 0x000b0000;
483         }
484         else {
485                 reg_2934 = 0x00000FF0;
486                 reg_293c = 0x00000FF0;
487                 reg_2944 = 0x00000FF0;
488                 reg_294c = 0x00000FF0;
489         }
490
491         /* The first line to be displayed */
492         reg_2950 = 0x00010000 + src_y_major_y;
493         if (window->interlaced_y) reg_2950 += 0x00010000;
494         reg_2954 = reg_2950 + 1;
495
496         reg_2958 = 0x00010000 + (src_y_major_y >> 1);
497         if (window->interlaced_uv) reg_2958 += 0x00010000;
498         reg_295c = reg_2958 + 1;
499
500         if (itv->yuv_info.decode_height == 480)
501                 reg_289c = 0x011e0017;
502         else
503                 reg_289c = 0x01500017;
504
505         if (window->dst_y < 0)
506                 reg_289c = (reg_289c - ((window->dst_y & ~1)<<15))-(window->dst_y >>1);
507         else
508                 reg_289c = (reg_289c + ((window->dst_y & ~1)<<15))+(window->dst_y >>1);
509
510         /* How much of the source to decode.
511            Take into account the source offset */
512         reg_2960 = ((src_y_minor_y + window->src_h + src_y_major_y) - 1 ) |
513                         ((((src_y_minor_uv + window->src_h + src_y_major_uv) - 1) & ~1) << 15);
514
515         /* Calculate correct value for register 2964 */
516         if (window->src_h == window->dst_h)
517                 reg_2964 = 1;
518         else {
519                 reg_2964 = 2 + ((window->dst_h << 1) / window->src_h);
520                 reg_2964 = (reg_2964 >> 1) + (reg_2964 & 1);
521         }
522         reg_2968 = (reg_2964 << 16) + reg_2964 + (reg_2964 >> 1);
523         reg_2964 = (reg_2964 << 16) + reg_2964 + (reg_2964 * 46 / 94);
524
525         /* Okay, we've wasted time working out the correct value,
526            but if we use it, it fouls the the window alignment.
527            Fudge it to what we want... */
528         reg_2964 = 0x00010001 + ((reg_2964 & 0x0000FFFF) - (reg_2964 >> 16));
529         reg_2968 = 0x00010001 + ((reg_2968 & 0x0000FFFF) - (reg_2968 >> 16));
530
531         /* Deviate further from what it should be. I find the flicker headache
532            inducing so try to reduce it slightly. Leave 2968 as-is otherwise
533            colours foul. */
534         if ((reg_2964 != 0x00010001) && (window->dst_h / 2 <= window->src_h))
535                 reg_2964 = (reg_2964 & 0xFFFF0000) + ((reg_2964 & 0x0000FFFF)/2);
536
537         if (!window->interlaced_y) reg_2964 -= 0x00010001;
538         if (!window->interlaced_uv) reg_2968 -= 0x00010001;
539
540         reg_2964 += ((reg_2964_base << 16) | reg_2964_base);
541         reg_2968 += ((reg_2968_base << 16) | reg_2968_base);
542
543         /* Select the vertical filter */
544         if (window->src_h == window->dst_h) {
545                 /* An exact size match uses filter 0/1 */
546                 v_filter_1 = 0;
547                 v_filter_2 = 1;
548         }
549         else {
550                 /* Figure out which filter to use */
551                 v_filter_1 = ((window->src_h << 16) / window->dst_h) >> 15;
552                 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
553                 /* Only an exact size match can use filter 0 */
554                 if (v_filter_1 == 0) v_filter_1 = 1;
555                 v_filter_2 = v_filter_1;
556         }
557
558         write_reg(reg_2934, 0x02934);
559         write_reg(reg_293c, 0x0293c);
560         IVTV_DEBUG_YUV("Update reg 0x2934 %08x->%08x 0x293c %08x->%08x\n",itv->yuv_info.reg_2934, reg_2934, itv->yuv_info.reg_293c, reg_293c);
561         write_reg(reg_2944, 0x02944);
562         write_reg(reg_294c, 0x0294c);
563         IVTV_DEBUG_YUV("Update reg 0x2944 %08x->%08x 0x294c %08x->%08x\n",itv->yuv_info.reg_2944, reg_2944, itv->yuv_info.reg_294c, reg_294c);
564
565         /* Ensure 2970 is 0 (does it ever change ?) */
566 /*      write_reg(0,0x02970); */
567 /*      IVTV_DEBUG_YUV("Update reg 0x2970 %08x->%08x\n",itv->yuv_info.reg_2970, 0); */
568
569         write_reg(reg_2930, 0x02938);
570         write_reg(reg_2930, 0x02930);
571         IVTV_DEBUG_YUV("Update reg 0x2930 %08x->%08x 0x2938 %08x->%08x\n",itv->yuv_info.reg_2930, reg_2930, itv->yuv_info.reg_2938, reg_2930);
572
573         write_reg(reg_2928, 0x02928);
574         write_reg(reg_2928+0x514, 0x0292C);
575         IVTV_DEBUG_YUV("Update reg 0x2928 %08x->%08x 0x292c %08x->%08x\n",itv->yuv_info.reg_2928, reg_2928, itv->yuv_info.reg_292c, reg_2928+0x514);
576
577         write_reg(reg_2920, 0x02920);
578         write_reg(reg_2920+0x514, 0x02924);
579         IVTV_DEBUG_YUV("Update reg 0x2920 %08x->%08x 0x2924 %08x->%08x\n",itv->yuv_info.reg_2920, reg_2920, itv->yuv_info.reg_2924, 0x514+reg_2920);
580
581         write_reg (reg_2918,0x02918);
582         write_reg (reg_291c,0x0291C);
583         IVTV_DEBUG_YUV("Update reg 0x2918 %08x->%08x 0x291C %08x->%08x\n",itv->yuv_info.reg_2918,reg_2918,itv->yuv_info.reg_291c,reg_291c);
584
585         write_reg(reg_296c, 0x0296c);
586         IVTV_DEBUG_YUV("Update reg 0x296c %08x->%08x\n",itv->yuv_info.reg_296c, reg_296c);
587
588         write_reg(reg_2940, 0x02948);
589         write_reg(reg_2940, 0x02940);
590         IVTV_DEBUG_YUV("Update reg 0x2940 %08x->%08x 0x2948 %08x->%08x\n",itv->yuv_info.reg_2940, reg_2940, itv->yuv_info.reg_2948, reg_2940);
591
592         write_reg(reg_2950, 0x02950);
593         write_reg(reg_2954, 0x02954);
594         IVTV_DEBUG_YUV("Update reg 0x2950 %08x->%08x 0x2954 %08x->%08x\n",itv->yuv_info.reg_2950, reg_2950, itv->yuv_info.reg_2954, reg_2954);
595
596         write_reg(reg_2958, 0x02958);
597         write_reg(reg_295c, 0x0295C);
598         IVTV_DEBUG_YUV("Update reg 0x2958 %08x->%08x 0x295C %08x->%08x\n",itv->yuv_info.reg_2958, reg_2958, itv->yuv_info.reg_295c, reg_295c);
599
600         write_reg(reg_2960, 0x02960);
601         IVTV_DEBUG_YUV("Update reg 0x2960 %08x->%08x \n",itv->yuv_info.reg_2960, reg_2960);
602
603         write_reg(reg_2964, 0x02964);
604         write_reg(reg_2968, 0x02968);
605         IVTV_DEBUG_YUV("Update reg 0x2964 %08x->%08x 0x2968 %08x->%08x\n",itv->yuv_info.reg_2964, reg_2964, itv->yuv_info.reg_2968, reg_2968);
606
607         write_reg( reg_289c,0x0289c);
608         IVTV_DEBUG_YUV("Update reg 0x289c %08x->%08x\n",itv->yuv_info.reg_289c, reg_289c);
609
610         /* Only update filter 1 if we really need to */
611         if (v_filter_1 != itv->yuv_info.v_filter_1) {
612                 ivtv_yuv_filter (itv,-1,v_filter_1,-1);
613                 itv->yuv_info.v_filter_1 = v_filter_1;
614         }
615
616         /* Only update filter 2 if we really need to */
617         if (v_filter_2 != itv->yuv_info.v_filter_2) {
618                 ivtv_yuv_filter (itv,-1,-1,v_filter_2);
619                 itv->yuv_info.v_filter_2 = v_filter_2;
620         }
621
622 }
623
624 /* Modify the supplied coordinate information to fit the visible osd area */
625 static u32 ivtv_yuv_window_setup (struct ivtv *itv, struct yuv_frame_info *window)
626 {
627         int osd_crop, lace_threshold;
628         u32 osd_scale;
629         u32 yuv_update = 0;
630
631         lace_threshold = itv->yuv_info.lace_threshold;
632         if (lace_threshold < 0)
633                 lace_threshold = itv->yuv_info.decode_height - 1;
634
635         /* Work out the lace settings */
636         switch (itv->yuv_info.lace_mode) {
637                 case IVTV_YUV_MODE_PROGRESSIVE: /* Progressive mode */
638                         itv->yuv_info.frame_interlaced = 0;
639                         if (window->tru_h < 512 || (window->tru_h > 576 && window->tru_h < 1021))
640                                 window->interlaced_y = 0;
641                         else
642                                 window->interlaced_y = 1;
643
644                         if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
645                                 window->interlaced_uv = 0;
646                         else
647                                 window->interlaced_uv = 1;
648                         break;
649
650                 case IVTV_YUV_MODE_AUTO:
651                         if (window->tru_h <= lace_threshold || window->tru_h > 576 || window->tru_w > 720){
652                                 itv->yuv_info.frame_interlaced = 0;
653                                 if ((window->tru_h < 512) ||
654                                   (window->tru_h > 576 && window->tru_h < 1021) ||
655                                   (window->tru_w > 720 && window->tru_h < 1021))
656                                         window->interlaced_y = 0;
657                                 else
658                                         window->interlaced_y = 1;
659
660                                 if (window->tru_h < 1021 && (window->dst_h >= window->src_h /2))
661                                         window->interlaced_uv = 0;
662                                 else
663                                         window->interlaced_uv = 1;
664                         }
665                         else {
666                                 itv->yuv_info.frame_interlaced = 1;
667                                 window->interlaced_y = 1;
668                                 window->interlaced_uv = 1;
669                         }
670                         break;
671
672                         case IVTV_YUV_MODE_INTERLACED: /* Interlace mode */
673                 default:
674                         itv->yuv_info.frame_interlaced = 1;
675                         window->interlaced_y = 1;
676                         window->interlaced_uv = 1;
677                         break;
678         }
679
680         /* Sorry, but no negative coords for src */
681         if (window->src_x < 0) window->src_x = 0;
682         if (window->src_y < 0) window->src_y = 0;
683
684         /* Can only reduce width down to 1/4 original size */
685         if ((osd_crop = window->src_w - ( 4 * window->dst_w )) > 0) {
686                 window->src_x += osd_crop / 2;
687                 window->src_w = (window->src_w - osd_crop) & ~3;
688                 window->dst_w = window->src_w / 4;
689                 window->dst_w += window->dst_w & 1;
690         }
691
692         /* Can only reduce height down to 1/4 original size */
693         if (window->src_h / window->dst_h >= 2) {
694                 /* Overflow may be because we're running progressive, so force mode switch */
695                 window->interlaced_y = 1;
696                 /* Make sure we're still within limits for interlace */
697                 if ((osd_crop = window->src_h - ( 4 * window->dst_h )) > 0) {
698                         /* If we reach here we'll have to force the height. */
699                         window->src_y += osd_crop / 2;
700                         window->src_h = (window->src_h - osd_crop) & ~3;
701                         window->dst_h = window->src_h / 4;
702                         window->dst_h += window->dst_h & 1;
703                 }
704         }
705
706         /* If there's nothing to safe to display, we may as well stop now */
707         if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
708                 return 0;
709         }
710
711         /* Ensure video remains inside OSD area */
712         osd_scale = (window->src_h << 16) / window->dst_h;
713
714         if ((osd_crop = window->pan_y - window->dst_y) > 0) {
715                 /* Falls off the upper edge - crop */
716                 window->src_y += (osd_scale * osd_crop) >> 16;
717                 window->src_h -= (osd_scale * osd_crop) >> 16;
718                 window->dst_h -= osd_crop;
719                 window->dst_y = 0;
720         }
721         else {
722                 window->dst_y -= window->pan_y;
723         }
724
725         if ((osd_crop = window->dst_h + window->dst_y - window->vis_h) > 0) {
726                 /* Falls off the lower edge - crop */
727                 window->dst_h -= osd_crop;
728                 window->src_h -= (osd_scale * osd_crop) >> 16;
729         }
730
731         osd_scale = (window->src_w << 16) / window->dst_w;
732
733         if ((osd_crop = window->pan_x - window->dst_x) > 0) {
734                 /* Fall off the left edge - crop */
735                 window->src_x += (osd_scale * osd_crop) >> 16;
736                 window->src_w -= (osd_scale * osd_crop) >> 16;
737                 window->dst_w -= osd_crop;
738                 window->dst_x = 0;
739         }
740         else {
741                 window->dst_x -= window->pan_x;
742         }
743
744         if ((osd_crop = window->dst_w + window->dst_x - window->vis_w) > 0) {
745                 /* Falls off the right edge - crop */
746                 window->dst_w -= osd_crop;
747                 window->src_w -= (osd_scale * osd_crop) >> 16;
748         }
749
750         /* The OSD can be moved. Track to it */
751         window->dst_x += itv->yuv_info.osd_x_offset;
752         window->dst_y += itv->yuv_info.osd_y_offset;
753
754         /* Width & height for both src & dst must be even.
755            Same for coordinates. */
756         window->dst_w &= ~1;
757         window->dst_x &= ~1;
758
759         window->src_w += window->src_x & 1;
760         window->src_x &= ~1;
761
762         window->src_w &= ~1;
763         window->dst_w &= ~1;
764
765         window->dst_h &= ~1;
766         window->dst_y &= ~1;
767
768         window->src_h += window->src_y & 1;
769         window->src_y &= ~1;
770
771         window->src_h &= ~1;
772         window->dst_h &= ~1;
773
774         /* Due to rounding, we may have reduced the output size to <1/4 of the source
775            Check again, but this time just resize. Don't change source coordinates */
776         if (window->dst_w < window->src_w / 4) {
777                 window->src_w &= ~3;
778                 window->dst_w = window->src_w / 4;
779                 window->dst_w += window->dst_w & 1;
780         }
781         if (window->dst_h < window->src_h / 4) {
782                 window->src_h &= ~3;
783                 window->dst_h = window->src_h / 4;
784                 window->dst_h += window->dst_h & 1;
785         }
786
787         /* Check again. If there's nothing to safe to display, stop now */
788         if ((int)window->dst_w <= 2 || (int)window->dst_h <= 2 || (int)window->src_w <= 2 || (int)window->src_h <= 2) {
789                 return 0;
790         }
791
792         /* Both x offset & width are linked, so they have to be done together */
793         if ((itv->yuv_info.old_frame_info.dst_w != window->dst_w) ||
794             (itv->yuv_info.old_frame_info.src_w != window->src_w) ||
795             (itv->yuv_info.old_frame_info.dst_x != window->dst_x) ||
796             (itv->yuv_info.old_frame_info.src_x != window->src_x) ||
797             (itv->yuv_info.old_frame_info.pan_x != window->pan_x) ||
798             (itv->yuv_info.old_frame_info.vis_w != window->vis_w)) {
799                 yuv_update |= IVTV_YUV_UPDATE_HORIZONTAL;
800         }
801
802         if ((itv->yuv_info.old_frame_info.src_h != window->src_h) ||
803             (itv->yuv_info.old_frame_info.dst_h != window->dst_h) ||
804             (itv->yuv_info.old_frame_info.dst_y != window->dst_y) ||
805             (itv->yuv_info.old_frame_info.src_y != window->src_y) ||
806             (itv->yuv_info.old_frame_info.pan_y != window->pan_y) ||
807             (itv->yuv_info.old_frame_info.vis_h != window->vis_h) ||
808             (itv->yuv_info.old_frame_info.lace_mode != window->lace_mode) ||
809             (itv->yuv_info.old_frame_info.interlaced_y != window->interlaced_y) ||
810             (itv->yuv_info.old_frame_info.interlaced_uv != window->interlaced_uv)) {
811                 yuv_update |= IVTV_YUV_UPDATE_VERTICAL;
812         }
813
814         return yuv_update;
815 }
816
817 /* Update the scaling register to the requested value */
818 void ivtv_yuv_work_handler (struct ivtv *itv)
819 {
820         struct yuv_frame_info window;
821         u32 yuv_update;
822
823         int frame = itv->yuv_info.update_frame;
824
825 /*      IVTV_DEBUG_YUV("Update yuv registers for frame %d\n",frame); */
826         memcpy(&window, &itv->yuv_info.new_frame_info[frame], sizeof (window));
827
828         /* Update the osd pan info */
829         window.pan_x = itv->yuv_info.osd_x_pan;
830         window.pan_y = itv->yuv_info.osd_y_pan;
831         window.vis_w = itv->yuv_info.osd_vis_w;
832         window.vis_h = itv->yuv_info.osd_vis_h;
833
834         /* Calculate the display window coordinates. Exit if nothing left */
835         if (!(yuv_update = ivtv_yuv_window_setup (itv, &window)))
836                 return;
837
838         /* Update horizontal settings */
839         if (yuv_update & IVTV_YUV_UPDATE_HORIZONTAL)
840                 ivtv_yuv_handle_horizontal(itv, &window);
841
842         if (yuv_update & IVTV_YUV_UPDATE_VERTICAL)
843                 ivtv_yuv_handle_vertical(itv, &window);
844
845         memcpy(&itv->yuv_info.old_frame_info, &window, sizeof (itv->yuv_info.old_frame_info));
846 }
847
848 static void ivtv_yuv_init (struct ivtv *itv)
849 {
850         IVTV_DEBUG_YUV("ivtv_yuv_init\n");
851
852         /* Take a snapshot of the current register settings */
853         itv->yuv_info.reg_2834 = read_reg(0x02834);
854         itv->yuv_info.reg_2838 = read_reg(0x02838);
855         itv->yuv_info.reg_283c = read_reg(0x0283c);
856         itv->yuv_info.reg_2840 = read_reg(0x02840);
857         itv->yuv_info.reg_2844 = read_reg(0x02844);
858         itv->yuv_info.reg_2848 = read_reg(0x02848);
859         itv->yuv_info.reg_2854 = read_reg(0x02854);
860         itv->yuv_info.reg_285c = read_reg(0x0285c);
861         itv->yuv_info.reg_2864 = read_reg(0x02864);
862         itv->yuv_info.reg_2870 = read_reg(0x02870);
863         itv->yuv_info.reg_2874 = read_reg(0x02874);
864         itv->yuv_info.reg_2898 = read_reg(0x02898);
865         itv->yuv_info.reg_2890 = read_reg(0x02890);
866
867         itv->yuv_info.reg_289c = read_reg(0x0289c);
868         itv->yuv_info.reg_2918 = read_reg(0x02918);
869         itv->yuv_info.reg_291c = read_reg(0x0291c);
870         itv->yuv_info.reg_2920 = read_reg(0x02920);
871         itv->yuv_info.reg_2924 = read_reg(0x02924);
872         itv->yuv_info.reg_2928 = read_reg(0x02928);
873         itv->yuv_info.reg_292c = read_reg(0x0292c);
874         itv->yuv_info.reg_2930 = read_reg(0x02930);
875         itv->yuv_info.reg_2934 = read_reg(0x02934);
876         itv->yuv_info.reg_2938 = read_reg(0x02938);
877         itv->yuv_info.reg_293c = read_reg(0x0293c);
878         itv->yuv_info.reg_2940 = read_reg(0x02940);
879         itv->yuv_info.reg_2944 = read_reg(0x02944);
880         itv->yuv_info.reg_2948 = read_reg(0x02948);
881         itv->yuv_info.reg_294c = read_reg(0x0294c);
882         itv->yuv_info.reg_2950 = read_reg(0x02950);
883         itv->yuv_info.reg_2954 = read_reg(0x02954);
884         itv->yuv_info.reg_2958 = read_reg(0x02958);
885         itv->yuv_info.reg_295c = read_reg(0x0295c);
886         itv->yuv_info.reg_2960 = read_reg(0x02960);
887         itv->yuv_info.reg_2964 = read_reg(0x02964);
888         itv->yuv_info.reg_2968 = read_reg(0x02968);
889         itv->yuv_info.reg_296c = read_reg(0x0296c);
890         itv->yuv_info.reg_2970 = read_reg(0x02970);
891
892         itv->yuv_info.v_filter_1 = -1;
893         itv->yuv_info.v_filter_2 = -1;
894         itv->yuv_info.h_filter = -1;
895
896         /* Set some valid size info */
897         itv->yuv_info.osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
898         itv->yuv_info.osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
899
900         /* Bit 2 of reg 2878 indicates current decoder output format
901            0 : NTSC    1 : PAL */
902         if (read_reg(0x2878) & 4)
903                 itv->yuv_info.decode_height = 576;
904         else
905                 itv->yuv_info.decode_height = 480;
906
907         /* If no visible size set, assume full size */
908         if (!itv->yuv_info.osd_vis_w)
909                 itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
910
911         if (!itv->yuv_info.osd_vis_h) {
912                 itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
913         } else {
914                 /* If output video standard has changed, requested height may
915                 not be legal */
916                 if (itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset > itv->yuv_info.decode_height) {
917                         IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
918                                         itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset,
919                                         itv->yuv_info.decode_height);
920                         itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
921                 }
922         }
923
924         /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
925         itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL);
926         if (itv->yuv_info.blanking_ptr) {
927                 itv->yuv_info.blanking_dmaptr = pci_map_single(itv->dev, itv->yuv_info.blanking_ptr, 720*16, PCI_DMA_TODEVICE);
928         }
929         else {
930                 itv->yuv_info.blanking_dmaptr = 0;
931                 IVTV_DEBUG_WARN ("Failed to allocate yuv blanking buffer\n");
932         }
933
934         IVTV_DEBUG_WARN("Enable video output\n");
935         write_reg_sync(0x00108080, 0x2898);
936
937         /* Enable YUV decoder output */
938         write_reg_sync(0x01, IVTV_REG_VDM);
939
940         set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
941         atomic_set(&itv->yuv_info.next_dma_frame,0);
942 }
943
944 int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
945 {
946         DEFINE_WAIT(wait);
947         int rc = 0;
948         int got_sig = 0;
949         int frame, next_fill_frame, last_fill_frame;
950         int register_update = 0;
951
952         IVTV_DEBUG_INFO("yuv_prep_frame\n");
953
954         if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv);
955
956         frame = atomic_read(&itv->yuv_info.next_fill_frame);
957         next_fill_frame = (frame + 1) & 0x3;
958         last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3;
959
960         if (next_fill_frame != last_fill_frame && last_fill_frame != frame) {
961                 /* Buffers are full - Overwrite the last frame */
962                 next_fill_frame = frame;
963                 frame = (frame - 1) & 3;
964                 register_update = itv->yuv_info.new_frame_info[frame].update;
965         }
966
967         /* Take a snapshot of the yuv coordinate information */
968         itv->yuv_info.new_frame_info[frame].src_x = args->src.left;
969         itv->yuv_info.new_frame_info[frame].src_y = args->src.top;
970         itv->yuv_info.new_frame_info[frame].src_w = args->src.width;
971         itv->yuv_info.new_frame_info[frame].src_h = args->src.height;
972         itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left;
973         itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top;
974         itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width;
975         itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height;
976         itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left;
977         itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
978         itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
979
980         /* Snapshot field order */
981         itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;
982
983         /* Are we going to offset the Y plane */
984         if (args->src.height + args->src.top < 512-16)
985                 itv->yuv_info.new_frame_info[frame].offset_y = 1;
986         else
987                 itv->yuv_info.new_frame_info[frame].offset_y = 0;
988
989         /* Snapshot the osd pan info */
990         itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan;
991         itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan;
992         itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w;
993         itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h;
994
995         itv->yuv_info.new_frame_info[frame].update = 0;
996         itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
997         itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
998         itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;
999
1000         if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
1001             sizeof (itv->yuv_info.new_frame_info[frame]))) {
1002                 memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args));
1003                 itv->yuv_info.new_frame_info[frame].update = 1;
1004 /*              IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
1005         }
1006
1007         itv->yuv_info.new_frame_info[frame].update |= register_update;
1008
1009         /* Should this frame be delayed ? */
1010         if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])
1011                 itv->yuv_info.field_delay[frame] = 1;
1012         else
1013                 itv->yuv_info.field_delay[frame] = 0;
1014
1015         /* DMA the frame */
1016         mutex_lock(&itv->udma.lock);
1017
1018         if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1019                 mutex_unlock(&itv->udma.lock);
1020                 return rc;
1021         }
1022
1023         ivtv_udma_prepare(itv);
1024         prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
1025         /* if no UDMA is pending and no UDMA is in progress, then the DMA
1026         is finished */
1027         while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
1028                 /* don't interrupt if the DMA is in progress but break off
1029                 a still pending DMA. */
1030                 got_sig = signal_pending(current);
1031                 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1032                         break;
1033                 got_sig = 0;
1034                 schedule();
1035         }
1036         finish_wait(&itv->dma_waitq, &wait);
1037
1038         /* Unmap Last DMA Xfer */
1039         ivtv_udma_unmap(itv);
1040
1041         if (got_sig) {
1042                 IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1043                 mutex_unlock(&itv->udma.lock);
1044                 return -EINTR;
1045         }
1046
1047         atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame);
1048
1049         mutex_unlock(&itv->udma.lock);
1050         return rc;
1051 }
1052
1053 void ivtv_yuv_close(struct ivtv *itv)
1054 {
1055         int h_filter, v_filter_1, v_filter_2;
1056
1057         IVTV_DEBUG_YUV("ivtv_yuv_close\n");
1058         ivtv_waitq(&itv->vsync_waitq);
1059
1060         atomic_set(&itv->yuv_info.next_dma_frame, -1);
1061         atomic_set(&itv->yuv_info.next_fill_frame, 0);
1062
1063         /* Reset registers we have changed so mpeg playback works */
1064
1065         /* If we fully restore this register, the display may remain active.
1066            Restore, but set one bit to blank the video. Firmware will always
1067            clear this bit when needed, so not a problem. */
1068         write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);
1069
1070         write_reg(itv->yuv_info.reg_2834, 0x02834);
1071         write_reg(itv->yuv_info.reg_2838, 0x02838);
1072         write_reg(itv->yuv_info.reg_283c, 0x0283c);
1073         write_reg(itv->yuv_info.reg_2840, 0x02840);
1074         write_reg(itv->yuv_info.reg_2844, 0x02844);
1075         write_reg(itv->yuv_info.reg_2848, 0x02848);
1076         write_reg(itv->yuv_info.reg_2854, 0x02854);
1077         write_reg(itv->yuv_info.reg_285c, 0x0285c);
1078         write_reg(itv->yuv_info.reg_2864, 0x02864);
1079         write_reg(itv->yuv_info.reg_2870, 0x02870);
1080         write_reg(itv->yuv_info.reg_2874, 0x02874);
1081         write_reg(itv->yuv_info.reg_2890, 0x02890);
1082         write_reg(itv->yuv_info.reg_289c, 0x0289c);
1083
1084         write_reg(itv->yuv_info.reg_2918, 0x02918);
1085         write_reg(itv->yuv_info.reg_291c, 0x0291c);
1086         write_reg(itv->yuv_info.reg_2920, 0x02920);
1087         write_reg(itv->yuv_info.reg_2924, 0x02924);
1088         write_reg(itv->yuv_info.reg_2928, 0x02928);
1089         write_reg(itv->yuv_info.reg_292c, 0x0292c);
1090         write_reg(itv->yuv_info.reg_2930, 0x02930);
1091         write_reg(itv->yuv_info.reg_2934, 0x02934);
1092         write_reg(itv->yuv_info.reg_2938, 0x02938);
1093         write_reg(itv->yuv_info.reg_293c, 0x0293c);
1094         write_reg(itv->yuv_info.reg_2940, 0x02940);
1095         write_reg(itv->yuv_info.reg_2944, 0x02944);
1096         write_reg(itv->yuv_info.reg_2948, 0x02948);
1097         write_reg(itv->yuv_info.reg_294c, 0x0294c);
1098         write_reg(itv->yuv_info.reg_2950, 0x02950);
1099         write_reg(itv->yuv_info.reg_2954, 0x02954);
1100         write_reg(itv->yuv_info.reg_2958, 0x02958);
1101         write_reg(itv->yuv_info.reg_295c, 0x0295c);
1102         write_reg(itv->yuv_info.reg_2960, 0x02960);
1103         write_reg(itv->yuv_info.reg_2964, 0x02964);
1104         write_reg(itv->yuv_info.reg_2968, 0x02968);
1105         write_reg(itv->yuv_info.reg_296c, 0x0296c);
1106         write_reg(itv->yuv_info.reg_2970, 0x02970);
1107
1108         /* Prepare to restore filters */
1109
1110         /* First the horizontal filter */
1111         if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {
1112                 /* An exact size match uses filter 0 */
1113                 h_filter = 0;
1114         }
1115         else {
1116                 /* Figure out which filter to use */
1117                 h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;
1118                 h_filter = (h_filter >> 1) + (h_filter & 1);
1119                 /* Only an exact size match can use filter 0. */
1120                 if (h_filter < 1) h_filter = 1;
1121         }
1122
1123         /* Now the vertical filter */
1124         if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) {
1125                 /* An exact size match uses filter 0/1 */
1126                 v_filter_1 = 0;
1127                 v_filter_2 = 1;
1128         }
1129         else {
1130                 /* Figure out which filter to use */
1131                 v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;
1132                 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
1133                 /* Only an exact size match can use filter 0 */
1134                 if (v_filter_1 == 0) v_filter_1 = 1;
1135                 v_filter_2 = v_filter_1;
1136         }
1137
1138         /* Now restore the filters */
1139         ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
1140
1141         /* and clear a few registers */
1142         write_reg(0, 0x02814);
1143         write_reg(0, 0x0282c);
1144         write_reg(0, 0x02904);
1145         write_reg(0, 0x02910);
1146
1147         /* Release the blanking buffer */
1148         if (itv->yuv_info.blanking_ptr) {
1149                 kfree (itv->yuv_info.blanking_ptr);
1150                 itv->yuv_info.blanking_ptr = NULL;
1151                 pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
1152         }
1153
1154         /* Invalidate the old dimension information */
1155         itv->yuv_info.old_frame_info.src_w = 0;
1156         itv->yuv_info.old_frame_info.src_h = 0;
1157         itv->yuv_info.old_frame_info_args.src_w = 0;
1158         itv->yuv_info.old_frame_info_args.src_h = 0;
1159
1160         /* All done. */
1161         clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
1162 }
1163