1/* Author:
2   Rudolf Cornelissen 4/2003-1/2006
3*/
4
5#define MODULE_BIT 0x00008000
6
7#include "nm_std.h"
8
9static status_t test_ram(void);
10static status_t nmxxxx_general_powerup (void);
11static status_t nm_general_bios_to_powergraphics(void);
12
13static void nm_dump_configuration_space (void)
14{
15#define DUMP_CFG(reg, type) if (si->ps.card_type >= type) do { \
16	uint32 value = CFGR(reg); \
17	MSG(("configuration_space 0x%02x %20s 0x%08x\n", \
18		NMCFG_##reg, #reg, value)); \
19} while (0)
20	DUMP_CFG (DEVID,	0);
21	DUMP_CFG (DEVCTRL,	0);
22	DUMP_CFG (CLASS,	0);
23	DUMP_CFG (HEADER,	0);
24	DUMP_CFG (BASE1FB,	0);
25	DUMP_CFG (BASE2REG1,0);
26	DUMP_CFG (BASE3REG2,0);
27	DUMP_CFG (BASE4,	0);
28	DUMP_CFG (BASE5,	0);
29	DUMP_CFG (BASE6,	0);
30	DUMP_CFG (BASE7,	0);
31	DUMP_CFG (SUBSYSID1,0);
32	DUMP_CFG (ROMBASE,	0);
33	DUMP_CFG (CAPPTR,	0);
34	DUMP_CFG (CFG_1,	0);
35	DUMP_CFG (INTERRUPT,0);
36	DUMP_CFG (CFG_3,	0);
37	DUMP_CFG (CFG_4,	0);
38	DUMP_CFG (CFG_5,	0);
39	DUMP_CFG (CFG_6,	0);
40	DUMP_CFG (CFG_7,	0);
41	DUMP_CFG (CFG_8,	0);
42	DUMP_CFG (CFG_9,	0);
43	DUMP_CFG (CFG_10,	0);
44	DUMP_CFG (CFG_11,	0);
45	DUMP_CFG (CFG_12,	0);
46	DUMP_CFG (CFG_13,	0);
47	DUMP_CFG (CFG_14,	0);
48	DUMP_CFG (CFG_15,	0);
49	DUMP_CFG (CFG_16,	0);
50	DUMP_CFG (CFG_17,	0);
51	DUMP_CFG (CFG_18,	0);
52	DUMP_CFG (CFG_19,	0);
53	DUMP_CFG (CFG_20,	0);
54	DUMP_CFG (CFG_21,	0);
55	DUMP_CFG (CFG_22,	0);
56	DUMP_CFG (CFG_23,	0);
57	DUMP_CFG (CFG_24,	0);
58	DUMP_CFG (CFG_25,	0);
59	DUMP_CFG (CFG_26,	0);
60	DUMP_CFG (CFG_27,	0);
61	DUMP_CFG (CFG_28,	0);
62	DUMP_CFG (CFG_29,	0);
63	DUMP_CFG (CFG_30,	0);
64	DUMP_CFG (CFG_31,	0);
65	DUMP_CFG (CFG_32,	0);
66	DUMP_CFG (CFG_33,	0);
67	DUMP_CFG (CFG_34,	0);
68	DUMP_CFG (CFG_35,	0);
69	DUMP_CFG (CFG_36,	0);
70	DUMP_CFG (CFG_37,	0);
71	DUMP_CFG (CFG_38,	0);
72	DUMP_CFG (CFG_39,	0);
73	DUMP_CFG (CFG_40,	0);
74	DUMP_CFG (CFG_41,	0);
75	DUMP_CFG (CFG_42,	0);
76	DUMP_CFG (CFG_43,	0);
77	DUMP_CFG (CFG_44,	0);
78	DUMP_CFG (CFG_45,	0);
79	DUMP_CFG (CFG_46,	0);
80	DUMP_CFG (CFG_47,	0);
81	DUMP_CFG (CFG_48,	0);
82	DUMP_CFG (CFG_49,	0);
83	DUMP_CFG (CFG_50,	0);
84#undef DUMP_CFG
85}
86
87status_t nm_general_powerup()
88{
89	status_t status;
90
91	LOG(1,("POWERUP: Haiku Neomagic Accelerant 0.14 running.\n"));
92
93	/* log VBLANK INT usability status */
94	if (si->ps.int_assigned)
95		LOG(4,("POWERUP: Usable INT assigned to HW; Vblank semaphore enabled\n"));
96	else
97		LOG(4,("POWERUP: No (usable) INT assigned to HW; Vblank semaphore disabled\n"));
98
99	/* WARNING:
100	 * _adi.name_ and _adi.chipset_ can contain 31 readable characters max.!!! */
101
102	/* detect card type and power it up */
103	switch(CFGR(DEVID))
104	{
105	case 0x000110c8: //NM2070 ISA
106		si->ps.card_type = NM2070;
107		sprintf(si->adi.name, "Neomagic MagicGraph 128");
108		sprintf(si->adi.chipset, "NM2070 (ISA)");
109		break;
110	case 0x000210c8: //NM2090 ISA
111		si->ps.card_type = NM2090;
112		sprintf(si->adi.name, "Neomagic MagicGraph 128V");
113		sprintf(si->adi.chipset, "NM2090 (ISA)");
114		break;
115	case 0x000310c8: //NM2093 ISA
116		si->ps.card_type = NM2093;
117		sprintf(si->adi.name, "Neomagic MagicGraph 128ZV");
118		sprintf(si->adi.chipset, "NM2093 (ISA)");
119		break;
120	case 0x008310c8: //NM2097 PCI
121		si->ps.card_type = NM2097;
122		sprintf(si->adi.name, "Neomagic MagicGraph 128ZV+");
123		sprintf(si->adi.chipset, "NM2097 (PCI)");
124		break;
125	case 0x000410c8: //NM2160 PCI
126		si->ps.card_type = NM2160;
127		sprintf(si->adi.name, "Neomagic MagicGraph 128XD");
128		sprintf(si->adi.chipset, "NM2160 (PCI)");
129		break;
130	case 0x000510c8: //NM2200
131		si->ps.card_type = NM2200;
132		sprintf(si->adi.name, "Neomagic MagicMedia 256AV");
133		sprintf(si->adi.chipset, "NM2200");
134		break;
135	case 0x002510c8: //NM2230
136		si->ps.card_type = NM2230;
137		sprintf(si->adi.name, "Neomagic MagicMedia 256AV+");
138		sprintf(si->adi.chipset, "NM2230");
139		break;
140	case 0x000610c8: //NM2360
141		si->ps.card_type = NM2360;
142		sprintf(si->adi.name, "Neomagic MagicMedia 256ZX");
143		sprintf(si->adi.chipset, "NM2360");
144		break;
145	case 0x001610c8: //NM2380
146		si->ps.card_type = NM2380;
147		sprintf(si->adi.name, "Neomagic MagicMedia 256XL+");
148		sprintf(si->adi.chipset, "NM2380");
149		break;
150	default:
151		LOG(8,("POWERUP: Failed to detect valid card 0x%08x\n",CFGR(DEVID)));
152		return B_ERROR;
153	}
154
155	/* power up the card */
156	status = nmxxxx_general_powerup();
157
158	/* override memory detection if requested by user */
159	if (si->settings.memory != 0)
160		si->ps.memory_size = si->settings.memory;
161
162	return status;
163}
164
165static status_t test_ram(void)
166{
167	uint32 value, offset;
168	status_t result = B_OK;
169
170	/* make sure we don't corrupt the hardware cursor by using fbc.frame_buffer. */
171	if (si->fbc.frame_buffer == NULL)
172	{
173		LOG(8,("INIT: test_ram detected NULL pointer.\n"));
174		return B_ERROR;
175	}
176
177	for (offset = 0, value = 0x55aa55aa; offset < 256; offset++)
178	{
179		/* write testpattern to cardRAM */
180		((uint32 *)si->fbc.frame_buffer)[offset] = value;
181		/* toggle testpattern */
182		value = 0xffffffff - value;
183	}
184
185	for (offset = 0, value = 0x55aa55aa; offset < 256; offset++)
186	{
187		/* readback and verify testpattern from cardRAM */
188		if (((uint32 *)si->fbc.frame_buffer)[offset] != value) result = B_ERROR;
189		/* toggle testpattern */
190		value = 0xffffffff - value;
191	}
192	return result;
193}
194
195/* NOTE:
196 * This routine *has* to be done *after* SetDispplayMode has been executed,
197 * or test results will not be representative!
198 * (CAS latency is dependant on nm setup on some (DRAM) boards) */
199status_t nm_set_cas_latency()
200{
201	/* check current RAM access to see if we need to change anything */
202	if (test_ram() == B_OK)
203	{
204		LOG(4,("INIT: RAM access OK.\n"));
205		return B_OK;
206	}
207
208	/* check if we read PINS at starttime so we have valid registersettings at our disposal */
209	LOG(4,("INIT: RAM access errors; not fixable: missing coldstart specs.\n"));
210	return B_ERROR;
211}
212
213void nm_unlock()
214{
215	/* unlock cards GRAPHICS registers (any other value than 0x26 should lock it again) */
216    ISAGRPHW(GRPHXLOCK, 0x26);
217}
218
219static status_t nmxxxx_general_powerup()
220{
221	uint8 temp;
222//	status_t result;
223
224	LOG(4, ("INIT: powerup\n"));
225	LOG(4, ("INIT: Detected %s (%s)\n", si->adi.name, si->adi.chipset));
226	if (si->settings.logmask & 0x80000000) nm_dump_configuration_space();
227
228	/* set ISA registermapping to VGA colormode */
229	temp = (ISARB(MISCR) | 0x01);
230	/* we need to wait a bit or the card will mess-up it's register values.. */
231	snooze(10);
232	ISAWB(MISCW, temp);
233
234	/* unlock cards GRAPHICS registers (any other value than 0x26 should lock it again) */
235    ISAGRPHW(GRPHXLOCK, 0x26);
236
237	/* unlock cards CRTC registers */
238//don't touch: most cards get into trouble on this!
239//	ISAGRPHW(GENLOCK, 0x00);
240
241	/* initialize the shared_info struct */
242	set_specs();
243	/* log the struct settings */
244	dump_specs();
245
246	/* activate PCI access: b7 = framebuffer, b6 = registers */
247	ISAGRPHW(IFACECTRL2, 0xc0);
248
249	/* disable VGA-mode cursor (just to be sure) */
250	ISACRTCW(VGACURCTRL, 0x00);
251
252	/* if the user doesn't want a coldstart OR the BIOS pins info could not be found warmstart */
253	/*if (si->settings.usebios || (result != B_OK)) */return nm_general_bios_to_powergraphics();
254
255	/*power up the PLLs,LUT,DAC*/
256	LOG(2,("INIT: powerup\n"));
257
258	/* turn off both displays and the hardcursor (also disables transfers) */
259	nm_crtc_dpms(false, false, false);
260	nm_crtc_cursor_hide();
261
262	/* setup sequencer clocking mode */
263	ISASEQW(CLKMODE, 0x21);
264
265	//fixme: setup coldstart capability...
266
267	/* turn on display */
268	nm_crtc_dpms(true, true, true);
269
270	return B_OK;
271}
272
273status_t nm_general_output_select()
274{
275	/* log currently selected output */
276	switch (nm_general_output_read() & 0x03)
277	{
278	case 0x01:
279		LOG(2, ("INIT: external CRT only mode active\n"));
280		break;
281	case 0x02:
282		LOG(2, ("INIT: internal LCD only mode active\n"));
283		break;
284	case 0x03:
285		LOG(2, ("INIT: simultaneous LCD/CRT mode active\n"));
286		break;
287	}
288	return B_OK;
289}
290
291uint8 nm_general_output_read()
292{
293	uint8 size_outputs;
294
295	/* read panelsize and currently active outputs */
296	size_outputs = ISAGRPHR(PANELCTRL1);
297
298	/* update noted currently active outputs if prudent:
299	 * - tracks active output devices, even if the keyboard shortcut is used because
300	 *   using that key will take the selected output devices out of DPMS sleep mode
301	 *   if programmed via these bits;
302	 * - when the shortcut key is not used, and DPMS was in a power-saving mode while
303	 *   programmed via these bits, an output device will (still) be shut-off. */
304	if (si->ps.card_type < NM2200)
305	{
306		/* both output devices do DPMS via these bits.
307		 * if one of the bits is on we have a valid setting if no power-saving mode
308		 * is active, or the keyboard shortcut key for selecting output devices has
309		 * been used during power-saving mode. */
310		if (size_outputs & 0x03) si->ps.outputs = (size_outputs & 0x03);
311	}
312	else
313	{
314		/* check if any power-saving mode active */
315		if 	(!(ISASEQR(CLKMODE) & 0x20))
316		{
317			/* screen is on:
318			 * we can 'safely' copy both output devices settings... */
319			if (size_outputs & 0x03)
320			{
321				si->ps.outputs = (size_outputs & 0x03);
322			}
323			else
324			{
325				/* ... unless no output is active, as this is illegal then */
326				si->ps.outputs = 0x02;
327
328				LOG(4, ("INIT: illegal outputmode detected, assuming internal mode!\n"));
329			}
330		}
331		else
332		{
333			/* screen is off:
334			 * only the internal panel does DPMS via these bits, so the external setting
335			 * can always be copied */
336			si->ps.outputs &= 0xfe;
337			si->ps.outputs |= (size_outputs & 0x01);
338			/* if the panel is on, we can note that (the shortcut key has been used) */
339			if (size_outputs & 0x02) si->ps.outputs |= 0x02;
340		}
341	}
342
343	return ((size_outputs & 0xfc) | (si->ps.outputs & 0x03));
344}
345
346/* basic change of card state from VGA to powergraphics -> should work from BIOS init state*/
347static
348status_t nm_general_bios_to_powergraphics()
349{
350	uint8 temp;
351
352	LOG(2, ("INIT: Skipping card coldstart!\n"));
353
354	/* turn off display */
355	nm_crtc_dpms(false, false, false);
356
357	/* set card to 'enhanced' mode: (only VGA standard registers used for NeoMagic cards) */
358	/* (keep) card enabled, set plain normal memory usage, no old VGA 'tricks' ... */
359	ISACRTCW(MODECTL, 0xc3);
360	/* ... plain sequential memory use, more than 64Kb RAM installed,
361	 * switch to graphics mode ... */
362	ISASEQW(MEMMODE, 0x0e);
363	/* ... disable bitplane tweaking ... */
364	/* note:
365	 * NeoMagic cards have custom b4-b7 use in this register! */
366	ISAGRPHW(ENSETRESET, 0x80);
367	/* ... no logical function tweaking with display data, no data rotation ... */
368	ISAGRPHW(DATAROTATE, 0x00);
369	/* ... reset read map select to plane 0 ... */
370	ISAGRPHW(READMAPSEL, 0x00);
371	/* ... set standard mode ... */
372	ISAGRPHW(MODE, 0x00);
373	/* ... ISA framebuffer mapping is 64Kb window, switch to graphics mode (again),
374	 * select standard adressing ... */
375	ISAGRPHW(MISC, 0x05);
376	/* ... disable bit masking ... */
377	ISAGRPHW(BITMASK, 0xff);
378	/* ... attributes are in color, switch to graphics mode (again) ... */
379	ISAATBW(MODECTL, 0x01);
380	/* ... set overscan color to black ... */
381	ISAATBW(OSCANCOLOR, 0x00);
382	/* ... enable all color planes ... */
383	ISAATBW(COLPLANE_EN, 0x0f);
384	/* ... reset horizontal pixelpanning ... */
385	ISAATBW(HORPIXPAN, 0x00);
386	/* ...  reset colorpalette groupselect bits ... */
387	ISAATBW(COLSEL, 0x00);
388	/* ... do unknown standard VGA register ... */
389	/* note:
390	 * NeoMagic cards have custom b6 use in this register! */
391	ISAATBW(0x16, 0x01);
392	/* ... and enable all four byteplanes. */
393	ISASEQW(MAPMASK, 0x0f);
394
395	/* setup sequencer clocking mode */
396	ISASEQW(CLKMODE, 0x21);
397
398	/* enable memory above 256Kb: set b4 (disables adress wraparound at 256Kb boundary) */
399	ISAGRPHW(FBSTADDE, 0x10);
400
401	/* this register has influence on the CRTC framebuffer offset, so reset! */
402	//fixme: investigate further...
403	ISAGRPHW(0x15, 0x00);
404
405	/* enable fast PCI write bursts (b4-5) */
406	temp = ((ISAGRPHR(IFACECTRL1) & 0x0f) | 0x30);
407	/* we need to wait a bit or the card will mess-up it's register values.. */
408	snooze(10);
409	ISAGRPHW(IFACECTRL1, temp);
410
411	/* this speeds up RAM writes according to XFree driver */
412//	fixme: don't touch until more is known: part of RAM or CORE PLL???
413//	ISAGRPHW(SPEED, 0xc0);
414
415	/* turn on display */
416	nm_crtc_dpms(true, true, true);
417
418	return B_OK;
419}
420
421/* Check if mode virtual_size adheres to the cards _maximum_ contraints, and modify
422 * virtual_size to the nearest valid maximum for the mode on the card if not so.
423 * Then: check if virtual_width adheres to the cards _multiple_ constraints, and
424 * create mode slopspace if not so.
425 * We use acc multiple constraints here if we expect we can use acceleration, because
426 * acc constraints are worse than CRTC constraints.
427 *
428 * Mode slopspace is reflected in fbc->bytes_per_row BTW. */
429status_t nm_general_validate_pic_size (display_mode *target, uint32 *bytes_per_row, bool *acc_mode)
430{
431	/* Note:
432	 * This routine assumes that the CRTC memory pitch granularity is 'smaller than',
433	 * or 'equals' the acceleration engine memory pitch granularity! */
434
435	uint32 video_pitch = 0;
436	uint32 crtc_mask;
437	uint8 depth = 8;
438
439	/* determine pixel multiple based on CRTC memory pitch constraints.
440	 * (Note: Don't mix this up with CRTC timing contraints! Those are
441	 *        multiples of 8 for horizontal, 1 for vertical timing.)
442	 *
443	 * CRTC pitch constraints are 'officially' the same for all Neomagic cards */
444	switch (si->ps.card_type)
445	{
446	case NM2070:
447		switch (target->space)
448		{
449			case B_CMAP8: crtc_mask = 0x07; depth =  8; break;
450			/* Note for NM2070 only:
451			 * The following depths have bandwidth trouble (pixel noise) with the
452			 * 'official' crtc_masks (used as defaults below). Masks of 0x1f are
453			 * needed (confirmed 15 and 16 bit spaces) to minimize this. */
454			//fixme: doublecheck for NM2090 and NM2093: correct code if needed!
455			case B_RGB15: crtc_mask = 0x1f; depth = 16; break;
456			case B_RGB16: crtc_mask = 0x1f; depth = 16; break;
457			case B_RGB24: crtc_mask = 0x1f; depth = 24; break;
458			default:
459				LOG(8,("INIT: unsupported colorspace: 0x%08x\n", target->space));
460				return B_ERROR;
461		}
462		break;
463	default:
464		switch (target->space)
465		{
466			case B_CMAP8: crtc_mask = 0x07; depth =  8; break;
467			case B_RGB15: crtc_mask = 0x03; depth = 16; break;
468			case B_RGB16: crtc_mask = 0x03; depth = 16; break;
469			case B_RGB24: crtc_mask = 0x07; depth = 24; break;
470			default:
471				LOG(8,("INIT: unsupported colorspace: 0x%08x\n", target->space));
472				return B_ERROR;
473		}
474		break;
475	}
476
477	/* check if we can setup this mode with acceleration: */
478	*acc_mode = true;
479
480	/* pre-NM2200 cards don't support accelerated 24bit modes */
481	if ((si->ps.card_type < NM2200) && (target->space == B_RGB24)) *acc_mode = false;
482
483	/* virtual_width */
484	if (si->ps.card_type == NM2070)
485	{
486		/* confirmed NM2070 */
487		if (target->virtual_width > 1024) *acc_mode = false;
488	}
489	else
490	{
491		/* confirmed for all cards */
492		if (target->virtual_width > 1600) *acc_mode = false;
493	}
494
495	/* virtual_height (confirmed NM2070, NM2097, NM2160 and NM2200 */
496	if (target->virtual_height > 1024) *acc_mode = false;
497
498	/* now check virtual_size based on CRTC constraints and modify if needed */
499//fixme: checkout cardspecs here!! (NM2160 can do 8192 _bytes_ at least (in theory))
500	{
501		/* virtual_width */
502		switch(target->space)
503		{
504		case B_CMAP8:
505			if (target->virtual_width > 16368)
506				target->virtual_width = 16368;
507			break;
508		case B_RGB15_LITTLE:
509		case B_RGB16_LITTLE:
510			if (target->virtual_width > 8184)
511				target->virtual_width = 8184;
512			break;
513		case B_RGB24_LITTLE:
514			if (target->virtual_width > 5456)
515				target->virtual_width = 5456;
516			break;
517		}
518
519		/* virtual_height: The only constraint here is the cards memory size which is
520		 * checked later on in ProposeMode: virtual_height is adjusted then if needed.
521		 * 'Limiting here' to the variable size that's at least available (uint16). */
522		if (target->virtual_height > 65535) target->virtual_height = 65535;
523	}
524
525	/* OK, now we know that virtual_width is valid, and it's needing no slopspace if
526	 * it was confined above, so we can finally calculate safely if we need slopspace
527	 * for this mode... */
528	if (*acc_mode)
529	{
530		if (si->ps.card_type == NM2070)
531		{
532			uint32 acc_mask = 0;
533
534			/* determine pixel multiple based on 2D engine constraints */
535			switch (target->space)
536			{
537				case B_CMAP8: acc_mask = 0x07; break;
538				/* Note:
539				 * The following depths have actual acc_masks of 0x03. 0x1f is used
540				 * because on lower acc_masks more bandwidth trouble arises.
541				 * (pixel noise) */
542				//fixme: doublecheck for NM2090 and NM2093: correct code if needed!
543				case B_RGB15: acc_mask = 0x1f; break;
544				case B_RGB16: acc_mask = 0x1f; break;
545			}
546			video_pitch = ((target->virtual_width + acc_mask) & ~acc_mask);
547		}
548		else
549		{
550			/* Note:
551			 * We prefer unaccelerated modes above accelerated ones here if not enough
552			 * RAM exists and the mode can be closer matched to the requested one if
553			 * unaccelerated. We do this because of the large amount of slopspace
554			 * sometimes needed here to keep a mode accelerated. */
555
556			uint32 mem_avail, bytes_X_height;
557
558			/* calculate amount of available memory */
559			mem_avail = (si->ps.memory_size * 1024);
560			if (si->settings.hardcursor) mem_avail -= si->ps.curmem_size;
561			/* helper */
562			bytes_X_height = (depth >> 3) * target->virtual_height;
563
564			/* Accelerated modes work with a table, there are very few fixed settings.. */
565			if (target->virtual_width == 640) video_pitch = 640;
566			else
567				if (target->virtual_width <= 800)
568				{
569					if (((800 * bytes_X_height) > mem_avail) &&
570						(target->virtual_width < (800 - crtc_mask)))
571						*acc_mode = false;
572					else
573						video_pitch = 800;
574				}
575				else
576					if (target->virtual_width <= 1024)
577					{
578						if (((1024 * bytes_X_height) > mem_avail) &&
579							(target->virtual_width < (1024 - crtc_mask)))
580							*acc_mode = false;
581						else
582							video_pitch = 1024;
583					}
584					else
585						if (target->virtual_width <= 1152)
586						{
587							if (((1152 * bytes_X_height) > mem_avail) &&
588								(target->virtual_width < (1152 - crtc_mask)))
589								*acc_mode = false;
590							else
591								video_pitch = 1152;
592						}
593						else
594							if (target->virtual_width <= 1280)
595							{
596								if (((1280 * bytes_X_height) > mem_avail) &&
597									(target->virtual_width < (1280 - crtc_mask)))
598									*acc_mode = false;
599								else
600									video_pitch = 1280;
601							}
602							else
603								if (target->virtual_width <= 1600)
604								{
605									if (((1600 * bytes_X_height) > mem_avail) &&
606										(target->virtual_width < (1600 - crtc_mask)))
607										*acc_mode = false;
608									else
609										video_pitch = 1600;
610								}
611		}
612	}
613	if (!*acc_mode)
614		video_pitch = ((target->virtual_width + crtc_mask) & ~crtc_mask);
615
616	LOG(2,("INIT: memory pitch will be set to %d pixels for colorspace 0x%08x\n",
617														video_pitch, target->space));
618	if (target->virtual_width != video_pitch)
619		LOG(2,("INIT: effective mode slopspace is %d pixels\n",
620											(video_pitch - target->virtual_width)));
621
622	/* now calculate bytes_per_row for this mode */
623	*bytes_per_row = video_pitch * (depth >> 3);
624
625	return B_OK;
626}
627