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
36static void
37dump_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
47class ModeOps {
48public:
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
76private:
77	const char *fName;
78protected:
79	status_t fInitStatus;
80};
81
82struct 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;
89status_t	Set() { ops->Set(this); };
90status_t	Unset() { ops->Unset(this); };
91};
92
93static struct list sModeList;
94static video_mode *sMode, *sDefaultMode;
95static uint32 sModeCount;
96static addr_t sFrameBuffer;
97static bool sModeChosen;
98
99
100static int
101compare_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*/
126static void
127add_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
149struct video_mode *
150ModeOps::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
161status_t
162ModeOps::Decode(int16 id, struct video_mode *mode)
163{
164	mode->ops = this;
165	mode->mode = id;
166	return B_OK;
167}
168
169
170int16
171ModeOps::Width(const struct video_mode *mode)
172{
173	return mode ? mode->width : 0;
174}
175
176
177int16
178ModeOps::Height(const struct video_mode *mode)
179{
180	return mode ? mode->height : 0;
181}
182
183
184int16
185ModeOps::Depth(const struct video_mode *mode)
186{
187	return mode ? mode->bits_per_pixel : 0;
188}
189
190
191int16
192ModeOps::BytesPerRow(const struct video_mode *mode)
193{
194	return mode ? mode->bytes_per_row : 0;
195}
196
197
198void
199ModeOps::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
209class STModeOps : public ModeOps {
210public:
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);
226private:
227	static int16		fPreviousMode;
228	static bool			fIsTT;
229};
230
231
232int16 STModeOps::fPreviousMode = -1;
233bool STModeOps::fIsTT = false;
234
235
236status_t
237STModeOps::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
252status_t
253STModeOps::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
281status_t
282STModeOps::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
313status_t
314STModeOps::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
324status_t
325STModeOps::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
347status_t
348STModeOps::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
363status_t
364STModeOps::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
381addr_t
382STModeOps::Framebuffer()
383{
384	addr_t fb = (addr_t)Physbase();
385	return fb;
386}
387
388
389void
390STModeOps::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
400static STModeOps sSTModeOps;
401
402
403//	#pragma mark - Falcon XBIOS API
404
405class FalconModeOps : public ModeOps {
406public:
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);
422private:
423	static int16		fPreviousMode;
424};
425
426
427int16 FalconModeOps::fPreviousMode = -1;
428
429
430status_t
431FalconModeOps::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
444status_t
445FalconModeOps::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
495status_t
496FalconModeOps::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
521status_t
522FalconModeOps::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
532status_t
533FalconModeOps::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
552status_t
553FalconModeOps::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
568status_t
569FalconModeOps::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
584addr_t
585FalconModeOps::Framebuffer()
586{
587	addr_t fb = (addr_t)Physbase();
588	return fb;
589}
590
591
592void
593FalconModeOps::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
610static FalconModeOps sFalconModeOps;
611
612
613//	#pragma mark - Milan XBIOS API
614
615class MilanModeOps : public ModeOps {
616public:
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);
632private:
633	static int16		fPreviousMode;
634};
635
636
637int16 MilanModeOps::fPreviousMode = -1;
638
639
640status_t
641MilanModeOps::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
652status_t
653MilanModeOps::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
707status_t
708MilanModeOps::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
732status_t
733MilanModeOps::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
746status_t
747MilanModeOps::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
766status_t
767MilanModeOps::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
782status_t
783MilanModeOps::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
798addr_t
799MilanModeOps::Framebuffer()
800{
801	//XXX
802	addr_t fb = (addr_t)Physbase();
803	return fb;
804}
805
806
807void
808MilanModeOps::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
825static 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
842class NFVDIModeOps : public ModeOps {
843public:
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
857private:
858	int32 fNatFeatId;
859};
860
861
862status_t
863NFVDIModeOps::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
880status_t
881NFVDIModeOps::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
922status_t
923NFVDIModeOps::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
938status_t
939NFVDIModeOps::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
957status_t
958NFVDIModeOps::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
969addr_t
970NFVDIModeOps::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
981int16
982NFVDIModeOps::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
992int16
993NFVDIModeOps::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
1003int16
1004NFVDIModeOps::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
1014static NFVDIModeOps sNFVDIModeOps;
1015
1016
1017//	#pragma mark -
1018
1019
1020bool
1021video_mode_hook(Menu *menu, MenuItem *item)
1022{
1023	// find selected mode
1024	video_mode *mode = NULL;
1025
1026	Menu* submenu = item->Submenu();
1027	MenuItem* subitem = submenu->FindMarked();
1028	if (subitem != NULL) {
1029		switch (submenu->IndexOf(subitem)) {
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 *)subitem->Data();
1041				break;
1042		}
1043	}
1044
1045	if (mode != sMode) {
1046		// update standard mode
1047		// ToDo: update fb settings!
1048		sMode = mode;
1049platform_switch_to_logo();
1050	}
1051
1052	sModeChosen = true;
1053	return true;
1054}
1055
1056
1057Menu *
1058video_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
1089void
1090platform_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
1098extern "C" void
1099platform_set_palette(const uint8 *palette)
1100{
1101	if (sMode)
1102		sMode->ops->SetPalette(sMode, palette);
1103}
1104
1105
1106//	#pragma mark -
1107
1108
1109extern "C" void
1110platform_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
1165extern "C" void
1166platform_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
1179extern "C" status_t
1180platform_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