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