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