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