xref: /haiku/src/add-ons/accelerants/nvidia/engine/nv_crtc2.c (revision 5d9e40fe9252c8f9c5e5e41594545bfa4419fcc7)
1 /* second CTRC functionality for GeForce cards */
2 /* Author:
3    Rudolf Cornelissen 11/2002-1/2004
4 */
5 
6 #define MODULE_BIT 0x00020000
7 
8 #include "nv_std.h"
9 
10 /*Adjust passed parameters to a valid mode line*/
11 status_t nv_crtc2_validate_timing(
12 	uint16 *hd_e,uint16 *hs_s,uint16 *hs_e,uint16 *ht,
13 	uint16 *vd_e,uint16 *vs_s,uint16 *vs_e,uint16 *vt
14 )
15 {
16 /* horizontal */
17 	/* make all parameters multiples of 8 */
18 	*hd_e &= 0xfff8;
19 	*hs_s &= 0xfff8;
20 	*hs_e &= 0xfff8;
21 	*ht   &= 0xfff8;
22 
23 	/* confine to required number of bits, taking logic into account */
24 	if (*hd_e > ((0x01ff - 2) << 3)) *hd_e = ((0x01ff - 2) << 3);
25 	if (*hs_s > ((0x01ff - 1) << 3)) *hs_s = ((0x01ff - 1) << 3);
26 	if (*hs_e > ( 0x01ff      << 3)) *hs_e = ( 0x01ff      << 3);
27 	if (*ht   > ((0x01ff + 5) << 3)) *ht   = ((0x01ff + 5) << 3);
28 
29 	/* NOTE: keep horizontal timing at multiples of 8! */
30 	/* confine to a reasonable width */
31 	if (*hd_e < 640) *hd_e = 640;
32 	if (*hd_e > 2048) *hd_e = 2048;
33 
34 	/* if hor. total does not leave room for a sensible sync pulse, increase it! */
35 	if (*ht < (*hd_e + 80)) *ht = (*hd_e + 80);
36 
37 	/* make sure sync pulse is not during display */
38 	if (*hs_e > (*ht - 8)) *hs_e = (*ht - 8);
39 	if (*hs_s < (*hd_e + 8)) *hs_s = (*hd_e + 8);
40 
41 	/* correct sync pulse if it is too long:
42 	 * there are only 5 bits available to save this in the card registers! */
43 	if (*hs_e > (*hs_s + 0xf8)) *hs_e = (*hs_s + 0xf8);
44 
45 /*vertical*/
46 	/* confine to required number of bits, taking logic into account */
47 	//fixme if needed: on GeForce cards there are 12 instead of 11 bits...
48 	if (*vd_e > (0x7ff - 2)) *vd_e = (0x7ff - 2);
49 	if (*vs_s > (0x7ff - 1)) *vs_s = (0x7ff - 1);
50 	if (*vs_e >  0x7ff     ) *vs_e =  0x7ff     ;
51 	if (*vt   > (0x7ff + 2)) *vt   = (0x7ff + 2);
52 
53 	/* confine to a reasonable height */
54 	if (*vd_e < 480) *vd_e = 480;
55 	if (*vd_e > 1536) *vd_e = 1536;
56 
57 	/*if vertical total does not leave room for a sync pulse, increase it!*/
58 	if (*vt < (*vd_e + 3)) *vt = (*vd_e + 3);
59 
60 	/* make sure sync pulse is not during display */
61 	if (*vs_e > (*vt - 1)) *vs_e = (*vt - 1);
62 	if (*vs_s < (*vd_e + 1)) *vs_s = (*vd_e + 1);
63 
64 	/* correct sync pulse if it is too long:
65 	 * there are only 4 bits available to save this in the card registers! */
66 	if (*vs_e > (*vs_s + 0x0f)) *vs_e = (*vs_s + 0x0f);
67 
68 	return B_OK;
69 }
70 
71 /*set a mode line - inputs are in pixels*/
72 status_t nv_crtc2_set_timing(display_mode target)
73 {
74 	uint8 temp;
75 
76 	uint32 htotal;		/*total horizontal total VCLKs*/
77 	uint32 hdisp_e;            /*end of horizontal display (begins at 0)*/
78 	uint32 hsync_s;            /*begin of horizontal sync pulse*/
79 	uint32 hsync_e;            /*end of horizontal sync pulse*/
80 	uint32 hblnk_s;            /*begin horizontal blanking*/
81 	uint32 hblnk_e;            /*end horizontal blanking*/
82 
83 	uint32 vtotal;		/*total vertical total scanlines*/
84 	uint32 vdisp_e;            /*end of vertical display*/
85 	uint32 vsync_s;            /*begin of vertical sync pulse*/
86 	uint32 vsync_e;            /*end of vertical sync pulse*/
87 	uint32 vblnk_s;            /*begin vertical blanking*/
88 	uint32 vblnk_e;            /*end vertical blanking*/
89 
90 	uint32 linecomp;	/*split screen and vdisp_e interrupt*/
91 
92 	LOG(4,("CRTC2: setting timing\n"));
93 
94 	/* Modify parameters as required by standard VGA */
95 	htotal = ((target.timing.h_total >> 3) - 5);
96 	hdisp_e = ((target.timing.h_display >> 3) - 1);
97 	hblnk_s = hdisp_e;
98 	hblnk_e = (htotal + 4);//0;
99 	hsync_s = (target.timing.h_sync_start >> 3);
100 	hsync_e = (target.timing.h_sync_end >> 3);
101 
102 	vtotal = target.timing.v_total - 2;
103 	vdisp_e = target.timing.v_display - 1;
104 	vblnk_s = vdisp_e;
105 	vblnk_e = (vtotal + 1);
106 	vsync_s = target.timing.v_sync_start;//-1;
107 	vsync_e = target.timing.v_sync_end;//-1;
108 
109 	/* prevent memory adress counter from being reset (linecomp may not occur) */
110 	linecomp = target.timing.v_display;
111 
112 	/* enable access to CRTC2 */
113 	CRTC2W(OWNER, 0x03);
114 
115 //fixme: flatpanel 'don't touch' update needed for 'Go' cards!?!
116 	if (true)
117 	{
118 		LOG(4,("CRTC2: CRT only mode, setting full timing...\n"));
119 
120 		/* log the mode that will be set */
121 		LOG(2,("CRTC2:\n\tHTOT:%x\n\tHDISPEND:%x\n\tHBLNKS:%x\n\tHBLNKE:%x\n\tHSYNCS:%x\n\tHSYNCE:%x\n\t",htotal,hdisp_e,hblnk_s,hblnk_e,hsync_s,hsync_e));
122 		LOG(2,("VTOT:%x\n\tVDISPEND:%x\n\tVBLNKS:%x\n\tVBLNKE:%x\n\tVSYNCS:%x\n\tVSYNCE:%x\n",vtotal,vdisp_e,vblnk_s,vblnk_e,vsync_s,vsync_e));
123 
124 		/* actually program the card! */
125 		/* unlock CRTC registers at index 0-7 */
126 		CRTC2W(VSYNCE, (CRTC2R(VSYNCE) & 0x7f));
127 		/* horizontal standard VGA regs */
128 		CRTC2W(HTOTAL, (htotal & 0xff));
129 		CRTC2W(HDISPE, (hdisp_e & 0xff));
130 		CRTC2W(HBLANKS, (hblnk_s & 0xff));
131 		/* also unlock vertical retrace registers in advance */
132 		CRTC2W(HBLANKE, ((hblnk_e & 0x1f) | 0x80));
133 		CRTC2W(HSYNCS, (hsync_s & 0xff));
134 		CRTC2W(HSYNCE, ((hsync_e & 0x1f) | ((hblnk_e & 0x20) << 2)));
135 
136 		/* vertical standard VGA regs */
137 		CRTC2W(VTOTAL, (vtotal & 0xff));
138 		CRTC2W(OVERFLOW,
139 		(
140 			((vtotal & 0x100) >> (8 - 0)) | ((vtotal & 0x200) >> (9 - 5)) |
141 			((vdisp_e & 0x100) >> (8 - 1)) | ((vdisp_e & 0x200) >> (9 - 6)) |
142 			((vsync_s & 0x100) >> (8 - 2)) | ((vsync_s & 0x200) >> (9 - 7)) |
143 			((vblnk_s & 0x100) >> (8 - 3)) | ((linecomp & 0x100) >> (8 - 4))
144 		));
145 		CRTC2W(PRROWSCN, 0x00); /* not used */
146 		CRTC2W(MAXSCLIN, (((vblnk_s & 0x200) >> (9 - 5)) | ((linecomp & 0x200) >> (9 - 6))));
147 		CRTC2W(VSYNCS, (vsync_s & 0xff));
148 		CRTC2W(VSYNCE, ((CRTC2R(VSYNCE) & 0xf0) | (vsync_e & 0x0f)));
149 		CRTC2W(VDISPE, (vdisp_e & 0xff));
150 		CRTC2W(VBLANKS, (vblnk_s & 0xff));
151 		CRTC2W(VBLANKE, (vblnk_e & 0xff));
152 		CRTC2W(LINECOMP, (linecomp & 0xff));
153 
154 		/* horizontal extended regs */
155 		//fixme: we reset bit4. is this correct??
156 		CRTC2W(HEB, (CRTC2R(HEB) & 0xe0) |
157 			(
158 		 	((htotal & 0x100) >> (8 - 0)) |
159 			((hdisp_e & 0x100) >> (8 - 1)) |
160 			((hblnk_s & 0x100) >> (8 - 2)) |
161 			((hsync_s & 0x100) >> (8 - 3))
162 			));
163 
164 		/* (mostly) vertical extended regs */
165 		CRTC2W(LSR,
166 			(
167 		 	((vtotal & 0x400) >> (10 - 0)) |
168 			((vdisp_e & 0x400) >> (10 - 1)) |
169 			((vsync_s & 0x400) >> (10 - 2)) |
170 			((vblnk_s & 0x400) >> (10 - 3)) |
171 			((hblnk_e & 0x040) >> (6 - 4))
172 			//fixme: we still miss one linecomp bit!?! is this it??
173 			//| ((linecomp & 0x400) >> 3)
174 			));
175 
176 		/* more vertical extended regs */
177 		CRTC2W(EXTRA,
178 			(
179 		 	((vtotal & 0x800) >> (11 - 0)) |
180 			((vdisp_e & 0x800) >> (11 - 2)) |
181 			((vsync_s & 0x800) >> (11 - 4)) |
182 			((vblnk_s & 0x800) >> (11 - 6))
183 			//fixme: do we miss another linecomp bit!?!
184 			));
185 
186 		/* setup 'large screen' mode */
187 		if (target.timing.h_display >= 1280)
188 			CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0xfb));
189 		else
190 			CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x04));
191 
192 		/* setup HSYNC & VSYNC polarity */
193 		LOG(2,("CRTC2: sync polarity: "));
194 		temp = NV_REG8(NV8_MISCR);
195 		if (target.timing.flags & B_POSITIVE_HSYNC)
196 		{
197 			LOG(2,("H:pos "));
198 			temp &= ~0x40;
199 		}
200 		else
201 		{
202 			LOG(2,("H:neg "));
203 			temp |= 0x40;
204 		}
205 		if (target.timing.flags & B_POSITIVE_VSYNC)
206 		{
207 			LOG(2,("V:pos "));
208 			temp &= ~0x80;
209 		}
210 		else
211 		{
212 			LOG(2,("V:neg "));
213 			temp |= 0x80;
214 		}
215 		NV_REG8(NV8_MISCW) = temp;
216 
217 		LOG(2,(", MISC reg readback: $%02x\n", NV_REG8(NV8_MISCR)));
218 	}
219 
220 	/* always disable interlaced operation */
221 	/* (interlace is supported on upto and including NV10, NV15, and NV30 and up) */
222 	CRTC2W(INTERLACE, 0xff);
223 
224 	return B_OK;
225 }
226 
227 status_t nv_crtc2_depth(int mode)
228 {
229 	uint8 viddelay = 0;
230 	uint32 genctrl = 0;
231 
232 	/* set VCLK scaling */
233 	switch(mode)
234 	{
235 	case BPP8:
236 		viddelay = 0x01;
237 		/* genctrl b4 & b5 reset: 'direct mode' */
238 		genctrl = 0x00101100;
239 		break;
240 	case BPP15:
241 		viddelay = 0x02;
242 		/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
243 		genctrl = 0x00100130;
244 		break;
245 	case BPP16:
246 		viddelay = 0x02;
247 		/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
248 		genctrl = 0x00101130;
249 		break;
250 	case BPP24:
251 		viddelay = 0x03;
252 		/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
253 		genctrl = 0x00100130;
254 		break;
255 	case BPP32:
256 		viddelay = 0x03;
257 		/* genctrl b4 & b5 set: 'indirect mode' (via colorpalette) */
258 		genctrl = 0x00101130;
259 		break;
260 	}
261 	/* enable access to CRTC2 */
262 	CRTC2W(OWNER, 0x03);
263 
264 	CRTC2W(PIXEL, ((CRTC2R(PIXEL) & 0xfc) | viddelay));
265 	DAC2W(GENCTRL, genctrl);
266 
267 	return B_OK;
268 }
269 
270 status_t nv_crtc2_dpms(bool display, bool h, bool v)
271 {
272 	uint8 temp;
273 
274 	LOG(4,("CRTC2: setting DPMS: "));
275 
276 	/* enable access to CRTC2 (and SEQUENCER2) */
277 	CRTC2W(OWNER, 0x03);
278 
279 	/* start synchronous reset: required before turning screen off! */
280 	SEQW(RESET, 0x01);
281 
282 	/* turn screen off */
283 	temp = SEQR(CLKMODE);
284 	if (display)
285 	{
286 		SEQW(CLKMODE, (temp & ~0x20));
287 
288 		/* end synchronous reset if display should be enabled */
289 		SEQW(RESET, 0x03);
290 
291 		LOG(4,("display on, "));
292 	}
293 	else
294 	{
295 		SEQW(CLKMODE, (temp | 0x20));
296 
297 		LOG(4,("display off, "));
298 	}
299 
300 	if (h)
301 	{
302 		CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0x7f));
303 		LOG(4,("hsync enabled, "));
304 	}
305 	else
306 	{
307 		CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x80));
308 		LOG(4,("hsync disabled, "));
309 	}
310 	if (v)
311 	{
312 		CRTC2W(REPAINT1, (CRTC2R(REPAINT1) & 0xbf));
313 		LOG(4,("vsync enabled\n"));
314 	}
315 	else
316 	{
317 		CRTC2W(REPAINT1, (CRTC2R(REPAINT1) | 0x40));
318 		LOG(4,("vsync disabled\n"));
319 	}
320 
321 	return B_OK;
322 }
323 
324 status_t nv_crtc2_dpms_fetch(bool *display, bool *h, bool *v)
325 {
326 	/* enable access to CRTC2 (and SEQUENCER2) */
327 	CRTC2W(OWNER, 0x03);
328 
329 	*display = !(SEQR(CLKMODE) & 0x20);
330 	*h = !(CRTC2R(REPAINT1) & 0x80);
331 	*v = !(CRTC2R(REPAINT1) & 0x40);
332 
333 	LOG(4,("CTRC2: fetched DPMS state:"));
334 	if (display) LOG(4,("display on, "));
335 	else LOG(4,("display off, "));
336 	if (h) LOG(4,("hsync enabled, "));
337 	else LOG(4,("hsync disabled, "));
338 	if (v) LOG(4,("vsync enabled\n"));
339 	else LOG(4,("vsync disabled\n"));
340 
341 	return B_OK;
342 }
343 
344 status_t nv_crtc2_set_display_pitch()
345 {
346 	uint32 offset;
347 
348 	LOG(4,("CRTC2: setting card pitch (offset between lines)\n"));
349 
350 	/* figure out offset value hardware needs */
351 	offset = si->fbc.bytes_per_row / 8;
352 
353 	LOG(2,("CRTC2: offset register set to: $%04x\n", offset));
354 
355 	/* enable access to CRTC2 */
356 	CRTC2W(OWNER, 0x03);
357 
358 	/* program the card */
359 	CRTC2W(PITCHL, (offset & 0x00ff));
360 	CRTC2W(REPAINT0, ((CRTC2R(REPAINT0) & 0x1f) | ((offset & 0x0700) >> 3)));
361 
362 	return B_OK;
363 }
364 
365 status_t nv_crtc2_set_display_start(uint32 startadd,uint8 bpp)
366 {
367 	uint32 timeout = 0;
368 
369 	LOG(4,("CRTC2: setting card RAM to be displayed bpp %d\n", bpp));
370 
371 	LOG(2,("CRTC2: startadd: $%08x\n", startadd));
372 	LOG(2,("CRTC2: frameRAM: $%08x\n", si->framebuffer));
373 	LOG(2,("CRTC2: framebuffer: $%08x\n", si->fbc.frame_buffer));
374 
375 	/* we might have no retraces during setmode! */
376 	/* wait 25mS max. for retrace to occur (refresh > 40Hz) */
377 	while (((NV_REG32(NV32_RASTER2) & 0x000007ff) < si->dm.timing.v_display) &&
378 			(timeout < (25000/10)))
379 	{
380 		/* don't snooze much longer or retrace might get missed! */
381 		snooze(10);
382 		timeout++;
383 	}
384 
385 	/* enable access to CRTC2 */
386 	CRTC2W(OWNER, 0x03);
387 
388 	/* upto 4Gb RAM adressing: must be used on NV10 and later! */
389 	/* NOTE:
390 	 * While this register also exists on pre-NV10 cards, it will
391 	 * wrap-around at 16Mb boundaries!! */
392 
393 	/* 30bit adress in 32bit words */
394 	NV_REG32(NV32_NV10FB2STADD32) = (startadd & 0xfffffffc);
395 
396 	/* set byte adress: (b0 - 1) */
397 	ATB2W(HORPIXPAN, ((startadd & 0x00000003) << 1));
398 
399 	return B_OK;
400 }
401 
402 status_t nv_crtc2_cursor_init()
403 {
404 	int i;
405 	uint32 * fb;
406 	/* cursor bitmap will be stored at the start of the framebuffer */
407 	const uint32 curadd = 0;
408 
409 	/* enable access to CRTC2 */
410 	CRTC2W(OWNER, 0x03);
411 
412 	/* set cursor bitmap adress ... */
413 	if (si->ps.laptop)
414 	{
415 		/* must be used this way on pre-NV10 and on all 'Go' cards! */
416 
417 		/* cursorbitmap must start on 2Kbyte boundary: */
418 		/* set adress bit11-16, and set 'no doublescan' (registerbit 1 = 0) */
419 		CRTC2W(CURCTL0, ((curadd & 0x0001f800) >> 9));
420 		/* set adress bit17-23, and set graphics mode cursor(?) (registerbit 7 = 1) */
421 		CRTC2W(CURCTL1, (((curadd & 0x00fe0000) >> 17) | 0x80));
422 		/* set adress bit24-31 */
423 		CRTC2W(CURCTL2, ((curadd & 0xff000000) >> 24));
424 	}
425 	else
426 	{
427 		/* upto 4Gb RAM adressing:
428 		 * can be used on NV10 and later (except for 'Go' cards)! */
429 		/* NOTE:
430 		 * This register does not exist on pre-NV10 and 'Go' cards. */
431 
432 		/* cursorbitmap must still start on 2Kbyte boundary: */
433 		NV_REG32(NV32_NV10CUR2ADD32) = (curadd & 0xfffff800);
434 	}
435 
436 	/* set cursor colour: not needed because of direct nature of cursor bitmap. */
437 
438 	/*clear cursor*/
439 	fb = (uint32 *) si->framebuffer + curadd;
440 	for (i=0;i<(2048/4);i++)
441 	{
442 		fb[i]=0;
443 	}
444 
445 	/* select 32x32 pixel, 16bit color cursorbitmap, no doublescan */
446 	NV_REG32(NV32_2CURCONF) = 0x02000100;
447 
448 	/* activate hardware cursor */
449 	nv_crtc2_cursor_show();
450 
451 	return B_OK;
452 }
453 
454 status_t nv_crtc2_cursor_show()
455 {
456 	LOG(4,("CRTC2: enabling cursor\n"));
457 
458 	/* enable access to CRTC2 */
459 	CRTC2W(OWNER, 0x03);
460 
461 	/* b0 = 1 enables cursor */
462 	CRTC2W(CURCTL0, (CRTC2R(CURCTL0) | 0x01));
463 
464 	return B_OK;
465 }
466 
467 status_t nv_crtc2_cursor_hide()
468 {
469 	LOG(4,("CRTC2: disabling cursor\n"));
470 
471 	/* enable access to CRTC2 */
472 	CRTC2W(OWNER, 0x03);
473 
474 	/* b0 = 0 disables cursor */
475 	CRTC2W(CURCTL0, (CRTC2R(CURCTL0) & 0xfe));
476 
477 	return B_OK;
478 }
479 
480 /*set up cursor shape*/
481 status_t nv_crtc2_cursor_define(uint8* andMask,uint8* xorMask)
482 {
483 	int x, y;
484 	uint8 b;
485 	uint16 *cursor;
486 	uint16 pixel;
487 
488 	/* get a pointer to the cursor */
489 	cursor = (uint16*) si->framebuffer;
490 
491 	/* draw the cursor */
492 	/* (Nvidia cards have a RGB15 direct color cursor bitmap, bit #16 is transparancy) */
493 	for (y = 0; y < 16; y++)
494 	{
495 		b = 0x80;
496 		for (x = 0; x < 8; x++)
497 		{
498 			/* preset transparant */
499 			pixel = 0x0000;
500 			/* set white if requested */
501 			if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
502 			/* set black if requested */
503 			if ((!(*andMask & b)) &&   (*xorMask & b))  pixel = 0x8000;
504 			/* set invert if requested */
505 			if (  (*andMask & b)  &&   (*xorMask & b))  pixel = 0x7fff;
506 			/* place the pixel in the bitmap */
507 			cursor[x + (y * 32)] = pixel;
508 			b >>= 1;
509 		}
510 		xorMask++;
511 		andMask++;
512 		b = 0x80;
513 		for (; x < 16; x++)
514 		{
515 			/* preset transparant */
516 			pixel = 0x0000;
517 			/* set white if requested */
518 			if ((!(*andMask & b)) && (!(*xorMask & b))) pixel = 0xffff;
519 			/* set black if requested */
520 			if ((!(*andMask & b)) &&   (*xorMask & b))  pixel = 0x8000;
521 			/* set invert if requested */
522 			if (  (*andMask & b)  &&   (*xorMask & b))  pixel = 0x7fff;
523 			/* place the pixel in the bitmap */
524 			cursor[x + (y * 32)] = pixel;
525 			b >>= 1;
526 		}
527 		xorMask++;
528 		andMask++;
529 	}
530 
531 	return B_OK;
532 }
533 
534 /* position the cursor */
535 status_t nv_crtc2_cursor_position(uint16 x, uint16 y)
536 {
537 	uint16 yhigh;
538 
539 	/* make sure we are beyond the first line of the cursorbitmap being drawn during
540 	 * updating the position to prevent distortions: no double buffering feature */
541 	/* Note:
542 	 * we need to return as quick as possible or some apps will exhibit lagging.. */
543 
544 	/* read the old cursor Y position */
545 	yhigh = ((DAC2R(CURPOS) & 0x0fff0000) >> 16);
546 	/* make sure we will wait until we are below both the old and new Y position:
547 	 * visible cursorbitmap drawing needs to be done at least... */
548 	if (y > yhigh) yhigh = y;
549 
550 	if (yhigh < (si->dm.timing.v_display - 16))
551 	{
552 		/* we have vertical lines below old and new cursorposition to spare. So we
553 		 * update the cursor postion 'mid-screen', but below that area. */
554 		while (((uint16)(NV_REG32(NV32_RASTER2) & 0x000007ff)) < (yhigh + 16))
555 		{
556 			snooze(10);
557 		}
558 	}
559 	else
560 	{
561 		/* no room to spare, just wait for retrace (is relatively slow) */
562 		while ((NV_REG32(NV32_RASTER2) & 0x000007ff) < si->dm.timing.v_display)
563 		{
564 			/* don't snooze much longer or retrace might get missed! */
565 			snooze(10);
566 		}
567 	}
568 
569 	/* update cursorposition */
570 	DAC2W(CURPOS, ((x & 0x0fff) | ((y & 0x0fff) << 16)));
571 
572 	return B_OK;
573 }
574