V4L/DVB (6345): ivtvfb: YUV handling of an image which is not visible in the display...
[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-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         IVTV_DEBUG_YUV("ivtv_yuv_init\n");
861
862         /* Take a snapshot of the current register settings */
863         itv->yuv_info.reg_2834 = read_reg(0x02834);
864         itv->yuv_info.reg_2838 = read_reg(0x02838);
865         itv->yuv_info.reg_283c = read_reg(0x0283c);
866         itv->yuv_info.reg_2840 = read_reg(0x02840);
867         itv->yuv_info.reg_2844 = read_reg(0x02844);
868         itv->yuv_info.reg_2848 = read_reg(0x02848);
869         itv->yuv_info.reg_2854 = read_reg(0x02854);
870         itv->yuv_info.reg_285c = read_reg(0x0285c);
871         itv->yuv_info.reg_2864 = read_reg(0x02864);
872         itv->yuv_info.reg_2870 = read_reg(0x02870);
873         itv->yuv_info.reg_2874 = read_reg(0x02874);
874         itv->yuv_info.reg_2898 = read_reg(0x02898);
875         itv->yuv_info.reg_2890 = read_reg(0x02890);
876
877         itv->yuv_info.reg_289c = read_reg(0x0289c);
878         itv->yuv_info.reg_2918 = read_reg(0x02918);
879         itv->yuv_info.reg_291c = read_reg(0x0291c);
880         itv->yuv_info.reg_2920 = read_reg(0x02920);
881         itv->yuv_info.reg_2924 = read_reg(0x02924);
882         itv->yuv_info.reg_2928 = read_reg(0x02928);
883         itv->yuv_info.reg_292c = read_reg(0x0292c);
884         itv->yuv_info.reg_2930 = read_reg(0x02930);
885         itv->yuv_info.reg_2934 = read_reg(0x02934);
886         itv->yuv_info.reg_2938 = read_reg(0x02938);
887         itv->yuv_info.reg_293c = read_reg(0x0293c);
888         itv->yuv_info.reg_2940 = read_reg(0x02940);
889         itv->yuv_info.reg_2944 = read_reg(0x02944);
890         itv->yuv_info.reg_2948 = read_reg(0x02948);
891         itv->yuv_info.reg_294c = read_reg(0x0294c);
892         itv->yuv_info.reg_2950 = read_reg(0x02950);
893         itv->yuv_info.reg_2954 = read_reg(0x02954);
894         itv->yuv_info.reg_2958 = read_reg(0x02958);
895         itv->yuv_info.reg_295c = read_reg(0x0295c);
896         itv->yuv_info.reg_2960 = read_reg(0x02960);
897         itv->yuv_info.reg_2964 = read_reg(0x02964);
898         itv->yuv_info.reg_2968 = read_reg(0x02968);
899         itv->yuv_info.reg_296c = read_reg(0x0296c);
900         itv->yuv_info.reg_2970 = read_reg(0x02970);
901
902         itv->yuv_info.v_filter_1 = -1;
903         itv->yuv_info.v_filter_2 = -1;
904         itv->yuv_info.h_filter = -1;
905
906         /* Set some valid size info */
907         itv->yuv_info.osd_x_offset = read_reg(0x02a04) & 0x00000FFF;
908         itv->yuv_info.osd_y_offset = (read_reg(0x02a04) >> 16) & 0x00000FFF;
909
910         /* Bit 2 of reg 2878 indicates current decoder output format
911            0 : NTSC    1 : PAL */
912         if (read_reg(0x2878) & 4)
913                 itv->yuv_info.decode_height = 576;
914         else
915                 itv->yuv_info.decode_height = 480;
916
917         /* If no visible size set, assume full size */
918         if (!itv->yuv_info.osd_vis_w)
919                 itv->yuv_info.osd_vis_w = 720 - itv->yuv_info.osd_x_offset;
920
921         if (!itv->yuv_info.osd_vis_h) {
922                 itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
923         } else {
924                 /* If output video standard has changed, requested height may
925                 not be legal */
926                 if (itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset > itv->yuv_info.decode_height) {
927                         IVTV_DEBUG_WARN("Clipping yuv output - fb size (%d) exceeds video standard limit (%d)\n",
928                                         itv->yuv_info.osd_vis_h + itv->yuv_info.osd_y_offset,
929                                         itv->yuv_info.decode_height);
930                         itv->yuv_info.osd_vis_h = itv->yuv_info.decode_height - itv->yuv_info.osd_y_offset;
931                 }
932         }
933
934         /* We need a buffer for blanking when Y plane is offset - non-fatal if we can't get one */
935         itv->yuv_info.blanking_ptr = kzalloc(720*16,GFP_KERNEL);
936         if (itv->yuv_info.blanking_ptr) {
937                 itv->yuv_info.blanking_dmaptr = pci_map_single(itv->dev, itv->yuv_info.blanking_ptr, 720*16, PCI_DMA_TODEVICE);
938         }
939         else {
940                 itv->yuv_info.blanking_dmaptr = 0;
941                 IVTV_DEBUG_WARN ("Failed to allocate yuv blanking buffer\n");
942         }
943
944         /* Enable YUV decoder output */
945         write_reg_sync(0x01, IVTV_REG_VDM);
946
947         set_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
948         atomic_set(&itv->yuv_info.next_dma_frame,0);
949 }
950
951 int ivtv_yuv_prep_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
952 {
953         DEFINE_WAIT(wait);
954         int rc = 0;
955         int got_sig = 0;
956         int frame, next_fill_frame, last_fill_frame;
957         int register_update = 0;
958
959         IVTV_DEBUG_INFO("yuv_prep_frame\n");
960
961         if (atomic_read(&itv->yuv_info.next_dma_frame) == -1) ivtv_yuv_init(itv);
962
963         frame = atomic_read(&itv->yuv_info.next_fill_frame);
964         next_fill_frame = (frame + 1) & 0x3;
965         last_fill_frame = (atomic_read(&itv->yuv_info.next_dma_frame)+1) & 0x3;
966
967         if (next_fill_frame != last_fill_frame && last_fill_frame != frame) {
968                 /* Buffers are full - Overwrite the last frame */
969                 next_fill_frame = frame;
970                 frame = (frame - 1) & 3;
971                 register_update = itv->yuv_info.new_frame_info[frame].update;
972         }
973
974         /* Take a snapshot of the yuv coordinate information */
975         itv->yuv_info.new_frame_info[frame].src_x = args->src.left;
976         itv->yuv_info.new_frame_info[frame].src_y = args->src.top;
977         itv->yuv_info.new_frame_info[frame].src_w = args->src.width;
978         itv->yuv_info.new_frame_info[frame].src_h = args->src.height;
979         itv->yuv_info.new_frame_info[frame].dst_x = args->dst.left;
980         itv->yuv_info.new_frame_info[frame].dst_y = args->dst.top;
981         itv->yuv_info.new_frame_info[frame].dst_w = args->dst.width;
982         itv->yuv_info.new_frame_info[frame].dst_h = args->dst.height;
983         itv->yuv_info.new_frame_info[frame].tru_x = args->dst.left;
984         itv->yuv_info.new_frame_info[frame].tru_w = args->src_width;
985         itv->yuv_info.new_frame_info[frame].tru_h = args->src_height;
986
987         /* Snapshot field order */
988         itv->yuv_info.sync_field[frame] = itv->yuv_info.lace_sync_field;
989
990         /* Are we going to offset the Y plane */
991         if (args->src.height + args->src.top < 512-16)
992                 itv->yuv_info.new_frame_info[frame].offset_y = 1;
993         else
994                 itv->yuv_info.new_frame_info[frame].offset_y = 0;
995
996         /* Snapshot the osd pan info */
997         itv->yuv_info.new_frame_info[frame].pan_x = itv->yuv_info.osd_x_pan;
998         itv->yuv_info.new_frame_info[frame].pan_y = itv->yuv_info.osd_y_pan;
999         itv->yuv_info.new_frame_info[frame].vis_w = itv->yuv_info.osd_vis_w;
1000         itv->yuv_info.new_frame_info[frame].vis_h = itv->yuv_info.osd_vis_h;
1001
1002         itv->yuv_info.new_frame_info[frame].update = 0;
1003         itv->yuv_info.new_frame_info[frame].interlaced_y = 0;
1004         itv->yuv_info.new_frame_info[frame].interlaced_uv = 0;
1005         itv->yuv_info.new_frame_info[frame].lace_mode = itv->yuv_info.lace_mode;
1006
1007         if (memcmp (&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame],
1008             sizeof (itv->yuv_info.new_frame_info[frame]))) {
1009                 memcpy(&itv->yuv_info.old_frame_info_args, &itv->yuv_info.new_frame_info[frame], sizeof (itv->yuv_info.old_frame_info_args));
1010                 itv->yuv_info.new_frame_info[frame].update = 1;
1011 /*              IVTV_DEBUG_YUV ("Requesting register update for frame %d\n",frame); */
1012         }
1013
1014         itv->yuv_info.new_frame_info[frame].update |= register_update;
1015
1016         /* Should this frame be delayed ? */
1017         if (itv->yuv_info.sync_field[frame] != itv->yuv_info.sync_field[(frame - 1) & 3])
1018                 itv->yuv_info.field_delay[frame] = 1;
1019         else
1020                 itv->yuv_info.field_delay[frame] = 0;
1021
1022         /* DMA the frame */
1023         mutex_lock(&itv->udma.lock);
1024
1025         if ((rc = ivtv_yuv_prep_user_dma(itv, &itv->udma, args)) != 0) {
1026                 mutex_unlock(&itv->udma.lock);
1027                 return rc;
1028         }
1029
1030         ivtv_udma_prepare(itv);
1031         prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
1032         /* if no UDMA is pending and no UDMA is in progress, then the DMA
1033         is finished */
1034         while (itv->i_flags & (IVTV_F_I_UDMA_PENDING | IVTV_F_I_UDMA)) {
1035                 /* don't interrupt if the DMA is in progress but break off
1036                 a still pending DMA. */
1037                 got_sig = signal_pending(current);
1038                 if (got_sig && test_and_clear_bit(IVTV_F_I_UDMA_PENDING, &itv->i_flags))
1039                         break;
1040                 got_sig = 0;
1041                 schedule();
1042         }
1043         finish_wait(&itv->dma_waitq, &wait);
1044
1045         /* Unmap Last DMA Xfer */
1046         ivtv_udma_unmap(itv);
1047
1048         if (got_sig) {
1049                 IVTV_DEBUG_INFO("User stopped YUV UDMA\n");
1050                 mutex_unlock(&itv->udma.lock);
1051                 return -EINTR;
1052         }
1053
1054         atomic_set(&itv->yuv_info.next_fill_frame, next_fill_frame);
1055
1056         mutex_unlock(&itv->udma.lock);
1057         return rc;
1058 }
1059
1060 void ivtv_yuv_close(struct ivtv *itv)
1061 {
1062         int h_filter, v_filter_1, v_filter_2;
1063
1064         IVTV_DEBUG_YUV("ivtv_yuv_close\n");
1065         ivtv_waitq(&itv->vsync_waitq);
1066
1067         atomic_set(&itv->yuv_info.next_dma_frame, -1);
1068         atomic_set(&itv->yuv_info.next_fill_frame, 0);
1069
1070         /* Reset registers we have changed so mpeg playback works */
1071
1072         /* If we fully restore this register, the display may remain active.
1073            Restore, but set one bit to blank the video. Firmware will always
1074            clear this bit when needed, so not a problem. */
1075         write_reg(itv->yuv_info.reg_2898 | 0x01000000, 0x2898);
1076
1077         write_reg(itv->yuv_info.reg_2834, 0x02834);
1078         write_reg(itv->yuv_info.reg_2838, 0x02838);
1079         write_reg(itv->yuv_info.reg_283c, 0x0283c);
1080         write_reg(itv->yuv_info.reg_2840, 0x02840);
1081         write_reg(itv->yuv_info.reg_2844, 0x02844);
1082         write_reg(itv->yuv_info.reg_2848, 0x02848);
1083         write_reg(itv->yuv_info.reg_2854, 0x02854);
1084         write_reg(itv->yuv_info.reg_285c, 0x0285c);
1085         write_reg(itv->yuv_info.reg_2864, 0x02864);
1086         write_reg(itv->yuv_info.reg_2870, 0x02870);
1087         write_reg(itv->yuv_info.reg_2874, 0x02874);
1088         write_reg(itv->yuv_info.reg_2890, 0x02890);
1089         write_reg(itv->yuv_info.reg_289c, 0x0289c);
1090
1091         write_reg(itv->yuv_info.reg_2918, 0x02918);
1092         write_reg(itv->yuv_info.reg_291c, 0x0291c);
1093         write_reg(itv->yuv_info.reg_2920, 0x02920);
1094         write_reg(itv->yuv_info.reg_2924, 0x02924);
1095         write_reg(itv->yuv_info.reg_2928, 0x02928);
1096         write_reg(itv->yuv_info.reg_292c, 0x0292c);
1097         write_reg(itv->yuv_info.reg_2930, 0x02930);
1098         write_reg(itv->yuv_info.reg_2934, 0x02934);
1099         write_reg(itv->yuv_info.reg_2938, 0x02938);
1100         write_reg(itv->yuv_info.reg_293c, 0x0293c);
1101         write_reg(itv->yuv_info.reg_2940, 0x02940);
1102         write_reg(itv->yuv_info.reg_2944, 0x02944);
1103         write_reg(itv->yuv_info.reg_2948, 0x02948);
1104         write_reg(itv->yuv_info.reg_294c, 0x0294c);
1105         write_reg(itv->yuv_info.reg_2950, 0x02950);
1106         write_reg(itv->yuv_info.reg_2954, 0x02954);
1107         write_reg(itv->yuv_info.reg_2958, 0x02958);
1108         write_reg(itv->yuv_info.reg_295c, 0x0295c);
1109         write_reg(itv->yuv_info.reg_2960, 0x02960);
1110         write_reg(itv->yuv_info.reg_2964, 0x02964);
1111         write_reg(itv->yuv_info.reg_2968, 0x02968);
1112         write_reg(itv->yuv_info.reg_296c, 0x0296c);
1113         write_reg(itv->yuv_info.reg_2970, 0x02970);
1114
1115         /* Prepare to restore filters */
1116
1117         /* First the horizontal filter */
1118         if ((itv->yuv_info.reg_2834 & 0x0000FFFF) == (itv->yuv_info.reg_2834 >> 16)) {
1119                 /* An exact size match uses filter 0 */
1120                 h_filter = 0;
1121         }
1122         else {
1123                 /* Figure out which filter to use */
1124                 h_filter = ((itv->yuv_info.reg_2834 << 16) / (itv->yuv_info.reg_2834 >> 16)) >> 15;
1125                 h_filter = (h_filter >> 1) + (h_filter & 1);
1126                 /* Only an exact size match can use filter 0. */
1127                 if (h_filter < 1) h_filter = 1;
1128         }
1129
1130         /* Now the vertical filter */
1131         if ((itv->yuv_info.reg_2918 & 0x0000FFFF) == (itv->yuv_info.reg_2918 >> 16)) {
1132                 /* An exact size match uses filter 0/1 */
1133                 v_filter_1 = 0;
1134                 v_filter_2 = 1;
1135         }
1136         else {
1137                 /* Figure out which filter to use */
1138                 v_filter_1 = ((itv->yuv_info.reg_2918 << 16) / (itv->yuv_info.reg_2918 >> 16)) >> 15;
1139                 v_filter_1 = (v_filter_1 >> 1) + (v_filter_1 & 1);
1140                 /* Only an exact size match can use filter 0 */
1141                 if (v_filter_1 == 0) v_filter_1 = 1;
1142                 v_filter_2 = v_filter_1;
1143         }
1144
1145         /* Now restore the filters */
1146         ivtv_yuv_filter (itv,h_filter,v_filter_1,v_filter_2);
1147
1148         /* and clear a few registers */
1149         write_reg(0, 0x02814);
1150         write_reg(0, 0x0282c);
1151         write_reg(0, 0x02904);
1152         write_reg(0, 0x02910);
1153
1154         /* Release the blanking buffer */
1155         if (itv->yuv_info.blanking_ptr) {
1156                 kfree (itv->yuv_info.blanking_ptr);
1157                 itv->yuv_info.blanking_ptr = NULL;
1158                 pci_unmap_single(itv->dev, itv->yuv_info.blanking_dmaptr, 720*16, PCI_DMA_TODEVICE);
1159         }
1160
1161         /* Invalidate the old dimension information */
1162         itv->yuv_info.old_frame_info.src_w = 0;
1163         itv->yuv_info.old_frame_info.src_h = 0;
1164         itv->yuv_info.old_frame_info_args.src_w = 0;
1165         itv->yuv_info.old_frame_info_args.src_h = 0;
1166
1167         /* All done. */
1168         clear_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags);
1169 }
1170