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