xref: /haiku/src/add-ons/accelerants/neomagic/engine/nm_bes.c (revision 39241fe22890fb958b6ba32d6ab9526da98be187)
1 /* NeoMagic Back End Scaler functions */
2 /* Written by Rudolf Cornelissen 05/2002-08/2004 */
3 
4 #define MODULE_BIT 0x00000200
5 
6 #include "nm_std.h"
7 
8 //fixme: implement: (used for virtual screens!)
9 //void move_overlay(uint16 hdisp_start, uint16 vdisp_start);
10 
11 status_t nm_configure_bes
12 	(const overlay_buffer *ob, const overlay_window *ow, const overlay_view *ov, int offset)
13 {
14 	/* yuy2 (4:2:2) colorspace calculations */
15 	/* Note: Some calculations will have to be modified for other colorspaces if they are incorporated. */
16 
17 	/* Note:
18 	 * in BeOS R5.0.3 and DANO:
19 	 * 'ow->offset_xxx' is always 0, so not used;
20 	 * 'ow->width' and 'ow->height' are the output window size: does not change
21 	 * if window is clipping;
22 	 * 'ow->h_start' and 'ow->v_start' are the left-top position of the output
23 	 * window. These values can be negative: this means the window is clipping
24 	 * at the left or the top of the display, respectively. */
25 
26 	/* 'ov' is the view in the source bitmap, so which part of the bitmap is actually
27 	 * displayed on screen. This is used for the 'hardware zoom' function. */
28 
29 	/* bes setup data */
30 	nm_bes_data bi;
31 	/* misc used variables */
32 	uint16 temp1, temp2;
33 	/* BES output coordinate system for virtual workspaces */
34 	uint16 crtc_hstart, crtc_vstart, crtc_hend, crtc_vend;
35 	/* inverse scaling factor, used for source positioning */
36 	uint32 ifactor;
37 	/* copy of overlay view which has checked valid values */
38 	overlay_view my_ov;
39 
40 
41 	/**************************************************************************************
42 	 *** copy, check and limit if needed the user-specified view into the intput bitmap ***
43 	 **************************************************************************************/
44 	my_ov = *ov;
45 	/* check for valid 'coordinates' */
46 	if (my_ov.width == 0) my_ov.width++;
47 	if (my_ov.height == 0) my_ov.height++;
48 	if (my_ov.h_start > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
49 		my_ov.h_start = ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1);
50 	if (((my_ov.h_start + my_ov.width) - 1) > ((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1))
51 		my_ov.width = ((((ob->width - si->overlay.myBufInfo[offset].slopspace) - 1) - my_ov.h_start) + 1);
52 	if (my_ov.v_start > (ob->height - 1))
53 		my_ov.v_start = (ob->height - 1);
54 	if (((my_ov.v_start + my_ov.height) - 1) > (ob->height - 1))
55 		my_ov.height = (((ob->height - 1) - my_ov.v_start) + 1);
56 
57 	LOG(6,("Overlay: inputbuffer view (zoom) left %d, top %d, width %d, height %d\n",
58 		my_ov.h_start, my_ov.v_start, my_ov.width, my_ov.height));
59 
60 	/* the BES does not respect virtual_workspaces, but adheres to CRTC
61 	 * constraints only */
62 	crtc_hstart = si->dm.h_display_start;
63 	/* horizontal end is the first position beyond the displayed range on the CRTC */
64 	crtc_hend = crtc_hstart + si->dm.timing.h_display;
65 	crtc_vstart = si->dm.v_display_start;
66 	/* vertical end is the first position beyond the displayed range on the CRTC */
67 	crtc_vend = crtc_vstart + si->dm.timing.v_display;
68 
69 
70 	/****************************************
71 	 *** setup all edges of output window ***
72 	 ****************************************/
73 
74 	/* setup left and right edges of output window */
75 	bi.hcoordv = 0;
76 	/* left edge coordinate of output window, must be inside desktop */
77 	/* clipping on the left side */
78 	if (ow->h_start < crtc_hstart)
79 	{
80 		temp1 = 0;
81 	}
82 	else
83 	{
84 		/* clipping on the right side */
85 		if (ow->h_start >= (crtc_hend - 1))
86 		{
87 			/* width < 2 is not allowed */
88 			temp1 = (crtc_hend - crtc_hstart - 2);
89 		}
90 		else
91 		/* no clipping here */
92 		{
93 			temp1 = (ow->h_start - crtc_hstart);
94 		}
95 	}
96 	bi.hcoordv |= temp1 << 16;
97 	/* right edge coordinate of output window, must be inside desktop */
98 	/* width < 2 is not allowed */
99 	if (ow->width < 2)
100 	{
101 		temp2 = (temp1 + 1);
102 	}
103 	else
104 	{
105 		/* clipping on the right side */
106 		if ((ow->h_start + ow->width - 1) > (crtc_hend - 1))
107 		{
108 			temp2 = (crtc_hend - crtc_hstart - 1);
109 		}
110 		else
111 		{
112 			/* clipping on the left side */
113 			if ((ow->h_start + ow->width - 1) < (crtc_hstart + 1))
114 			{
115 				/* width < 2 is not allowed */
116 				temp2 = 1;
117 			}
118 			else
119 			/* no clipping here */
120 			{
121 				temp2 = ((uint16)(ow->h_start + ow->width - crtc_hstart - 1));
122 			}
123 		}
124 	}
125 	bi.hcoordv |= temp2 << 0;
126 	LOG(4,("Overlay: CRTC left-edge output %d, right-edge output %d\n",temp1, temp2));
127 
128 	/* setup top and bottom edges of output window */
129 	bi.vcoordv = 0;
130 	/* top edge coordinate of output window, must be inside desktop */
131 	/* clipping on the top side */
132 	if (ow->v_start < crtc_vstart)
133 	{
134 		temp1 = 0;
135 	}
136 	else
137 	{
138 		/* clipping on the bottom side */
139 		if (ow->v_start >= (crtc_vend - 1))
140 		{
141 			/* height < 2 is not allowed */
142 			temp1 = (crtc_vend - crtc_vstart - 2);
143 		}
144 		else
145 		/* no clipping here */
146 		{
147 			temp1 = (ow->v_start - crtc_vstart);
148 		}
149 	}
150 	bi.vcoordv |= temp1 << 16;
151 	/* bottom edge coordinate of output window, must be inside desktop */
152 	/* height < 2 is not allowed */
153 	if (ow->height < 2)
154 	{
155 		temp2 = (temp1 + 1);
156 	}
157 	else
158 	{
159 		/* clipping on the bottom side */
160 		if ((ow->v_start + ow->height - 1) > (crtc_vend - 1))
161 		{
162 			temp2 = (crtc_vend - crtc_vstart - 1);
163 		}
164 		else
165 		{
166 			/* clipping on the top side */
167 			if ((ow->v_start + ow->height - 1) < (crtc_vstart + 1))
168 			{
169 				/* height < 2 is not allowed */
170 				temp2 = 1;
171 			}
172 			else
173 			/* no clipping here */
174 			{
175 				temp2 = ((uint16)(ow->v_start + ow->height - crtc_vstart - 1));
176 			}
177 		}
178 	}
179 	bi.vcoordv |= temp2 << 0;
180 	LOG(4,("Overlay: CRTC top-edge output %d, bottom-edge output %d\n",temp1, temp2));
181 
182 
183 	/*********************************************
184 	 *** setup horizontal scaling and clipping ***
185 	 *********************************************/
186 
187 	LOG(6,("Overlay: total input picture width = %d, height = %d\n",
188 			(ob->width - si->overlay.myBufInfo[offset].slopspace), ob->height));
189 	LOG(6,("Overlay: output picture width = %d, height = %d\n", ow->width, ow->height));
190 
191 	/* calculate inverse horizontal scaling factor, taking zoom into account */
192 	ifactor = ((((uint32)my_ov.width) << 12) / ow->width);
193 
194 	/* correct factor to prevent most-right visible 'line' from distorting */
195 	ifactor -= 1;
196 	bi.hiscalv = ifactor;
197 	LOG(4,("Overlay: horizontal scaling factor is %f\n", (float)4096 / ifactor));
198 
199 	/* check scaling factor (and modify if needed) to be within scaling limits */
200 	/* the upscaling limit is 8.0 (see official Neomagic specsheets) */
201 	if (bi.hiscalv < 0x00000200)
202 	{
203 		/* (non-inverse) factor too large, set factor to max. valid value */
204 		bi.hiscalv = 0x00000200;
205 		LOG(4,("Overlay: horizontal scaling factor too large, clamping at %f\n", (float)4096 / bi.hiscalv));
206 	}
207 	/* horizontal downscaling cannot be done by NM BES hardware */
208 	if (bi.hiscalv > (1 << 12))
209 	{
210 		/* (non-inverse) factor too small, set factor to min. valid value */
211 		bi.hiscalv = 0x1000;
212 		LOG(4,("Overlay: horizontal scaling factor too small, clamping at %f\n", (float)4096 / bi.hiscalv));
213 	}
214 
215 
216 	/* do horizontal clipping... */
217 	/* Setup horizontal source start: first (sub)pixel contributing to output picture */
218 	/* Note:
219 	 * The method is to calculate, based on 1:1 scaling, based on the output window.
220 	 * After this is done, include the scaling factor so you get a value based on the input bitmap.
221 	 * Then add the left starting position of the bitmap's view (zoom function) to get the final value needed.
222 	 * Note: The input bitmaps slopspace is automatically excluded from the calculations this way! */
223 	/* Note also:
224 	 * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
225 	bi.hsrcstv = 0;
226 	/* check for destination horizontal clipping at left side */
227 	if (ow->h_start < crtc_hstart)
228 	{
229 		/* check if entire destination picture is clipping left:
230 		 * (2 pixels will be clamped onscreen at least) */
231 		if ((ow->h_start + ow->width - 1) < (crtc_hstart + 1))
232 		{
233 			/* increase 'first contributing pixel' with 'fixed value': (total dest. width - 2) */
234 			bi.hsrcstv += (ow->width - 2);
235 		}
236 		else
237 		{
238 			/* increase 'first contributing pixel' with actual number of dest. clipping pixels */
239 			bi.hsrcstv += (crtc_hstart - ow->h_start);
240 		}
241 		LOG(4,("Overlay: clipping left...\n"));
242 
243 		/* The calculated value is based on scaling = 1x. So we now compensate for scaling.
244 		 * Note that this also already takes care of aligning the value to the BES register! */
245 		bi.hsrcstv *= (ifactor << 4);
246 	}
247 	/* take zoom into account */
248 	bi.hsrcstv += ((uint32)my_ov.h_start) << 16;
249 	LOG(4,("Overlay: first hor. (sub)pixel of input bitmap contributing %f\n", bi.hsrcstv / (float)65536));
250 
251 
252 	/* Setup horizontal source end: last (sub)pixel contributing to output picture */
253 	/* Note:
254 	 * The method is to calculate, based on 1:1 scaling, based on the output window.
255 	 * After this is done, include the scaling factor so you get a value based on the input bitmap.
256 	 * Then add the right ending position of the bitmap's view (zoom function) to get the final value needed. */
257 	/* Note also:
258 	 * Even if the scaling factor is clamping we instruct the BES to use the correct source end pos.! */
259 
260 	bi.hsrcendv = 0;
261 	/* check for destination horizontal clipping at right side */
262 	if ((ow->h_start + ow->width - 1) > (crtc_hend - 1))
263 	{
264 		/* check if entire destination picture is clipping right:
265 		 * (2 pixels will be clamped onscreen at least) */
266 		if (ow->h_start > (crtc_hend - 2))
267 		{
268 			/* increase 'number of clipping pixels' with 'fixed value': (total dest. width - 2) */
269 			bi.hsrcendv += (ow->width - 2);
270 		}
271 		else
272 		{
273 			/* increase 'number of clipping pixels' with actual number of dest. clipping pixels */
274 			bi.hsrcendv += ((ow->h_start + ow->width - 1) - (crtc_hend - 1));
275 		}
276 		LOG(4,("Overlay: clipping right...\n"));
277 
278 		/* The calculated value is based on scaling = 1x. So we now compensate for scaling.
279 		 * Note that this also already takes care of aligning the value to the BES register! */
280 		bi.hsrcendv *= (ifactor << 4);
281 		/* now subtract this value from the last used pixel in (zoomed) inputbuffer, aligned to BES */
282 		bi.hsrcendv = (((uint32)((my_ov.h_start + my_ov.width) - 1)) << 16) - bi.hsrcendv;
283 	}
284 	else
285 	{
286 		/* set last contributing pixel to last used pixel in (zoomed) inputbuffer, aligned to BES */
287 		bi.hsrcendv = (((uint32)((my_ov.h_start + my_ov.width) - 1)) << 16);
288 	}
289 	/* AND below required by hardware */
290 	bi.hsrcendv &= 0x03ffffff;
291 	LOG(4,("Overlay: last horizontal (sub)pixel of input bitmap contributing %f\n", bi.hsrcendv / (float)65536));
292 
293 
294 	/*******************************************
295 	 *** setup vertical scaling and clipping ***
296 	 *******************************************/
297 
298 	/* calculate inverse vertical scaling factor, taking zoom into account */
299 	ifactor = ((((uint32)my_ov.height) << 12) / ow->height);
300 
301 	/* correct factor to prevent lowest visible line from distorting */
302 	ifactor -= 1;
303 	LOG(4,("Overlay: vertical scaling factor is %f\n", (float)4096 / ifactor));
304 
305 	/* preserve ifactor for source positioning calculations later on */
306 	bi.viscalv = ifactor;
307 
308 	/* check scaling factor (and modify if needed) to be within scaling limits */
309 	/* the upscaling limit is 8.0 (see official Neomagic specsheets) */
310 	if (bi.viscalv < 0x00000200)
311 	{
312 		/* (non-inverse) factor too large, set factor to max. valid value */
313 		bi.viscalv = 0x00000200;
314 		LOG(4,("Overlay: vertical scaling factor too large, clamping at %f\n", (float)4096 / bi.viscalv));
315 	}
316 	/* vertical downscaling cannot be done by NM BES hardware */
317 	if (bi.viscalv > (1 << 12))
318 	{
319 		/* (non-inverse) factor too small, set factor to min. valid value */
320 		bi.viscalv = 0x1000;
321 		LOG(4,("Overlay: vertical scaling factor too small, clamping at %f\n", (float)4096 / bi.viscalv));
322 	}
323 
324 
325 	/* do vertical clipping... */
326 	/* Setup vertical source start: first (sub)pixel contributing to output picture.
327 	 * Note: this exists of two parts:
328 	 * 1. setup fractional part (sign is always 'positive');
329 	 * 2. setup relative base_adress, taking clipping on top (and zoom) into account.
330 	 * Both parts are done intertwined below. */
331 	/* Note:
332 	 * The method is to calculate, based on 1:1 scaling, based on the output window.
333 	 * 'After' this is done, include the scaling factor so you get a value based on the input bitmap.
334 	 * Then add the top starting position of the bitmap's view (zoom function) to get the final value needed. */
335 	/* Note also:
336 	 * Even if the scaling factor is clamping we instruct the BES to use the correct source start pos.! */
337 
338 	/* calculate relative base_adress and 'vertical weight fractional part' */
339 	bi.weight = 0;
340 	bi.a1orgv = (uint32)((vuint32 *)ob->buffer);
341 	bi.a1orgv -= (uint32)((vuint32 *)si->framebuffer);
342 	/* calculate origin adress */
343 	LOG(4,("Overlay: topleft corner of input bitmap (cardRAM offset) $%08x\n",bi.a1orgv));
344 	/* check for destination vertical clipping at top side */
345 	if (ow->v_start < crtc_vstart)
346 	{
347 		/* check if entire destination picture is clipping at top:
348 		 * (2 pixels will be clamped onscreen at least) */
349 		if ((ow->v_start + ow->height - 1) < (crtc_vstart + 1))
350 		{
351 			/* increase source buffer origin with 'fixed value':
352 			 * (integer part of ('total height - 2' of dest. picture in pixels * inverse scaling factor)) *
353 			 * bytes per row source picture */
354 			bi.weight = (ow->height - 2) * (ifactor << 4);
355 			bi.a1orgv += ((bi.weight >> 16) * ob->bytes_per_row);
356 		}
357 		else
358 		{
359 			/* increase source buffer origin with:
360 			 * (integer part of (number of destination picture clipping pixels * inverse scaling factor)) *
361 			 * bytes per row source picture */
362 			bi.weight = (crtc_vstart - ow->v_start) * (ifactor << 4);
363 			bi.a1orgv += ((bi.weight >> 16) * ob->bytes_per_row);
364 		}
365 		LOG(4,("Overlay: clipping at top...\n"));
366 	}
367 	/* take zoom into account */
368 	bi.a1orgv += (my_ov.v_start * ob->bytes_per_row);
369 	bi.weight += (((uint32)my_ov.v_start) << 16);
370 
371 	/* now include 'pixel precise' left clipping...
372 	 * (subpixel precision is not supported by NeoMagic cards) */
373 	bi.a1orgv += ((bi.hsrcstv >> 16) * 2);
374 	/* we need to step in 4-byte (2 pixel) granularity due to the nature of yuy2 */
375 	bi.a1orgv &= ~0x03;
376 	LOG(4,("Overlay: 'contributing part of buffer' origin is (cardRAM offset) $%08x\n",bi.a1orgv));
377 	LOG(4,("Overlay: first vert. (sub)pixel of input bitmap contributing %f\n", bi.weight / (float)65536));
378 
379 
380 	/*****************************
381 	 *** log color keying info ***
382 	 *****************************/
383 
384 	LOG(6,("Overlay: key_red %d, key_green %d, key_blue %d, key_alpha %d\n",
385 		ow->red.value, ow->green.value, ow->blue.value, ow->alpha.value));
386 	LOG(6,("Overlay: mask_red %d, mask_green %d, mask_blue %d, mask_alpha %d\n",
387 		ow->red.mask, ow->green.mask, ow->blue.mask, ow->alpha.mask));
388 
389 
390 	/*************************
391 	 *** setup BES control ***
392 	 *************************/
393 
394 	/* BES global control: setup functions */
395 	bi.globctlv = 0;
396 
397 	/* enable BES */
398 	bi.globctlv |= 1 << 0;
399 	/* enable colorkeying */
400 	bi.globctlv |= 1 << 1;
401 	/* b3 = 1: distorts right-half of overlay output. Keeping it zero. */
402 	/* colorspace is YV12, I420 or YUY2 (no RV15 or RV16) */
403 	bi.globctlv |= 0 << 5;
404 
405 	/* enable auto-alternating hardware buffers if alternating buffers is enabled (NM2160) */
406 	bi.globctlv |= 1 << 8;
407 	/* disable capture */
408 	bi.globctlv |= 1 << 13;
409 	/* capture: display one buffer (no alternating buffers) */
410 	bi.globctlv |= 0 << 14;
411 	/* capture: display frame (no field) */
412 	bi.globctlv |= 0 << 15;
413 
414 	/* BTW: horizontal and vertical filtering are always turned on in NM hardware. */
415 
416 
417 	/*************************************
418 	 *** sync to BES (Back End Scaler) ***
419 	 *************************************/
420 
421 	/* Make sure reprogramming the BES completes before the next retrace occurs,
422 	 * to prevent register-update glitches (double buffer feature). */
423 
424 	//fixme...
425 
426 //	LOG(3,("Overlay: starting register programming beyond Vcount %d\n", CR1R(VCOUNT)));
427 	/* Even at 1600x1200x90Hz, a single line still takes about 9uS to complete:
428 	 * this resolution will generate about 180Mhz pixelclock while we can do
429 	 * upto 360Mhz. So snooze about 4uS to prevent bus-congestion...
430 	 * Appr. 200 lines time will provide enough room even on a 100Mhz CPU if it's
431 	 * screen is set to the highest refreshrate/resolution possible. */
432 //	while (CR1R(VCOUNT) > (si->dm.timing.v_total - 200)) snooze(4);
433 
434 
435 	/**************************************
436 	 *** actually program the registers ***
437 	 **************************************/
438 
439 	if (si->ps.card_type >= NM2097)
440 	{
441 		/* helper: some cards use pixels to define buffer pitch, others use bytes */
442 		uint16 buf_pitch = ob->width;
443 
444 		/* PCI card */
445 		LOG(4,("Overlay: accelerant is programming BES\n"));
446 		/* unlock card overlay sequencer registers (b5 = 1) */
447 		PCIGRPHW(GENLOCK, (PCIGRPHR(GENLOCK) | 0x20));
448 		/* destination rectangle #1 (output window position and size) */
449 		PCIGRPHW(HD1COORD1L, ((bi.hcoordv >> 16) & 0xff));
450 		PCIGRPHW(HD1COORD2L, (bi.hcoordv & 0xff));
451 		PCIGRPHW(HD1COORD21H, (((bi.hcoordv >> 4) & 0xf0) | ((bi.hcoordv >> 24) & 0x0f)));
452 		PCIGRPHW(VD1COORD1L, ((bi.vcoordv >> 16) & 0xff));
453 		PCIGRPHW(VD1COORD2L, (bi.vcoordv & 0xff));
454 		PCIGRPHW(VD1COORD21H, (((bi.vcoordv >> 4) & 0xf0) | ((bi.vcoordv >> 24) & 0x0f)));
455 		/* scaling */
456 		PCIGRPHW(XSCALEL, (bi.hiscalv & 0xff));
457 		PCIGRPHW(XSCALEH, ((bi.hiscalv >> 8) & 0xff));
458 		PCIGRPHW(YSCALEL, (bi.viscalv & 0xff));
459 		PCIGRPHW(YSCALEH, ((bi.viscalv >> 8) & 0xff));
460 		/* inputbuffer #1 origin */
461 		/* (we don't program buffer #2 as it's unused.) */
462 		if (si->ps.card_type < NM2200)
463 		{
464 			bi.a1orgv >>= 1;
465 			/* horizontal source end does not use subpixelprecision: granularity is 8 pixels */
466 			/* notes:
467 			 * - correctly programming horizontal source end minimizes used bandwidth;
468 			 * - adding 9 below is in fact:
469 			 *   - adding 1 to round-up to the nearest whole source-end value
470 			       (making SURE we NEVER are a (tiny) bit too low);
471 			     - adding 1 to convert 'last used position' to 'number of used pixels';
472 			     - adding 7 to round-up to the nearest higher (or equal) valid register
473 			       value (needed because of it's 8-pixel granularity). */
474 			PCIGRPHW(0xbc, ((((bi.hsrcendv >> 16) + 9) >> 3) - 1));
475 		}
476 		else
477 		{
478 			/* NM2200 and later cards use bytes to define buffer pitch */
479 			buf_pitch <<= 1;
480 			/* horizontal source end does not use subpixelprecision: granularity is 16 pixels */
481 			/* notes:
482 			 * - programming this register just a tiny bit too low messes up vertical
483 			 *   scaling badly (also distortion stripes and flickering are reported)!
484 			 * - not programming this register correctly will mess-up the picture when
485 			 *   it's partly clipping on the right side of the screen...
486 			 * - make absolutely sure the engine can fetch the last pixel needed from
487 			 *   the sourcebitmap even if only to generate a tiny subpixel from it!
488 			 *   (see remarks for < NM2200 cards regarding programming this register) */
489 			PCIGRPHW(0xbc, ((((bi.hsrcendv >> 16) + 17) >> 4) - 1));
490 		}
491 		PCIGRPHW(BUF1ORGL, (bi.a1orgv & 0xff));
492 		PCIGRPHW(BUF1ORGM, ((bi.a1orgv >> 8) & 0xff));
493 		PCIGRPHW(BUF1ORGH, ((bi.a1orgv >> 16) & 0xff));
494 		/* ??? */
495 		PCIGRPHW(0xbd, 0x02);
496 		PCIGRPHW(0xbe, 0x00);
497 		/* b2 = 0: don't use horizontal mirroring (NM2160) */
498 		/* other bits do ??? */
499 		PCIGRPHW(0xbf, 0x02);
500 
501 		/* destination rectangle #2 (output window position and size) */
502 /*
503 	{
504 		uint16 left = 0;
505 		uint16 right = 128;
506 		uint16 top = 0;
507 		uint16 bottom = 128;
508 
509 		PCISEQW(HD2COORD1L, (left & 0xff));
510 		PCISEQW(HD2COORD2L, (right & 0xff));
511 		PCISEQW(HD2COORD21H, (((right >> 4) & 0xf0) | ((left >> 8) & 0x0f)));
512 		PCISEQW(VD2COORD1L, (top & 0xff));
513 		PCISEQW(VD2COORD2L, (bottom & 0xff));
514 		PCISEQW(VD2COORD21H, (((bottom >> 4) & 0xf0) | ((top >> 8) & 0x0f)));
515 	}
516 */
517 		/* ??? */
518 	    PCISEQW(0x1c, 0xfb);
519     	PCISEQW(0x1d, 0x00);
520 		PCISEQW(0x1e, 0xe2);
521     	PCISEQW(0x1f, 0x02);
522  		/* b1 = 0: disable alternating hardware buffers (NM2160) */
523 		/* other bits do ??? */
524  		PCISEQW(0x09, 0x11);
525 		/* we don't use PCMCIA Zoomed Video port capturing, set 1:1 scale just in case */
526 		/* (b6-4 = Y downscale = 100%, b2-0 = X downscale = 100%;
527 		 *  downscaling selectable in 12.5% steps on increasing setting by 1) */
528 		PCISEQW(ZVCAP_DSCAL, 0x00);
529 		/* global BES control */
530 		PCIGRPHW(BESCTRL1, (bi.globctlv & 0xff));
531 		PCISEQW(BESCTRL2, ((bi.globctlv >> 8) & 0xff));
532 
533 
534 		/**************************
535 		 *** setup color keying ***
536 		 **************************/
537 
538 		PCIGRPHW(COLKEY_R, (ow->red.value & ow->red.mask));
539 		PCIGRPHW(COLKEY_G, (ow->green.value & ow->green.mask));
540 		PCIGRPHW(COLKEY_B, (ow->blue.value & ow->blue.mask));
541 
542 
543 		/*************************
544 		 *** setup misc. stuff ***
545 		 *************************/
546 
547 		/* setup brightness to be 'neutral' (two's complement number) */
548 		PCIGRPHW(BRIGHTNESS, 0x00);
549 
550 		/* setup inputbuffer #1 pitch including slopspace */
551 		/* (we don't program the pitch for inputbuffer #2 as it's unused.) */
552 		PCIGRPHW(BUF1PITCHL, (buf_pitch & 0xff));
553 		PCIGRPHW(BUF1PITCHH, ((buf_pitch >> 8) & 0xff));
554 	}
555 	else
556 	{
557 		/* ISA card. Speed required, so:
558 		 * program entire sequence in kerneldriver in one context switch! */
559 		LOG(4,("Overlay: kerneldriver programs BES\n"));
560 
561 		/* complete BES info struct... */
562 		bi.card_type = si->ps.card_type;
563 		bi.colkey_r = (ow->red.value & ow->red.mask);
564 		bi.colkey_g = (ow->green.value & ow->green.mask);
565 		bi.colkey_b = (ow->blue.value & ow->blue.mask);
566 		bi.ob_width = ob->width;
567 		/* ... and call kerneldriver to program the BES */
568 		bi.magic = NM_PRIVATE_DATA_MAGIC;
569 		ioctl(fd, NM_PGM_BES, &bi, sizeof(bi));
570 	}
571 
572 	/* on a 500Mhz P3 CPU just logging a line costs 400uS (18-19 vcounts at 1024x768x60Hz)!
573 	 * programming the registers above actually costs 180uS here */
574 //	LOG(3,("Overlay: completed at Vcount %d\n", CR1R(VCOUNT)));
575 
576 	return B_OK;
577 }
578 
579 status_t nm_release_bes()
580 {
581 	/* setup BES control: disable scaler */
582 	if (si->ps.card_type >= NM2097)
583 	{
584 		/* PCI card */
585 		PCIGRPHW(BESCTRL1, 0x02);
586 		PCISEQW(BESCTRL2, 0xa0);
587 	}
588 	else
589 	{
590 		/* ISA card */
591 		ISAGRPHW(BESCTRL1, 0x02);
592 		ISASEQW(BESCTRL2, 0xa0);
593 	}
594 
595 	return B_OK;
596 }
597