1/*
2 * Copyright 2004-2009, Axel D��rfler, axeld@pinc-software.de.
3 * Copyright 2008, Stephan A��mus <superstippi@gmx.de>
4 * Copyright 2008, Philippe Saint-Pierre <stpere@gmail.com>
5 * Copyright 2011, Rene Gollent, rene@gollent.com.
6 * Distributed under the terms of the MIT License.
7 */
8
9
10#include "video.h"
11#include "bios.h"
12#include "vesa.h"
13#include "vesa_info.h"
14#include "vga.h"
15#include "mmu.h"
16
17#include <edid.h>
18
19#include <arch/cpu.h>
20#include <boot/stage2.h>
21#include <boot/platform.h>
22#include <boot/menu.h>
23#include <boot/kernel_args.h>
24#include <boot/platform/generic/video.h>
25#include <util/list.h>
26#include <drivers/driver_settings.h>
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32
33#define TRACE_VIDEO
34#ifdef TRACE_VIDEO
35#	define TRACE(x) dprintf x
36#else
37#	define TRACE(x) ;
38#endif
39
40
41struct video_mode {
42	list_link	link;
43	uint16		mode;
44	uint16		width, height, bits_per_pixel;
45	uint32		bytes_per_row;
46	crtc_info_block* timing;
47};
48
49static vbe_info_block sInfo;
50static video_mode *sMode, *sDefaultMode;
51static bool sVesaCompatible;
52static struct list sModeList;
53static uint32 sModeCount;
54static addr_t sFrameBuffer;
55static bool sModeChosen;
56static bool sSettingsLoaded;
57
58
59static int
60compare_video_modes(video_mode *a, video_mode *b)
61{
62	int compare = a->width - b->width;
63	if (compare != 0)
64		return compare;
65
66	compare = a->height - b->height;
67	if (compare != 0)
68		return compare;
69
70	// TODO: compare video_mode::mode?
71	return a->bits_per_pixel - b->bits_per_pixel;
72}
73
74
75/*!	Insert the video mode into the list, sorted by resolution and bit depth.
76	Higher resolutions/depths come first.
77*/
78static void
79add_video_mode(video_mode *videoMode)
80{
81	video_mode *mode = NULL;
82	while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
83			!= NULL) {
84		int compare = compare_video_modes(videoMode, mode);
85		if (compare == 0) {
86			// mode already exists
87			return;
88		}
89
90		if (compare > 0)
91			break;
92	}
93
94	list_insert_item_before(&sModeList, mode, videoMode);
95	sModeCount++;
96}
97
98
99/*! \brief Finds a video mode with the given resolution.
100	If \a allowPalette is true, 8-bit modes are considered, too.
101	If \a height is \c -1, the height is ignored, and only the width
102	matters.
103*/
104static video_mode *
105find_video_mode(int32 width, int32 height, bool allowPalette)
106{
107	video_mode *found = NULL;
108	video_mode *mode = NULL;
109	while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
110			!= NULL) {
111		if (mode->width == width && (height == -1 || mode->height == height)
112			&& (mode->bits_per_pixel > 8 || allowPalette)) {
113			if (found == NULL || found->bits_per_pixel < mode->bits_per_pixel)
114				found = mode;
115		}
116	}
117
118	return found;
119}
120
121
122/*! Returns the VESA mode closest to the one specified, with a width less or
123	equal as specified.
124	The height as well as the depth may vary in both directions, though.
125*/
126static video_mode *
127closest_video_mode(int32 width, int32 height, int32 depth)
128{
129	video_mode *bestMode = NULL;
130	uint32 bestDiff = 0;
131
132	video_mode *mode = NULL;
133	while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
134			!= NULL) {
135		if (mode->width > width) {
136			// Only choose modes with a width less or equal than the searched
137			// one; or else it might well be that the monitor cannot keep up.
138			continue;
139		}
140
141		uint32 diff = 2 * abs(mode->width - width) + abs(mode->height - height)
142			+ abs(mode->bits_per_pixel - depth);
143
144		if (bestMode == NULL || bestDiff > diff) {
145			bestMode = mode;
146			bestDiff = diff;
147		}
148	}
149
150	return bestMode;
151}
152
153
154static crtc_info_block*
155get_crtc_info_block(edid1_detailed_timing& timing)
156{
157	// This feature is only available on chipsets supporting VBE3 and up
158	if (sInfo.version.major < 3)
159		return NULL;
160
161	// Copy timing structure to set the mode with
162	crtc_info_block* crtcInfo = (crtc_info_block*)malloc(
163		sizeof(crtc_info_block));
164	if (crtcInfo == NULL)
165		return NULL;
166
167	memset(crtcInfo, 0, sizeof(crtc_info_block));
168	crtcInfo->horizontal_sync_start = timing.h_active + timing.h_sync_off;
169	crtcInfo->horizontal_sync_end = crtcInfo->horizontal_sync_start
170		+ timing.h_sync_width;
171	crtcInfo->horizontal_total = timing.h_active + timing.h_blank;
172	crtcInfo->vertical_sync_start = timing.v_active + timing.v_sync_off;
173	crtcInfo->vertical_sync_end = crtcInfo->vertical_sync_start
174		+ timing.v_sync_width;
175	crtcInfo->vertical_total = timing.v_active + timing.v_blank;
176	crtcInfo->pixel_clock = timing.pixel_clock * 10000L;
177	crtcInfo->refresh_rate = crtcInfo->pixel_clock
178		/ (crtcInfo->horizontal_total / 10)
179		/ (crtcInfo->vertical_total / 10);
180
181	TRACE(("crtc: h %u/%u/%u, v %u/%u/%u, pixel clock %lu, refresh %u\n",
182		crtcInfo->horizontal_sync_start, crtcInfo->horizontal_sync_end,
183		crtcInfo->horizontal_total, crtcInfo->vertical_sync_start,
184		crtcInfo->vertical_sync_end, crtcInfo->vertical_total,
185		crtcInfo->pixel_clock, crtcInfo->refresh_rate));
186
187	crtcInfo->flags = 0;
188	if (timing.sync == 3) {
189		// TODO: this switches the default sync when sync != 3 (compared to
190		// create_display_modes().
191		if ((timing.misc & 1) == 0)
192			crtcInfo->flags |= CRTC_NEGATIVE_HSYNC;
193		if ((timing.misc & 2) == 0)
194			crtcInfo->flags |= CRTC_NEGATIVE_VSYNC;
195	}
196	if (timing.interlaced)
197		crtcInfo->flags |= CRTC_INTERLACED;
198
199	return crtcInfo;
200}
201
202
203static crtc_info_block*
204get_crtc_info_block(edid1_std_timing& timing)
205{
206	// TODO: implement me!
207	return NULL;
208}
209
210
211static video_mode*
212find_edid_mode(edid1_info& info, bool allowPalette)
213{
214	video_mode *mode = NULL;
215
216	// try detailed timing first
217	for (int32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; i++) {
218		edid1_detailed_monitor& monitor = info.detailed_monitor[i];
219
220		if (monitor.monitor_desc_type == EDID1_IS_DETAILED_TIMING) {
221			mode = find_video_mode(monitor.data.detailed_timing.h_active,
222				monitor.data.detailed_timing.v_active, allowPalette);
223			if (mode != NULL) {
224				mode->timing
225					= get_crtc_info_block(monitor.data.detailed_timing);
226				return mode;
227			}
228		}
229	}
230
231	int32 best = -1;
232
233	// try standard timings next
234	for (int32 i = 0; i < EDID1_NUM_STD_TIMING; i++) {
235		if (info.std_timing[i].h_size <= 256)
236			continue;
237
238		video_mode* found = find_video_mode(info.std_timing[i].h_size,
239			info.std_timing[i].v_size, allowPalette);
240		if (found != NULL) {
241			if (mode != NULL) {
242				// prefer higher resolutions
243				if (found->width > mode->width) {
244					mode = found;
245					best = i;
246				}
247			} else {
248				mode = found;
249				best = i;
250			}
251		}
252	}
253
254	if (best >= 0)
255		mode->timing = get_crtc_info_block(info.std_timing[best]);
256
257	return mode;
258}
259
260
261static void
262vesa_fixups(void *settings)
263{
264	const char *oem_string = (const char *)sInfo.oem_string;
265
266	if (!strcmp(oem_string, "NVIDIA")) {
267		const char *arg = NULL;
268		int32 scaling = -1;
269
270		if (settings != NULL)
271			arg = get_driver_parameter(settings, "nvidia_scaling", NULL, "1");
272		if (arg != NULL)
273			scaling = strtol(arg, NULL, 0);
274
275		if (scaling > -1) {
276			dprintf("Setting nvidia scaling mode to %" B_PRId32 "\n", scaling);
277			struct bios_regs regs;
278			regs.eax = 0x4f14;
279			regs.ebx = 0x0102;
280			regs.ecx = scaling;
281			call_bios(0x10, &regs);
282		}
283	}
284
285}
286
287
288static bool
289get_mode_from_settings(void)
290{
291	if (sSettingsLoaded)
292		return true;
293
294	void *handle = load_driver_settings("vesa");
295	if (handle == NULL)
296		return false;
297
298	vesa_fixups(handle);
299
300	bool found = false;
301
302	const driver_settings *settings = get_driver_settings(handle);
303	if (settings == NULL)
304		goto out;
305
306	sSettingsLoaded = true;
307
308	for (int32 i = 0; i < settings->parameter_count; i++) {
309		driver_parameter &parameter = settings->parameters[i];
310
311		if (!strcmp(parameter.name, "mode") && parameter.value_count > 2) {
312			// parameter found, now get its values
313			int32 width = strtol(parameter.values[0], NULL, 0);
314			int32 height = strtol(parameter.values[1], NULL, 0);
315			int32 depth = strtol(parameter.values[2], NULL, 0);
316
317			// search mode that fits
318
319			video_mode *mode = closest_video_mode(width, height, depth);
320			if (mode != NULL) {
321				found = true;
322				sMode = mode;
323			}
324		}
325	}
326
327out:
328	unload_driver_settings(handle);
329	return found;
330}
331
332
333//	#pragma mark - vga
334
335
336static void
337vga_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries)
338{
339	out8(firstIndex, VGA_COLOR_WRITE_MODE);
340	// write VGA palette
341	for (int32 i = firstIndex; i < numEntries; i++) {
342		// VGA (usually) has only 6 bits per gun
343		out8(palette[i * 3 + 0] >> 2, VGA_COLOR_DATA);
344		out8(palette[i * 3 + 1] >> 2, VGA_COLOR_DATA);
345		out8(palette[i * 3 + 2] >> 2, VGA_COLOR_DATA);
346	}
347}
348
349
350static void
351vga_enable_bright_background_colors(void)
352{
353	// reset attribute controller
354	in8(VGA_INPUT_STATUS_1);
355
356	// select mode control register
357	out8(0x30, VGA_ATTRIBUTE_WRITE);
358
359	// read mode control register, change it (we need to clear bit 3), and write it back
360	uint8 mode = in8(VGA_ATTRIBUTE_READ) & 0xf7;
361	out8(mode, VGA_ATTRIBUTE_WRITE);
362}
363
364
365//	#pragma mark - vesa
366
367
368static status_t
369vesa_get_edid(edid1_info *info)
370{
371	struct bios_regs regs;
372	regs.eax = 0x4f15;
373	regs.ebx = 0;
374		// report DDC service
375	regs.ecx = 0;
376	regs.es = 0;
377	regs.edi = 0;
378	call_bios(0x10, &regs);
379
380	TRACE(("EDID1: %lx\n", regs.eax));
381	// %ah contains the error code
382	// %al determines whether or not the function is supported
383	if (regs.eax != 0x4f)
384		return B_NOT_SUPPORTED;
385
386	TRACE(("EDID2: ebx %lx\n", regs.ebx));
387	// test if DDC is supported by the monitor
388	if ((regs.ebx & 3) == 0)
389		return B_NOT_SUPPORTED;
390
391	edid1_raw edidRaw;
392
393	regs.eax = 0x4f15;
394	regs.ebx = 1;
395		// read EDID
396	regs.ecx = 0;
397	regs.edx = 0;
398	regs.es = ADDRESS_SEGMENT(&edidRaw);
399	regs.edi = ADDRESS_OFFSET(&edidRaw);
400	call_bios(0x10, &regs);
401	TRACE(("EDID3: %lx\n", regs.eax));
402
403	if (regs.eax != 0x4f)
404		return B_NOT_SUPPORTED;
405
406	// retrieved EDID - now parse it
407	edid_decode(info, &edidRaw);
408
409#ifdef TRACE_VIDEO
410	edid_dump(info);
411#endif
412	return B_OK;
413}
414
415
416static status_t
417vesa_get_mode_info(uint16 mode, struct vbe_mode_info *modeInfo)
418{
419	memset(modeInfo, 0, sizeof(vbe_mode_info));
420
421	struct bios_regs regs;
422	regs.eax = 0x4f01;
423	regs.ecx = mode;
424	regs.es = ADDRESS_SEGMENT(modeInfo);
425	regs.edi = ADDRESS_OFFSET(modeInfo);
426	call_bios(0x10, &regs);
427
428	// %ah contains the error code
429	if ((regs.eax & 0xff00) != 0)
430		return B_ENTRY_NOT_FOUND;
431
432	return B_OK;
433}
434
435
436static status_t
437vesa_get_vbe_info_block(vbe_info_block *info)
438{
439	memset(info, 0, sizeof(vbe_info_block));
440	info->signature = VBE2_SIGNATURE;
441
442	struct bios_regs regs;
443	regs.eax = 0x4f00;
444	regs.es = ADDRESS_SEGMENT(info);
445	regs.edi = ADDRESS_OFFSET(info);
446	call_bios(0x10, &regs);
447
448	// %ah contains the error code
449	if ((regs.eax & 0xff00) != 0)
450		return B_ERROR;
451
452	if (info->signature != VESA_SIGNATURE)
453		return B_ERROR;
454
455	dprintf("VESA version = %d.%d, capabilities %lx\n", info->version.major,
456		info->version.minor, info->capabilities);
457
458	if (info->version.major < 2) {
459		dprintf("VESA support too old\n");
460		return B_ERROR;
461	}
462
463	info->oem_string = SEGMENTED_TO_LINEAR(info->oem_string);
464	info->mode_list = SEGMENTED_TO_LINEAR(info->mode_list);
465	dprintf("OEM string: %s\n", (const char *)info->oem_string);
466
467	return B_OK;
468}
469
470
471static status_t
472vesa_init(vbe_info_block *info, video_mode **_standardMode)
473{
474	if (vesa_get_vbe_info_block(info) != B_OK)
475		return B_ERROR;
476
477	// fill mode list and find standard video mode
478
479	video_mode *standardMode = NULL;
480
481	for (int32 i = 0; true; i++) {
482		uint16 mode = ((uint16 *)info->mode_list)[i];
483		if (mode == 0xffff)
484			break;
485
486		struct vbe_mode_info modeInfo;
487		if (vesa_get_mode_info(mode, &modeInfo) == B_OK) {
488			TRACE((" 0x%03x: %u x %u x %u (a = %d, mem = %d, phy = %lx, p = %d, b = %d)\n", mode,
489				   modeInfo.width, modeInfo.height, modeInfo.bits_per_pixel, modeInfo.attributes,
490				   modeInfo.memory_model, modeInfo.physical_base, modeInfo.num_planes,
491				   modeInfo.num_banks));
492			TRACE(("	mask: r: %d %d g: %d %d b: %d %d dcmi: %d\n",
493				   modeInfo.red_mask_size, modeInfo.red_field_position,
494				   modeInfo.green_mask_size, modeInfo.green_field_position,
495				   modeInfo.blue_mask_size, modeInfo.blue_field_position,
496				   modeInfo.direct_color_mode_info));
497
498			const uint32 requiredAttributes = MODE_ATTR_AVAILABLE
499				| MODE_ATTR_GRAPHICS_MODE | MODE_ATTR_COLOR_MODE
500				| MODE_ATTR_LINEAR_BUFFER;
501
502			if (modeInfo.width >= 640
503				&& modeInfo.physical_base != 0
504				&& modeInfo.num_planes == 1
505				&& (modeInfo.memory_model == MODE_MEMORY_PACKED_PIXEL
506					|| modeInfo.memory_model == MODE_MEMORY_DIRECT_COLOR)
507				&& (modeInfo.attributes & requiredAttributes)
508					== requiredAttributes) {
509				// this mode fits our needs
510				video_mode *videoMode = (video_mode *)malloc(
511					sizeof(struct video_mode));
512				if (videoMode == NULL)
513					continue;
514
515				videoMode->mode = mode;
516				videoMode->bytes_per_row = modeInfo.bytes_per_row;
517				videoMode->width = modeInfo.width;
518				videoMode->height = modeInfo.height;
519				videoMode->bits_per_pixel = modeInfo.bits_per_pixel;
520				videoMode->timing = NULL;
521
522				if (modeInfo.bits_per_pixel == 16
523					&& modeInfo.red_mask_size + modeInfo.green_mask_size
524						+ modeInfo.blue_mask_size == 15) {
525					// this is really a 15-bit mode
526					videoMode->bits_per_pixel = 15;
527				}
528
529				add_video_mode(videoMode);
530			}
531		} else
532			TRACE((" 0x%03x: (failed)\n", mode));
533	}
534
535	// Choose default resolution (when no EDID information is available)
536	const uint32 kPreferredWidth = 1024;
537	const uint32 kFallbackWidth = 800;
538
539	standardMode = find_video_mode(kPreferredWidth, -1, false);
540	if (standardMode == NULL) {
541		standardMode = find_video_mode(kFallbackWidth, -1, false);
542		if (standardMode == NULL) {
543			standardMode = find_video_mode(kPreferredWidth, -1, true);
544			if (standardMode == NULL)
545				standardMode = find_video_mode(kFallbackWidth, -1, true);
546		}
547	}
548	if (standardMode == NULL) {
549		// just take any mode
550		standardMode = (video_mode *)list_get_first_item(&sModeList);
551	}
552
553	if (standardMode == NULL) {
554		// no usable VESA mode found...
555		return B_ERROR;
556	}
557
558	TRACE(("Using mode 0x%03x\n", standardMode->mode));
559	*_standardMode = standardMode;
560	return B_OK;
561}
562
563
564#if 0
565static status_t
566vesa_get_mode(uint16 *_mode)
567{
568	struct bios_regs regs;
569	regs.eax = 0x4f03;
570	call_bios(0x10, &regs);
571
572	if ((regs.eax & 0xffff) != 0x4f)
573		return B_ERROR;
574
575	*_mode = regs.ebx & 0xffff;
576	return B_OK;
577}
578#endif
579
580
581static status_t
582vesa_set_mode(video_mode* mode, bool useTiming)
583{
584	struct bios_regs regs;
585	regs.eax = 0x4f02;
586	regs.ebx = (mode->mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER;
587
588	if (useTiming && mode->timing != NULL) {
589		regs.ebx |= SET_MODE_SPECIFY_CRTC;
590		regs.es = ADDRESS_SEGMENT(mode->timing);
591		regs.edi = ADDRESS_OFFSET(mode->timing);
592	}
593
594	call_bios(0x10, &regs);
595
596	if ((regs.eax & 0xffff) != 0x4f)
597		return B_ERROR;
598
599#if 0
600	// make sure we have 8 bits per color channel
601	regs.eax = 0x4f08;
602	regs.ebx = 8 << 8;
603	call_bios(0x10, &regs);
604#endif
605
606	return B_OK;
607}
608
609
610static status_t
611vesa_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries)
612{
613	// is this an 8 bit indexed color mode?
614	if (gKernelArgs.frame_buffer.depth != 8)
615		return B_BAD_TYPE;
616
617#if 0
618	struct bios_regs regs;
619	regs.eax = 0x4f09;
620	regs.ebx = 0;
621	regs.ecx = numEntries;
622	regs.edx = firstIndex;
623	regs.es = (addr_t)palette >> 4;
624	regs.edi = (addr_t)palette & 0xf;
625	call_bios(0x10, &regs);
626
627	if ((regs.eax & 0xffff) != 0x4f) {
628#endif
629		// the VESA call does not work, just try good old VGA mechanism
630		vga_set_palette(palette, firstIndex, numEntries);
631#if 0
632		return B_ERROR;
633	}
634#endif
635	return B_OK;
636}
637
638
639//	#pragma mark -
640
641
642bool
643video_mode_hook(Menu *menu, MenuItem *item)
644{
645	// find selected mode
646	video_mode *mode = NULL;
647
648	Menu* submenu = item->Submenu();
649	MenuItem* subitem = submenu->FindMarked();
650	if (subitem != NULL) {
651		switch (submenu->IndexOf(subitem)) {
652			case 0:
653				// "Default" mode special
654				sMode = sDefaultMode;
655				sModeChosen = false;
656				return true;
657			case 1:
658				// "Standard VGA" mode special
659				// sets sMode to NULL which triggers VGA mode
660				break;
661			default:
662				mode = (video_mode *)subitem->Data();
663				break;
664		}
665	}
666
667	if (mode != sMode) {
668		// update standard mode
669		// ToDo: update fb settings!
670		sMode = mode;
671	}
672
673	sModeChosen = true;
674	return true;
675}
676
677
678Menu *
679video_mode_menu()
680{
681	Menu *menu = new(nothrow) Menu(CHOICE_MENU, "Select Video Mode");
682	MenuItem *item;
683
684	menu->AddItem(item = new(nothrow) MenuItem("Default"));
685	item->SetMarked(true);
686	item->Select(true);
687	item->SetHelpText("The Default video mode is the one currently configured "
688		"in the system. If there is no mode configured yet, a viable mode will "
689		"be chosen automatically.");
690
691	menu->AddItem(new(nothrow) MenuItem("Standard VGA"));
692
693	video_mode *mode = NULL;
694	while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) != NULL) {
695		char label[64];
696		snprintf(label, sizeof(label), "%ux%u %u bit", mode->width,
697			mode->height, mode->bits_per_pixel);
698
699		menu->AddItem(item = new(nothrow) MenuItem(label));
700		item->SetData(mode);
701	}
702
703	menu->AddSeparatorItem();
704	menu->AddItem(item = new(nothrow) MenuItem("Return to main menu"));
705	item->SetType(MENU_ITEM_NO_CHOICE);
706
707	return menu;
708}
709
710
711static void
712set_vga_mode(void)
713{
714	// sets 640x480 16 colors graphics mode
715	bios_regs regs;
716	regs.eax = 0x0012;
717	call_bios(0x10, &regs);
718}
719
720
721static void
722set_text_mode(void)
723{
724	// sets 80x25 text console
725	bios_regs regs;
726	regs.eax = 0x0003;
727	call_bios(0x10, &regs);
728
729	video_hide_text_cursor();
730}
731
732
733void
734video_move_text_cursor(int x, int y)
735{
736	bios_regs regs;
737	regs.eax = 0x0200;
738	regs.ebx = 0;
739	regs.edx = (y << 8) | x;
740	call_bios(0x10, &regs);
741}
742
743
744void
745video_show_text_cursor(void)
746{
747	bios_regs regs;
748	regs.eax = 0x0100;
749	regs.ecx = 0x0607;
750	call_bios(0x10, &regs);
751}
752
753
754void
755video_hide_text_cursor(void)
756{
757	bios_regs regs;
758	regs.eax = 0x0100;
759	regs.ecx = 0x2000;
760	call_bios(0x10, &regs);
761}
762
763
764//	#pragma mark - blit
765
766
767void
768platform_blit4(addr_t frameBuffer, const uint8 *data,
769	uint16 width, uint16 height, uint16 imageWidth, uint16 left, uint16 top)
770{
771	if (!data)
772		return;
773	// ToDo: no boot logo yet in VGA mode
774#if 1
775// this draws 16 big rectangles in all the available colors
776	uint8 *bits = (uint8 *)frameBuffer;
777	uint32 bytesPerRow = 80;
778	for (int32 i = 0; i < 32; i++) {
779		bits[9 * bytesPerRow + i + 2] = 0x55;
780		bits[30 * bytesPerRow + i + 2] = 0xaa;
781	}
782
783	for (int32 y = 10; y < 30; y++) {
784		for (int32 i = 0; i < 16; i++) {
785			out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX);
786			bits[32 * bytesPerRow + i*2 + 2] = i;
787
788			if (i & 1) {
789				out16((1 << 8) | 0x02, VGA_SEQUENCER_INDEX);
790				bits[y * bytesPerRow + i*2 + 2] = 0xff;
791				bits[y * bytesPerRow + i*2 + 3] = 0xff;
792			}
793			if (i & 2) {
794				out16((2 << 8) | 0x02, VGA_SEQUENCER_INDEX);
795				bits[y * bytesPerRow + i*2 + 2] = 0xff;
796				bits[y * bytesPerRow + i*2 + 3] = 0xff;
797			}
798			if (i & 4) {
799				out16((4 << 8) | 0x02, VGA_SEQUENCER_INDEX);
800				bits[y * bytesPerRow + i*2 + 2] = 0xff;
801				bits[y * bytesPerRow + i*2 + 3] = 0xff;
802			}
803			if (i & 8) {
804				out16((8 << 8) | 0x02, VGA_SEQUENCER_INDEX);
805				bits[y * bytesPerRow + i*2 + 2] = 0xff;
806				bits[y * bytesPerRow + i*2 + 3] = 0xff;
807			}
808		}
809	}
810
811	// enable all planes again
812	out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX);
813#endif
814}
815
816
817extern "C" void
818platform_set_palette(const uint8 *palette)
819{
820	switch (gKernelArgs.frame_buffer.depth) {
821		case 4:
822			//vga_set_palette((const uint8 *)kPalette16, 0, 16);
823			break;
824		case 8:
825			if (vesa_set_palette((const uint8 *)palette, 0, 256) != B_OK)
826				dprintf("set palette failed!\n");
827
828			break;
829		default:
830			break;
831	}
832}
833
834
835//	#pragma mark -
836
837extern "C" void
838platform_switch_to_logo(void)
839{
840	// in debug mode, we'll never show the logo
841	if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0)
842		return;
843
844	addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start;
845	size_t lastSize = gKernelArgs.frame_buffer.physical_buffer.size;
846
847	if (sVesaCompatible && sMode != NULL) {
848		if (!sModeChosen)
849			get_mode_from_settings();
850
851		// On some BIOS / chipset / monitor combinations, there seems to be a
852		// timing issue between getting the EDID data and setting the video
853		// mode. As such we wait here briefly to give everything enough time
854		// to settle.
855		spin(1000);
856
857		if ((sMode->timing == NULL || vesa_set_mode(sMode, true) != B_OK)
858			&& vesa_set_mode(sMode, false) != B_OK)
859			goto fallback;
860
861		struct vbe_mode_info modeInfo;
862		if (vesa_get_mode_info(sMode->mode, &modeInfo) != B_OK)
863			goto fallback;
864
865		gKernelArgs.frame_buffer.width = modeInfo.width;
866		gKernelArgs.frame_buffer.height = modeInfo.height;
867		gKernelArgs.frame_buffer.bytes_per_row = modeInfo.bytes_per_row;
868		gKernelArgs.frame_buffer.depth = modeInfo.bits_per_pixel;
869		gKernelArgs.frame_buffer.physical_buffer.size
870			= (phys_size_t)modeInfo.bytes_per_row
871				* (phys_size_t)gKernelArgs.frame_buffer.height;
872		gKernelArgs.frame_buffer.physical_buffer.start = modeInfo.physical_base;
873	} else {
874fallback:
875		// use standard VGA mode 640x480x4
876		set_vga_mode();
877
878		gKernelArgs.frame_buffer.width = 640;
879		gKernelArgs.frame_buffer.height = 480;
880		gKernelArgs.frame_buffer.bytes_per_row = 80;
881		gKernelArgs.frame_buffer.depth = 4;
882		gKernelArgs.frame_buffer.physical_buffer.size
883			= (phys_size_t)gKernelArgs.frame_buffer.width
884				* (phys_size_t)gKernelArgs.frame_buffer.height / 2;
885		gKernelArgs.frame_buffer.physical_buffer.start = 0xa0000;
886	}
887
888	dprintf("video mode: %ux%ux%u\n", gKernelArgs.frame_buffer.width,
889		gKernelArgs.frame_buffer.height, gKernelArgs.frame_buffer.depth);
890
891	gKernelArgs.frame_buffer.enabled = true;
892
893	// If the new frame buffer is either larger than the old one or located at
894	// a different address, we need to remap it, so we first have to throw
895	// away its previous mapping
896	if (lastBase != 0
897		&& (lastBase != gKernelArgs.frame_buffer.physical_buffer.start
898			|| lastSize < gKernelArgs.frame_buffer.physical_buffer.size)) {
899		mmu_free((void *)sFrameBuffer, lastSize);
900		lastBase = 0;
901	}
902	if (lastBase == 0) {
903		// the graphics memory has not been mapped yet!
904		sFrameBuffer = mmu_map_physical_memory(
905			gKernelArgs.frame_buffer.physical_buffer.start,
906			gKernelArgs.frame_buffer.physical_buffer.size, kDefaultPageFlags);
907	}
908
909	video_display_splash(sFrameBuffer);
910}
911
912
913extern "C" void
914platform_switch_to_text_mode(void)
915{
916	if (!gKernelArgs.frame_buffer.enabled) {
917		vga_enable_bright_background_colors();
918		return;
919	}
920
921	set_text_mode();
922	gKernelArgs.frame_buffer.enabled = 0;
923
924	vga_enable_bright_background_colors();
925}
926
927
928extern "C" status_t
929platform_init_video(void)
930{
931	gKernelArgs.frame_buffer.enabled = 0;
932	list_init(&sModeList);
933
934	set_text_mode();
935		// You may wonder why we do this here:
936		// Obviously, some graphics card BIOS implementations don't
937		// report all available modes unless you've done this before
938		// getting the VESA information.
939		// One example of those is the SiS 630 chipset in my laptop.
940
941	sVesaCompatible = vesa_init(&sInfo, &sDefaultMode) == B_OK;
942	if (!sVesaCompatible) {
943		TRACE(("No VESA compatible graphics!\n"));
944		gKernelArgs.vesa_capabilities = 0;
945		return B_ERROR;
946	}
947
948	gKernelArgs.vesa_capabilities = sInfo.capabilities;
949
950	TRACE(("VESA compatible graphics!\n"));
951
952	// store VESA modes into kernel args
953	vesa_mode *modes = (vesa_mode *)kernel_args_malloc(
954		sModeCount * sizeof(vesa_mode));
955	if (modes != NULL) {
956		video_mode *mode = NULL;
957		uint32 i = 0;
958		while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
959				!= NULL) {
960			modes[i].mode = mode->mode;
961			modes[i].width = mode->width;
962			modes[i].height = mode->height;
963			modes[i].bits_per_pixel = mode->bits_per_pixel;
964			i++;
965		}
966
967		gKernelArgs.vesa_modes = modes;
968		gKernelArgs.vesa_modes_size = sModeCount * sizeof(vesa_mode);
969	}
970
971	edid1_info info;
972	// Note, we currently ignore EDID information for VBE2 - while the EDID
973	// information itself seems to be reliable, older chips often seem to
974	// use very strange default timings with higher modes.
975	// TODO: Maybe add a setting to enable it anyway?
976	if (sInfo.version.major >= 3 && vesa_get_edid(&info) == B_OK) {
977		// we got EDID information from the monitor, try to find a new default
978		// mode
979		video_mode *defaultMode = find_edid_mode(info, false);
980		if (defaultMode == NULL)
981			defaultMode = find_edid_mode(info, true);
982
983		if (defaultMode != NULL) {
984			// We found a new default mode to use!
985			sDefaultMode = defaultMode;
986		}
987
988		gKernelArgs.edid_info = kernel_args_malloc(sizeof(edid1_info));
989		if (gKernelArgs.edid_info != NULL)
990			memcpy(gKernelArgs.edid_info, &info, sizeof(edid1_info));
991	}
992
993	sMode = sDefaultMode;
994	return B_OK;
995}
996
997