xref: /haiku/src/system/boot/platform/atari_m68k/video.cpp (revision f2b4344867e97c3f4e742a1b4a15e6879644601a)
1 /*
2  * Copyright 2008-2010, François Revol, revol@free.fr. All rights reserved.
3  * Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "toscalls.h"
9 #include "video.h"
10 #include "mmu.h"
11 //#include "images.h"
12 
13 #include <arch/cpu.h>
14 #include <boot/stage2.h>
15 #include <boot/platform.h>
16 #include <boot/menu.h>
17 #include <boot/kernel_args.h>
18 #include <boot/platform/generic/video.h>
19 #include <util/list.h>
20 #include <drivers/driver_settings.h>
21 #include <GraphicsDefs.h>
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 
28 #define TRACE_VIDEO
29 #ifdef TRACE_VIDEO
30 #	define TRACE(x) dprintf x
31 #else
32 #	define TRACE(x) ;
33 #endif
34 
35 
36 static void
37 dump_vars() {
38 	dprintf("v_bas_ad: %d\n", *TOSVAR_v_bas_ad);
39 	dprintf("Physbase %p\n", Physbase());
40 	dprintf("Logbase %p\n", Logbase());
41 
42 }
43 
44 // There are several API available to set video modes on atari platforms,
45 // cf. http://toshyp.atari.org/en/004.html
46 
47 class ModeOps {
48 public:
49 	ModeOps(const char *name) { fName = name; fInitStatus = B_NO_INIT; };
50 	~ModeOps() {};
51 	const char *Name() const { return fName; };
52 	virtual status_t	Init() { fInitStatus = B_OK; };
53 	status_t	InitStatus() const { return fInitStatus; };
54 	struct video_mode	*AllocMode();
55 
56 	// mode handling
57 	virtual status_t	Enumerate() = 0;
58 	virtual status_t	Decode(int16 id, struct video_mode *mode);
59 	virtual status_t	Get(struct video_mode *mode) = 0;
60 	virtual status_t	Set(const struct video_mode *mode) = 0;
61 	virtual status_t	Unset(const struct video_mode *mode) { return B_OK; };
62 
63 	// current settings
64 	virtual status_t	SetPalette(const struct video_mode *mode,
65 							const uint8 *palette) { return B_OK; };
66 	virtual addr_t		Framebuffer() { return NULL; };
67 
68 	virtual int16	Width(const struct video_mode *mode=NULL);
69 	virtual int16	Height(const struct video_mode *mode=NULL);
70 	virtual int16	Depth(const struct video_mode *mode=NULL);
71 	virtual int16	BytesPerRow(const struct video_mode *mode=NULL);
72 
73 	virtual void	MakeLabel(const struct video_mode *mode, char *label,
74 						size_t len);
75 
76 private:
77 	const char *fName;
78 protected:
79 	status_t fInitStatus;
80 };
81 
82 struct video_mode {
83 	list_link	link;
84 	ModeOps		*ops;
85 	color_space	space;
86 	uint16		mode;
87 	uint16		width, height, bits_per_pixel;
88 	uint32		bytes_per_row;
89 status_t	Set() { ops->Set(this); };
90 status_t	Unset() { ops->Unset(this); };
91 };
92 
93 static struct list sModeList;
94 static video_mode *sMode, *sDefaultMode;
95 static uint32 sModeCount;
96 static addr_t sFrameBuffer;
97 static bool sModeChosen;
98 
99 
100 static int
101 compare_video_modes(video_mode *a, video_mode *b)
102 {
103 	int compare = a->width - b->width;
104 	if (compare != 0)
105 		return compare;
106 
107 	compare = a->height - b->height;
108 	if (compare != 0)
109 		return compare;
110 
111 	compare = a->bits_per_pixel - b->bits_per_pixel;
112 	if (compare != 0)
113 		return compare;
114 
115 	compare = a->mode - b->mode;
116 	if (compare != 0)
117 		return compare;
118 
119 	return 0;
120 }
121 
122 
123 /*!	Insert the video mode into the list, sorted by resolution and bit depth.
124 	Higher resolutions/depths come first.
125 */
126 static void
127 add_video_mode(video_mode *videoMode)
128 {
129 	video_mode *mode = NULL;
130 	while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
131 			!= NULL) {
132 		int compare = compare_video_modes(videoMode, mode);
133 		if (compare == 0) {
134 			// mode already exists
135 			return;
136 		}
137 
138 		if (compare > 0)
139 			break;
140 	}
141 
142 	list_insert_item_before(&sModeList, mode, videoMode);
143 	sModeCount++;
144 }
145 
146 //	#pragma mark -
147 
148 
149 struct video_mode *
150 ModeOps::AllocMode()
151 {
152 
153 	video_mode *videoMode = (video_mode *)malloc(sizeof(struct video_mode));
154 	if (videoMode == NULL)
155 		return NULL;
156 
157 	videoMode->ops = this;
158 	return videoMode;
159 }
160 
161 status_t
162 ModeOps::Decode(int16 id, struct video_mode *mode)
163 {
164 	mode->ops = this;
165 	mode->mode = id;
166 	return B_OK;
167 }
168 
169 
170 int16
171 ModeOps::Width(const struct video_mode *mode)
172 {
173 	return mode ? mode->width : 0;
174 }
175 
176 
177 int16
178 ModeOps::Height(const struct video_mode *mode)
179 {
180 	return mode ? mode->height : 0;
181 }
182 
183 
184 int16
185 ModeOps::Depth(const struct video_mode *mode)
186 {
187 	return mode ? mode->bits_per_pixel : 0;
188 }
189 
190 
191 int16
192 ModeOps::BytesPerRow(const struct video_mode *mode)
193 {
194 	return mode ? mode->bytes_per_row : 0;
195 }
196 
197 
198 void
199 ModeOps::MakeLabel(const struct video_mode *mode, char *label, size_t len)
200 {
201 	sprintf(label, "%ux%u %u bit (%s)", mode->width, mode->height,
202 			mode->bits_per_pixel, mode->ops->Name());
203 
204 }
205 
206 
207 //	#pragma mark - ST/TT XBIOS API
208 
209 class STModeOps : public ModeOps {
210 public:
211 	STModeOps() : ModeOps("ST/TT") {};
212 	~STModeOps() {};
213 	virtual status_t	Init();
214 
215 	virtual status_t	Enumerate();
216 	virtual status_t	Decode(int16 id, struct video_mode *mode);
217 	virtual status_t	Get(struct video_mode *mode);
218 	virtual status_t	Set(const struct video_mode *mode);
219 	virtual status_t	Unset(const struct video_mode *mode);
220 
221 	virtual status_t	SetPalette(const struct video_mode *mode,
222 							const uint8 *palette);
223 	virtual addr_t		Framebuffer();
224 	virtual void		MakeLabel(const struct video_mode *mode,
225 							char *label, size_t len);
226 private:
227 	static int16		fPreviousMode;
228 	static bool			fIsTT;
229 };
230 
231 
232 int16 STModeOps::fPreviousMode = -1;
233 bool STModeOps::fIsTT = false;
234 
235 
236 status_t
237 STModeOps::Init()
238 {
239 	const tos_cookie *c = tos_find_cookie('_VDO');
240 	if (c == NULL)
241 		return ENODEV;
242 	if (c->ivalue >> 16 < 1)
243 		return ENODEV;
244 	if (c->ivalue >= 2)
245 		fIsTT = true;
246 	fInitStatus = B_OK;
247 	return fInitStatus;
248 }
249 
250 
251 
252 status_t
253 STModeOps::Enumerate()
254 {
255 	if (fInitStatus < B_OK)
256 		return fInitStatus;
257 
258 	static int16 modes[] = { 0, /*TT:*/ 4, 7 };
259 	for (int i = 0; i < sizeof(modes) / sizeof(int16); i++) {
260 		if (!fIsTT && i > 0)
261 			break;
262 
263 		video_mode *videoMode = AllocMode();
264 		if (videoMode == NULL)
265 			continue;
266 
267 		if (Decode(modes[i], videoMode) != B_OK)
268 			continue;
269 		add_video_mode(videoMode);
270 
271 	}
272 	return B_OK;
273 
274 #if 0
275 	// TODO: use TT video monitor detection and build possible mode list there...
276 	return ENODEV;
277 #endif
278 }
279 
280 
281 status_t
282 STModeOps::Decode(int16 id, struct video_mode *mode)
283 {
284 	mode->ops = this;
285 	mode->mode = id;
286 
287 	switch (id) {
288 		case 0:
289 			mode->width = 320;
290 			mode->height = 200;
291 			mode->bits_per_pixel = 4;
292 			break;
293 		case 4:
294 			mode->width = 640;
295 			mode->height = 480;
296 			mode->bits_per_pixel = 4;
297 			break;
298 		case 7:
299 			mode->width = 320;
300 			mode->height = 480;
301 			mode->bits_per_pixel = 8;
302 			break;
303 		default:
304 			mode->bits_per_pixel = 0;
305 			break;
306 	}
307 
308 	mode->bytes_per_row = mode->width * mode->bits_per_pixel / 8;
309 	return B_OK;
310 }
311 
312 
313 status_t
314 STModeOps::Get(struct video_mode *mode)
315 {
316 	if (fInitStatus < B_OK)
317 		return fInitStatus;
318 
319 	int16 m = Getrez();
320 	return Decode(m, mode);
321 }
322 
323 
324 status_t
325 STModeOps::Set(const struct video_mode *mode)
326 {
327 	if (fInitStatus < B_OK)
328 		return fInitStatus;
329 	if (mode == NULL)
330 		return B_BAD_VALUE;
331 
332 	fPreviousMode = Getrez();
333 
334 #warning M68K: FIXME: allocate framebuffer
335 	dprintf("Switching to mode 0x%04x\n", mode->mode);
336 	//VsetScreen(((uint32)0x00d00000), ((uint32)0x00d00000), 3, mode->mode);
337 	Setscreen(-1, -1, mode->mode, 0);
338 	if (Getrez() != mode->mode) {
339 		dprintf("failed to set mode %d. Current is %d\n", mode->mode, fPreviousMode);
340 		fPreviousMode = -1;
341 	}
342 
343 	return B_OK;
344 }
345 
346 
347 status_t
348 STModeOps::Unset(const struct video_mode *mode)
349 {
350 	if (fInitStatus < B_OK)
351 		return fInitStatus;
352 
353 	if (fPreviousMode != -1) {
354 		dprintf("Reverting to mode 0x%04x\n", fPreviousMode);
355 		Setscreen(-1, -1, fPreviousMode, 0);
356 		fPreviousMode = -1;
357 	}
358 
359 	return B_OK;
360 }
361 
362 
363 status_t
364 STModeOps::SetPalette(const struct video_mode *mode, const uint8 *palette)
365 {
366 	switch (mode->bits_per_pixel) {
367 		case 4:
368 			//VsetRGB(0, 16, palette);
369 			//XXX: Use ESet*
370 			break;
371 		case 8:
372 			//VsetRGB(0, 256, palette);
373 			//XXX: Use ESet*
374 			break;
375 		default:
376 			break;
377 	}
378 }
379 
380 
381 addr_t
382 STModeOps::Framebuffer()
383 {
384 	addr_t fb = (addr_t)Physbase();
385 	return fb;
386 }
387 
388 
389 void
390 STModeOps::MakeLabel(const struct video_mode *mode, char *label,
391 	size_t len)
392 {
393 	ModeOps::MakeLabel(mode, label, len);
394 	label += strlen(label);
395 	// XXX no len check
396 	sprintf(label, " 0x%04x", mode->mode);
397 }
398 
399 
400 static STModeOps sSTModeOps;
401 
402 
403 //	#pragma mark - Falcon XBIOS API
404 
405 class FalconModeOps : public ModeOps {
406 public:
407 	FalconModeOps() : ModeOps("Falcon") {};
408 	~FalconModeOps() {};
409 	virtual status_t	Init();
410 
411 	virtual status_t	Enumerate();
412 	virtual status_t	Decode(int16 id, struct video_mode *mode);
413 	virtual status_t	Get(struct video_mode *mode);
414 	virtual status_t	Set(const struct video_mode *mode);
415 	virtual status_t	Unset(const struct video_mode *mode);
416 
417 	virtual status_t	SetPalette(const struct video_mode *mode,
418 							const uint8 *palette);
419 	virtual addr_t		Framebuffer();
420 	virtual void		MakeLabel(const struct video_mode *mode,
421 							char *label, size_t len);
422 private:
423 	static int16		fPreviousMode;
424 };
425 
426 
427 int16 FalconModeOps::fPreviousMode = -1;
428 
429 
430 status_t
431 FalconModeOps::Init()
432 {
433 	const tos_cookie *c = tos_find_cookie('_VDO');
434 	if (c == NULL)
435 		return ENODEV;
436 	if (c->ivalue < 0x00030000)
437 		return ENODEV;
438 	fInitStatus = B_OK;
439 	return fInitStatus;
440 }
441 
442 
443 
444 status_t
445 FalconModeOps::Enumerate()
446 {
447 	if (fInitStatus < B_OK)
448 		return fInitStatus;
449 
450 	static int16 modes[] = {
451 		0x001b, 0x001c, 0x002b, 0x002c,
452 		0x003a, 0x003b, 0x003c, 0x000c,
453 		0x0034, 0x0004
454 		/*0x003a, 0x003b, 0x0003, 0x000c,
455 		0x000b, 0x0033, 0x000c, 0x001c*/ };
456 	for (int i = 0; i < sizeof(modes) / sizeof(int16); i++) {
457 		video_mode *videoMode = AllocMode();
458 		if (videoMode == NULL)
459 			continue;
460 
461 		if (Decode(modes[i], videoMode) != B_OK)
462 			continue;
463 		add_video_mode(videoMode);
464 
465 	}
466 	return B_OK;
467 
468 #if 0
469 	// TODO: use falcon video monitor detection and build possible mode list there...
470 	int16 monitor;
471 	bool vga = false;
472 	bool tv = false;
473 	monitor = VgetMonitor();
474 	switch (monitor) {
475 		case 0:
476 			panic("Monochrome ?\n");
477 			break;
478 		case 2:
479 			vga = true;
480 			break;
481 		case 3:
482 			tv = true;
483 			break;
484 		//case 4 & 5: check for CT60
485 		case 1:
486 		default:
487 			dprintf("monitor type %d\n", monitor);
488 			break;
489 	}
490 	return ENODEV;
491 #endif
492 }
493 
494 
495 status_t
496 FalconModeOps::Decode(int16 id, struct video_mode *mode)
497 {
498 	bool vga = (id & 0x0010) != 0;
499 	//bool pal = (id & 0x0020) != 0;
500 	bool overscan = (id & 0x0040) != 0;
501 	bool st = (id & 0x0080) != 0;
502 	bool interlace = (id & 0x0100) != 0;
503 	bool dbl = interlace;
504 
505 	mode->ops = this;
506 	mode->mode = id;
507 	// cf. F30.TXT
508 	mode->width = (id & 0x0008) ? 640 : 320;
509 	mode->height = (vga ? (interlace ? 400 : 200) : (dbl ? 240 : 480));
510 	if (overscan) {
511 		// *= 1.2
512 		mode->width = (mode->width * 12) / 10;
513 		mode->height = (mode->width * 12) / 10;
514 	}
515 	mode->bits_per_pixel = 1 << (id & 0x0007);
516 	mode->bytes_per_row = mode->width * mode->bits_per_pixel / 8;
517 	return B_OK;
518 }
519 
520 
521 status_t
522 FalconModeOps::Get(struct video_mode *mode)
523 {
524 	if (fInitStatus < B_OK)
525 		return fInitStatus;
526 
527 	int16 m = VsetMode(VM_INQUIRE);
528 	return Decode(m, mode);
529 }
530 
531 
532 status_t
533 FalconModeOps::Set(const struct video_mode *mode)
534 {
535 	if (fInitStatus < B_OK)
536 		return fInitStatus;
537 	if (mode == NULL)
538 		return B_BAD_VALUE;
539 
540 	fPreviousMode = VsetMode(VM_INQUIRE);
541 
542 #warning M68K: FIXME: allocate framebuffer
543 	dprintf("Switching to mode 0x%04x\n", mode->mode);
544 	//VsetScreen(((uint32)0x00d00000), ((uint32)0x00d00000), 3, mode->mode);
545 	VsetScreen(((uint32)0x00c00000), ((uint32)0x00c00000), 3, mode->mode);
546 	//VsetScreen(((uint32)-1), ((uint32)-1), 3, mode->mode);
547 
548 	return B_OK;
549 }
550 
551 
552 status_t
553 FalconModeOps::Unset(const struct video_mode *mode)
554 {
555 	if (fInitStatus < B_OK)
556 		return fInitStatus;
557 
558 	if (fPreviousMode != -1) {
559 		dprintf("Reverting to mode 0x%04x\n", fPreviousMode);
560 		VsetScreen(-1, -1, 3, fPreviousMode);
561 		fPreviousMode = -1;
562 	}
563 
564 	return B_OK;
565 }
566 
567 
568 status_t
569 FalconModeOps::SetPalette(const struct video_mode *mode, const uint8 *palette)
570 {
571 	switch (mode->bits_per_pixel) {
572 		case 4:
573 			VsetRGB(0, 16, palette);
574 			break;
575 		case 8:
576 			VsetRGB(0, 256, palette);
577 			break;
578 		default:
579 			break;
580 	}
581 }
582 
583 
584 addr_t
585 FalconModeOps::Framebuffer()
586 {
587 	addr_t fb = (addr_t)Physbase();
588 	return fb;
589 }
590 
591 
592 void
593 FalconModeOps::MakeLabel(const struct video_mode *mode, char *label,
594 	size_t len)
595 {
596 	ModeOps::MakeLabel(mode, label, len);
597 	label += strlen(label);
598 	// XXX no len check
599 	int16 m = mode->mode;
600 	sprintf(label, " 0x%04x", mode->mode);
601 	/*sprintf(label, "%s%s%s%s",
602 		m & 0x0010 ? " vga" : " tv",
603 		m & 0x0020 ? " pal" : "",
604 		m & 0x0040 ? " oscan" : "",
605 		//m & 0x0080 ? " tv" : "",
606 		m & 0x0100 ? " ilace" : "");*/
607 }
608 
609 
610 static FalconModeOps sFalconModeOps;
611 
612 
613 //	#pragma mark - Milan XBIOS API
614 
615 class MilanModeOps : public ModeOps {
616 public:
617 	MilanModeOps() : ModeOps("Milan") {};
618 	~MilanModeOps() {};
619 	virtual status_t	Init();
620 
621 	virtual status_t	Enumerate();
622 	virtual status_t	Decode(int16 id, struct video_mode *mode);
623 	virtual status_t	Get(struct video_mode *mode);
624 	virtual status_t	Set(const struct video_mode *mode);
625 	virtual status_t	Unset(const struct video_mode *mode);
626 
627 	virtual status_t	SetPalette(const struct video_mode *mode,
628 							const uint8 *palette);
629 	virtual addr_t		Framebuffer();
630 	virtual void		MakeLabel(const struct video_mode *mode,
631 							char *label, size_t len);
632 private:
633 	static int16		fPreviousMode;
634 };
635 
636 
637 int16 MilanModeOps::fPreviousMode = -1;
638 
639 
640 status_t
641 MilanModeOps::Init()
642 {
643 	const tos_cookie *c = tos_find_cookie('_MIL');
644 	if (c == NULL)
645 		return ENODEV;
646 	fInitStatus = B_OK;
647 	return fInitStatus;
648 }
649 
650 
651 
652 status_t
653 MilanModeOps::Enumerate()
654 {
655 	if (fInitStatus < B_OK)
656 		return fInitStatus;
657 
658 	SCREENINFO info;
659 	info.size = sizeof(info);
660 
661 
662 	static int16 modes[] = {
663 		0x001b, 0x001c, 0x002b, 0x002c,
664 		0x003a, 0x003b, 0x003c, 0x000c,
665 		0x0034, 0x0004
666 		/*0x003a, 0x003b, 0x0003, 0x000c,
667 		0x000b, 0x0033, 0x000c, 0x001c*/ };
668 	for (int i = 0; i < sizeof(modes) / sizeof(int16); i++) {
669 		video_mode *videoMode = AllocMode();
670 		if (videoMode == NULL)
671 			continue;
672 
673 		if (Decode(modes[i], videoMode) != B_OK)
674 			continue;
675 		add_video_mode(videoMode);
676 
677 	}
678 	return B_OK;
679 
680 #if 0
681 	// TODO: use Milan video monitor detection and build possible mode list there...
682 	int16 monitor;
683 	bool vga = false;
684 	bool tv = false;
685 	monitor = VgetMonitor();
686 	switch (monitor) {
687 		case 0:
688 			panic("Monochrome ?\n");
689 			break;
690 		case 2:
691 			vga = true;
692 			break;
693 		case 3:
694 			tv = true;
695 			break;
696 		//case 4 & 5: check for CT60
697 		case 1:
698 		default:
699 			dprintf("monitor type %d\n", monitor);
700 			break;
701 	}
702 	return ENODEV;
703 #endif
704 }
705 
706 
707 status_t
708 MilanModeOps::Decode(int16 id, struct video_mode *mode)
709 {
710 	SCREENINFO info;
711 	info.size = sizeof(info);
712 	info.devID = mode->mode;
713 	info.scrFlags = 0;
714 
715 	mode->ops = this;
716 	mode->mode = id;
717 
718 	Setscreen(-1,&info,MI_MAGIC,CMD_GETINFO);
719 
720 	if (info.scrFlags & SCRINFO_OK == 0)
721 		return B_ERROR;
722 
723 	// cf. F30.TXT
724 	mode->width = info.scrWidth;
725 	mode->height = info.scrHeight;
726 	mode->bits_per_pixel = info.scrPlanes;
727 	mode->bytes_per_row = mode->width * mode->bits_per_pixel / 8;
728 	return B_OK;
729 }
730 
731 
732 status_t
733 MilanModeOps::Get(struct video_mode *mode)
734 {
735 	if (fInitStatus < B_OK)
736 		return fInitStatus;
737 
738 	int16 m = -1;
739 	Setscreen(-1,&m,MI_MAGIC,CMD_GETMODE);
740 	if (m == -1)
741 		return B_ERROR;
742 	return Decode(m, mode);
743 }
744 
745 
746 status_t
747 MilanModeOps::Set(const struct video_mode *mode)
748 {
749 	if (fInitStatus < B_OK)
750 		return fInitStatus;
751 	if (mode == NULL)
752 		return B_BAD_VALUE;
753 
754 	Setscreen(-1,&fPreviousMode,MI_MAGIC,CMD_GETMODE);
755 
756 #warning M68K: FIXME: allocate framebuffer
757 	dprintf("Switching to mode 0x%04x\n", mode->mode);
758 	//VsetScreen(((uint32)0x00d00000), ((uint32)0x00d00000), 3, mode->mode);
759 	//VsetScreen(((uint32)-1), ((uint32)-1), 3, mode->mode);
760 	Setscreen(-1,mode->mode,MI_MAGIC,CMD_SETMODE);
761 
762 	return B_OK;
763 }
764 
765 
766 status_t
767 MilanModeOps::Unset(const struct video_mode *mode)
768 {
769 	if (fInitStatus < B_OK)
770 		return fInitStatus;
771 
772 	if (fPreviousMode != -1) {
773 		dprintf("Reverting to mode 0x%04x\n", fPreviousMode);
774 		Setscreen(-1,fPreviousMode,MI_MAGIC,CMD_SETMODE);
775 		fPreviousMode = -1;
776 	}
777 
778 	return B_OK;
779 }
780 
781 
782 status_t
783 MilanModeOps::SetPalette(const struct video_mode *mode, const uint8 *palette)
784 {
785 	switch (mode->bits_per_pixel) {
786 		case 4:
787 			//VsetRGB(0, 16, palette);
788 			break;
789 		case 8:
790 			//VsetRGB(0, 256, palette);
791 			break;
792 		default:
793 			break;
794 	}
795 }
796 
797 
798 addr_t
799 MilanModeOps::Framebuffer()
800 {
801 	//XXX
802 	addr_t fb = (addr_t)Physbase();
803 	return fb;
804 }
805 
806 
807 void
808 MilanModeOps::MakeLabel(const struct video_mode *mode, char *label,
809 	size_t len)
810 {
811 	ModeOps::MakeLabel(mode, label, len);
812 	label += strlen(label);
813 	// XXX no len check
814 	int16 m = mode->mode;
815 	sprintf(label, " 0x%04x", mode->mode);
816 	/*sprintf(label, "%s%s%s%s",
817 		m & 0x0010 ? " vga" : " tv",
818 		m & 0x0020 ? " pal" : "",
819 		m & 0x0040 ? " oscan" : "",
820 		//m & 0x0080 ? " tv" : "",
821 		m & 0x0100 ? " ilace" : "");*/
822 }
823 
824 
825 static MilanModeOps sMilanModeOps;
826 
827 
828 //	#pragma mark - ARAnyM NFVDI API
829 
830 /* NatFeat VDI */
831 #define FVDIDRV_NFAPI_VERSION	0x14000960L
832 #define FVDI_GET_VERSION	0
833 #define FVDI_GET_FBADDR	11
834 #define FVDI_SET_RESOLUTION	12
835 #define FVDI_GET_WIDTH	13
836 #define FVDI_GET_HEIGHT	14
837 #define FVDI_OPENWK 15
838 #define FVDI_CLOSEWK 16
839 #define FVDI_GETBPP	17
840 
841 
842 class NFVDIModeOps : public ModeOps {
843 public:
844 	NFVDIModeOps() : ModeOps("NFVDI") {};
845 	~NFVDIModeOps() {};
846 	virtual status_t	Init();
847 	virtual status_t	Enumerate();
848 	virtual status_t	Get(struct video_mode *mode);
849 	virtual status_t	Set(const struct video_mode *mode);
850 	virtual status_t	Unset(const struct video_mode *mode);
851 	virtual addr_t		Framebuffer();
852 
853 	virtual int16	Width(const struct video_mode *mode=NULL);
854 	virtual int16	Height(const struct video_mode *mode=NULL);
855 	virtual int16	Depth(const struct video_mode *mode=NULL);
856 
857 private:
858 	int32 fNatFeatId;
859 };
860 
861 
862 status_t
863 NFVDIModeOps::Init()
864 {
865 	// NF calls not available when the ctor is called
866 	fNatFeatId = nat_feat_getid("fVDI");
867 	if (fNatFeatId == 0)
868 		return B_ERROR;
869 	dprintf("fVDI natfeat id 0x%08lx\n", fNatFeatId);
870 
871 	int32 version = nat_feat_call(fNatFeatId, FVDI_GET_VERSION);
872 	dprintf("fVDI NF version %lx\n", version);
873 	if (version < FVDIDRV_NFAPI_VERSION)
874 		return B_ERROR;
875 	fInitStatus = B_OK;
876 	return fInitStatus;
877 }
878 
879 
880 status_t
881 NFVDIModeOps::Enumerate()
882 {
883 	if (fNatFeatId == 0)
884 		return B_NO_INIT;
885 
886 	video_mode * mode;
887 
888 	mode = AllocMode();
889 	if (mode == NULL)
890 		return B_ERROR;
891 
892 	Get(mode);
893 	//mode->space = ;
894 	mode->mode = 0;
895 	mode->width = 800;
896 	mode->height = 600;
897 	mode->bits_per_pixel = 8;
898 	mode->bytes_per_row = mode->width * mode->bits_per_pixel / 8;
899 
900 	add_video_mode(mode);
901 
902 
903 	mode = AllocMode();
904 	if (mode == NULL)
905 		return B_ERROR;
906 
907 	Get(mode);
908 	//mode->space = ;
909 	mode->mode = 0;
910 	mode->width = 1024;
911 	mode->height = 768;
912 	mode->bits_per_pixel = 16;
913 	mode->bytes_per_row = mode->width * mode->bits_per_pixel / 8;
914 
915 	add_video_mode(mode);
916 
917 
918 	return B_OK;
919 }
920 
921 
922 status_t
923 NFVDIModeOps::Get(struct video_mode *mode)
924 {
925 	if (mode == NULL)
926 		return B_BAD_VALUE;
927 	if (fNatFeatId == 0)
928 		return B_NOT_SUPPORTED;
929 	mode->width = Width();
930 	mode->height = Height();
931 	mode->bits_per_pixel = Depth();
932 	mode->bytes_per_row = mode->width * mode->bits_per_pixel / 8;
933 	dprintf("Get: %dx%d\n", mode->width, mode->height);
934 	return B_OK;
935 }
936 
937 
938 status_t
939 NFVDIModeOps::Set(const struct video_mode *mode)
940 {
941 	if (mode == NULL)
942 		return B_BAD_VALUE;
943 	if (fNatFeatId == 0)
944 		return B_NOT_SUPPORTED;
945 	status_t err;
946 	dprintf("fVDI::Set(%ldx%ld %ld)\n",
947 		(int32)Width(mode), (int32)Height(mode), (int32)Depth(mode));
948 	err = nat_feat_call(fNatFeatId, FVDI_SET_RESOLUTION,
949 		(int32)Width(mode), (int32)Height(mode), (int32)Depth(mode));
950 	err = toserror(err);
951 	err = nat_feat_call(fNatFeatId, FVDI_OPENWK);
952 
953 	return B_OK;
954 }
955 
956 
957 status_t
958 NFVDIModeOps::Unset(const struct video_mode *mode)
959 {
960 	if (mode == NULL)
961 		return B_BAD_VALUE;
962 	if (fNatFeatId == 0)
963 		return B_NOT_SUPPORTED;
964 	nat_feat_call(fNatFeatId, FVDI_CLOSEWK);
965 	return B_OK;
966 }
967 
968 
969 addr_t
970 NFVDIModeOps::Framebuffer()
971 {
972 	addr_t fb;
973 	if (fNatFeatId == 0)
974 		return (addr_t)NULL;
975 	fb = (addr_t)nat_feat_call(fNatFeatId, FVDI_GET_FBADDR);
976 	dprintf("fb 0x%08lx\n", fb);
977 	return fb;
978 }
979 
980 
981 int16
982 NFVDIModeOps::Width(const struct video_mode *mode)
983 {
984 	if (mode)
985 		return ModeOps::Width(mode);
986 	if (fNatFeatId == 0)
987 		return 0;
988 	return (int16)nat_feat_call(fNatFeatId, FVDI_GET_WIDTH);
989 }
990 
991 
992 int16
993 NFVDIModeOps::Height(const struct video_mode *mode)
994 {
995 	if (mode)
996 		return ModeOps::Height(mode);
997 	if (fNatFeatId == 0)
998 		return 0;
999 	return (int16)nat_feat_call(fNatFeatId, FVDI_GET_HEIGHT);
1000 }
1001 
1002 
1003 int16
1004 NFVDIModeOps::Depth(const struct video_mode *mode)
1005 {
1006 	if (mode)
1007 		return ModeOps::Depth(mode);
1008 	if (fNatFeatId == 0)
1009 		return 0;
1010 	return (int16)nat_feat_call(fNatFeatId, FVDI_GETBPP);
1011 }
1012 
1013 
1014 static NFVDIModeOps sNFVDIModeOps;
1015 
1016 
1017 //	#pragma mark -
1018 
1019 
1020 bool
1021 video_mode_hook(Menu *menu, MenuItem *item)
1022 {
1023 	// find selected mode
1024 	video_mode *mode = NULL;
1025 
1026 	menu = item->Submenu();
1027 	item = menu->FindMarked();
1028 	if (item != NULL) {
1029 		switch (menu->IndexOf(item)) {
1030 			case 0:
1031 				// "Default" mode special
1032 				sMode = sDefaultMode;
1033 				sModeChosen = false;
1034 				return true;
1035 			//case 1:
1036 				// "Standard VGA" mode special
1037 				// sets sMode to NULL which triggers VGA mode
1038 				//break;
1039 			default:
1040 				mode = (video_mode *)item->Data();
1041 				break;
1042 		}
1043 	}
1044 
1045 	if (mode != sMode) {
1046 		// update standard mode
1047 		// ToDo: update fb settings!
1048 		sMode = mode;
1049 platform_switch_to_logo();
1050 	}
1051 
1052 	sModeChosen = true;
1053 	return true;
1054 }
1055 
1056 
1057 Menu *
1058 video_mode_menu()
1059 {
1060 	Menu *menu = new(nothrow) Menu(CHOICE_MENU, "Select Video Mode");
1061 	MenuItem *item;
1062 
1063 	menu->AddItem(item = new(nothrow) MenuItem("Default"));
1064 	item->SetMarked(true);
1065 	item->Select(true);
1066 	item->SetHelpText("The Default video mode is the one currently configured "
1067 		"in the system. If there is no mode configured yet, a viable mode will "
1068 		"be chosen automatically.");
1069 
1070 	//menu->AddItem(new(nothrow) MenuItem("Standard VGA"));
1071 
1072 	video_mode *mode = NULL;
1073 	while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) != NULL) {
1074 		char label[64];
1075 		mode->ops->MakeLabel(mode, label, sizeof(label));
1076 
1077 		menu->AddItem(item = new(nothrow) MenuItem(label));
1078 		item->SetData(mode);
1079 	}
1080 
1081 	menu->AddSeparatorItem();
1082 	menu->AddItem(item = new(nothrow) MenuItem("Return to main menu"));
1083 	item->SetType(MENU_ITEM_NO_CHOICE);
1084 
1085 	return menu;
1086 }
1087 
1088 
1089 void
1090 platform_blit4(addr_t frameBuffer, const uint8 *data,
1091 	uint16 width, uint16 height, uint16 imageWidth, uint16 left, uint16 top)
1092 {
1093 	if (!data)
1094 		return;
1095 }
1096 
1097 
1098 extern "C" void
1099 platform_set_palette(const uint8 *palette)
1100 {
1101 	if (sMode)
1102 		sMode->ops->SetPalette(sMode, palette);
1103 }
1104 
1105 
1106 //	#pragma mark -
1107 
1108 
1109 extern "C" void
1110 platform_switch_to_logo(void)
1111 {
1112 	// in debug mode, we'll never show the logo
1113 	if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0)
1114 		return;
1115 
1116 	addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start;
1117 	size_t lastSize = gKernelArgs.frame_buffer.physical_buffer.size;
1118 
1119 	if (sMode != NULL) {
1120 		sMode->Set();
1121 
1122 		gKernelArgs.frame_buffer.width = sMode->ops->Width(sMode);
1123 		gKernelArgs.frame_buffer.height = sMode->ops->Height(sMode);
1124 		gKernelArgs.frame_buffer.bytes_per_row = sMode->ops->BytesPerRow(sMode);
1125 		gKernelArgs.frame_buffer.depth = sMode->ops->Depth(sMode);
1126 		gKernelArgs.frame_buffer.physical_buffer.size =
1127 			gKernelArgs.frame_buffer.height
1128 			* gKernelArgs.frame_buffer.bytes_per_row;
1129 		gKernelArgs.frame_buffer.physical_buffer.start =
1130 			sMode->ops->Framebuffer();
1131 		//XXX: FIXME: this is just for testing...
1132 		sFrameBuffer = sMode->ops->Framebuffer();
1133 	} else {
1134 		gKernelArgs.frame_buffer.enabled = false;
1135 		return;
1136 	}
1137 	gKernelArgs.frame_buffer.enabled = true;
1138 
1139 #if 1
1140 	// If the new frame buffer is either larger than the old one or located at
1141 	// a different address, we need to remap it, so we first have to throw
1142 	// away its previous mapping
1143 	if (lastBase != 0
1144 		&& (lastBase != gKernelArgs.frame_buffer.physical_buffer.start
1145 			|| lastSize < gKernelArgs.frame_buffer.physical_buffer.size)) {
1146 		mmu_free((void *)sFrameBuffer, lastSize);
1147 		lastBase = 0;
1148 	}
1149 	if (lastBase == 0) {
1150 		// the graphics memory has not been mapped yet!
1151 		sFrameBuffer = mmu_map_physical_memory(
1152 			gKernelArgs.frame_buffer.physical_buffer.start,
1153 			gKernelArgs.frame_buffer.physical_buffer.size, kDefaultPageFlags);
1154 	}
1155 #endif
1156 	video_display_splash(sFrameBuffer);
1157 	dump_vars();
1158 	spin(10000000);
1159 	platform_switch_to_text_mode();
1160 	dprintf("splash done\n");
1161 	dump_vars();
1162 }
1163 
1164 
1165 extern "C" void
1166 platform_switch_to_text_mode(void)
1167 {
1168 	if (!gKernelArgs.frame_buffer.enabled) {
1169 		return;
1170 	}
1171 
1172 	if (sMode)
1173 		sMode->Unset();
1174 
1175 	gKernelArgs.frame_buffer.enabled = 0;
1176 }
1177 
1178 
1179 extern "C" status_t
1180 platform_init_video(void)
1181 {
1182 	gKernelArgs.frame_buffer.enabled = 0;
1183 	list_init(&sModeList);
1184 
1185 	dprintf("current video mode: \n");
1186 	dprintf("Vsetmode(-1): 0x%08x\n", VsetMode(VM_INQUIRE));
1187 	dump_vars();
1188 
1189 	// NF VDI does not implement FVDI_GET_FBADDR :(
1190 	//sNFVDIModeOps.Init();
1191 	//sNFVDIModeOps.Enumerate();
1192 
1193 	if (sMilanModeOps.Init() == B_OK) {
1194 		sMilanModeOps.Enumerate();
1195 	} else if (sFalconModeOps.Init() == B_OK) {
1196 		sFalconModeOps.Enumerate();
1197 	} else if (sSTModeOps.Init() == B_OK) {
1198 		sSTModeOps.Enumerate();
1199 	} else {
1200 		dprintf("No usable video API found\n");
1201 	}
1202 
1203 	return B_OK;
1204 }
1205 
1206