video.cpp revision 0e35d5d2
1eefe4b1dSAxel Dörfler/*
213247f3aSAxel Dörfler * Copyright 2004-2009, Axel D��rfler,
3636bff2fSStephan Aßmus * Copyright 2008, Stephan A��mus <>
4636bff2fSStephan Aßmus * Copyright 2008, Philippe Saint-Pierre <>
5d2b49a00SRene Gollent * Copyright 2011, Rene Gollent,
6486c7eddSAxel Dörfler * Distributed under the terms of the MIT License.
7486c7eddSAxel Dörfler */
8eefe4b1dSAxel Dörfler
9eefe4b1dSAxel Dörfler
10eefe4b1dSAxel Dörfler#include "video.h"
11eefe4b1dSAxel Dörfler#include "bios.h"
12eefe4b1dSAxel Dörfler#include "vesa.h"
136328832fSAxel Dörfler#include "vesa_info.h"
14d3ff9cc3SAxel Dörfler#include "vga.h"
15eefe4b1dSAxel Dörfler#include "mmu.h"
16eefe4b1dSAxel Dörfler
175d7d960fSAxel Dörfler#include <edid.h>
185d7d960fSAxel Dörfler
19eefe4b1dSAxel Dörfler#include <arch/cpu.h>
20eefe4b1dSAxel Dörfler#include <boot/stage2.h>
21eefe4b1dSAxel Dörfler#include <boot/platform.h>
22689c94c8SAxel Dörfler#include <boot/menu.h>
23eefe4b1dSAxel Dörfler#include <boot/kernel_args.h>
240573d397SFrançois Revol#include <boot/platform/generic/video.h>
25f42302bcSAxel Dörfler#include <util/list.h>
26486c7eddSAxel Dörfler#include <drivers/driver_settings.h>
27eefe4b1dSAxel Dörfler
28f42302bcSAxel Dörfler#include <stdio.h>
29c918a987SAxel Dörfler#include <stdlib.h>
30eefe4b1dSAxel Dörfler#include <string.h>
31eefe4b1dSAxel Dörfler
32eefe4b1dSAxel Dörfler
33d16ddc57SAxel Dörfler#define TRACE_VIDEO
34b1cd9d2dSAxel Dörfler#ifdef TRACE_VIDEO
3592e0317cSAxel Dörfler#	define TRACE(x) dprintf x
36b1cd9d2dSAxel Dörfler#else
37b1cd9d2dSAxel Dörfler#	define TRACE(x) ;
38b1cd9d2dSAxel Dörfler#endif
39b1cd9d2dSAxel Dörfler
40b1cd9d2dSAxel Dörfler
41f42302bcSAxel Dörflerstruct video_mode {
42f42302bcSAxel Dörfler	list_link	link;
43f42302bcSAxel Dörfler	uint16		mode;
445845b6ecSAxel Dörfler	uint16		width, height, bits_per_pixel;
455845b6ecSAxel Dörfler	uint32		bytes_per_row;
46b4c8ccc3SAxel Dörfler	crtc_info_block* timing;
47f42302bcSAxel Dörfler};
48f42302bcSAxel Dörfler
49eefe4b1dSAxel Dörflerstatic vbe_info_block sInfo;
50d3ff9cc3SAxel Dörflerstatic video_mode *sMode, *sDefaultMode;
51486c7eddSAxel Dörflerstatic bool sVesaCompatible;
526328832fSAxel Dörflerstatic struct list sModeList;
536328832fSAxel Dörflerstatic uint32 sModeCount;
54a3a08080SAxel Dörflerstatic addr_t sFrameBuffer;
55486c7eddSAxel Dörflerstatic bool sModeChosen;
56486c7eddSAxel Dörflerstatic bool sSettingsLoaded;
57eefe4b1dSAxel Dörfler
58eefe4b1dSAxel Dörfler
59d5062208SAxel Dörflerstatic int
60d5062208SAxel Dörflercompare_video_modes(video_mode *a, video_mode *b)
61d5062208SAxel Dörfler{
62d5062208SAxel Dörfler	int compare = a->width - b->width;
63d5062208SAxel Dörfler	if (compare != 0)
64d5062208SAxel Dörfler		return compare;
65d5062208SAxel Dörfler
66d5062208SAxel Dörfler	compare = a->height - b->height;
67d5062208SAxel Dörfler	if (compare != 0)
68d5062208SAxel Dörfler		return compare;
69d5062208SAxel Dörfler
70d5062208SAxel Dörfler	// TODO: compare video_mode::mode?
71d5062208SAxel Dörfler	return a->bits_per_pixel - b->bits_per_pixel;
72d5062208SAxel Dörfler}
73d5062208SAxel Dörfler
74d5062208SAxel Dörfler
759b13056bSAxel Dörfler/*!	Insert the video mode into the list, sorted by resolution and bit depth.
769b13056bSAxel Dörfler	Higher resolutions/depths come first.
779b13056bSAxel Dörfler*/
78d5062208SAxel Dörflerstatic void
79d5062208SAxel Dörfleradd_video_mode(video_mode *videoMode)
80d5062208SAxel Dörfler{
81d5062208SAxel Dörfler	video_mode *mode = NULL;
82cedc3f1eSAxel Dörfler	while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
83cedc3f1eSAxel Dörfler			!= NULL) {
84d5062208SAxel Dörfler		int compare = compare_video_modes(videoMode, mode);
85d5062208SAxel Dörfler		if (compare == 0) {
86d5062208SAxel Dörfler			// mode already exists
87d5062208SAxel Dörfler			return;
88d5062208SAxel Dörfler		}
89d5062208SAxel Dörfler
90d5062208SAxel Dörfler		if (compare > 0)
91d5062208SAxel Dörfler			break;
92d5062208SAxel Dörfler	}
93d5062208SAxel Dörfler
94d5062208SAxel Dörfler	list_insert_item_before(&sModeList, mode, videoMode);
956328832fSAxel Dörfler	sModeCount++;
96d5062208SAxel Dörfler}
97d5062208SAxel Dörfler
98d5062208SAxel Dörfler
99652c8526SAxel Dörfler/*! \brief Finds a video mode with the given resolution.
100652c8526SAxel Dörfler	If \a allowPalette is true, 8-bit modes are considered, too.
101652c8526SAxel Dörfler	If \a height is \c -1, the height is ignored, and only the width
102652c8526SAxel Dörfler	matters.
103652c8526SAxel Dörfler*/
104d2de13bdSAxel Dörflerstatic video_mode *
105cedc3f1eSAxel Dörflerfind_video_mode(int32 width, int32 height, bool allowPalette)
106d2de13bdSAxel Dörfler{
107d2de13bdSAxel Dörfler	video_mode *found = NULL;
108d2de13bdSAxel Dörfler	video_mode *mode = NULL;
109cedc3f1eSAxel Dörfler	while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
110cedc3f1eSAxel Dörfler			!= NULL) {
111652c8526SAxel Dörfler		if (mode->width == width && (height == -1 || mode->height == height)
112cedc3f1eSAxel Dörfler			&& (mode->bits_per_pixel > 8 || allowPalette)) {
113d2de13bdSAxel Dörfler			if (found == NULL || found->bits_per_pixel < mode->bits_per_pixel)
114d2de13bdSAxel Dörfler				found = mode;
115d2de13bdSAxel Dörfler		}
116d2de13bdSAxel Dörfler	}
117d2de13bdSAxel Dörfler
118d2de13bdSAxel Dörfler	return found;
119d2de13bdSAxel Dörfler}
120d2de13bdSAxel Dörfler
121d2de13bdSAxel Dörfler
122ca6210d5SAxel Dörfler/*! Returns the VESA mode closest to the one specified, with a width less or
123ca6210d5SAxel Dörfler	equal as specified.
124ca6210d5SAxel Dörfler	The height as well as the depth may vary in both directions, though.
125ca6210d5SAxel Dörfler*/
126d5062208SAxel Dörflerstatic video_mode *
1276328832fSAxel Dörflerclosest_video_mode(int32 width, int32 height, int32 depth)
128d5062208SAxel Dörfler{
1296328832fSAxel Dörfler	video_mode *bestMode = NULL;
1306328832fSAxel Dörfler	uint32 bestDiff = 0;
1316328832fSAxel Dörfler
132d5062208SAxel Dörfler	video_mode *mode = NULL;
133cedc3f1eSAxel Dörfler	while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
134cedc3f1eSAxel Dörfler			!= NULL) {
135ca6210d5SAxel Dörfler		if (mode->width > width) {
136ca6210d5SAxel Dörfler			// Only choose modes with a width less or equal than the searched
137ca6210d5SAxel Dörfler			// one; or else it might well be that the monitor cannot keep up.
138ca6210d5SAxel Dörfler			continue;
139ca6210d5SAxel Dörfler		}
140ca6210d5SAxel Dörfler
1416328832fSAxel Dörfler		uint32 diff = 2 * abs(mode->width - width) + abs(mode->height - height)
1426328832fSAxel Dörfler			+ abs(mode->bits_per_pixel - depth);
1436328832fSAxel Dörfler
1446328832fSAxel Dörfler		if (bestMode == NULL || bestDiff > diff) {
1456328832fSAxel Dörfler			bestMode = mode;
1466328832fSAxel Dörfler			bestDiff = diff;
147d5062208SAxel Dörfler		}
148d5062208SAxel Dörfler	}
149d5062208SAxel Dörfler
1506328832fSAxel Dörfler	return bestMode;
151d5062208SAxel Dörfler}
152d5062208SAxel Dörfler
153d5062208SAxel Dörfler
154b4c8ccc3SAxel Dörflerstatic crtc_info_block*
155b4c8ccc3SAxel Dörflerget_crtc_info_block(edid1_detailed_timing& timing)
156b4c8ccc3SAxel Dörfler{
15739c7faa4SAxel Dörfler	// This feature is only available on chipsets supporting VBE3 and up
15839c7faa4SAxel Dörfler	if (sInfo.version.major < 3)
15939c7faa4SAxel Dörfler		return NULL;
16039c7faa4SAxel Dörfler
161b4c8ccc3SAxel Dörfler	// Copy timing structure to set the mode with
162b4c8ccc3SAxel Dörfler	crtc_info_block* crtcInfo = (crtc_info_block*)malloc(
163b4c8ccc3SAxel Dörfler		sizeof(crtc_info_block));
164b4c8ccc3SAxel Dörfler	if (crtcInfo == NULL)
165b4c8ccc3SAxel Dörfler		return NULL;
166b4c8ccc3SAxel Dörfler
167b4c8ccc3SAxel Dörfler	memset(crtcInfo, 0, sizeof(crtc_info_block));
168b4c8ccc3SAxel Dörfler	crtcInfo->horizontal_sync_start = timing.h_active + timing.h_sync_off;
169b4c8ccc3SAxel Dörfler	crtcInfo->horizontal_sync_end = crtcInfo->horizontal_sync_start
170b4c8ccc3SAxel Dörfler		+ timing.h_sync_width;
171b4c8ccc3SAxel Dörfler	crtcInfo->horizontal_total = timing.h_active + timing.h_blank;
172b4c8ccc3SAxel Dörfler	crtcInfo->vertical_sync_start = timing.v_active + timing.v_sync_off;
173b4c8ccc3SAxel Dörfler	crtcInfo->vertical_sync_end = crtcInfo->vertical_sync_start
174b4c8ccc3SAxel Dörfler		+ timing.v_sync_width;
175b4c8ccc3SAxel Dörfler	crtcInfo->vertical_total = timing.v_active + timing.v_blank;
176b4c8ccc3SAxel Dörfler	crtcInfo->pixel_clock = timing.pixel_clock * 10000L;
177b4c8ccc3SAxel Dörfler	crtcInfo->refresh_rate = crtcInfo->pixel_clock
178b4c8ccc3SAxel Dörfler		/ (crtcInfo->horizontal_total / 10)
179b4c8ccc3SAxel Dörfler		/ (crtcInfo->vertical_total / 10);
180b4c8ccc3SAxel Dörfler
18139c7faa4SAxel Dörfler	TRACE(("crtc: h %u/%u/%u, v %u/%u/%u, pixel clock %lu, refresh %u\n",
18239c7faa4SAxel Dörfler		crtcInfo->horizontal_sync_start, crtcInfo->horizontal_sync_end,
18339c7faa4SAxel Dörfler		crtcInfo->horizontal_total, crtcInfo->vertical_sync_start,
18439c7faa4SAxel Dörfler		crtcInfo->vertical_sync_end, crtcInfo->vertical_total,
18539c7faa4SAxel Dörfler		crtcInfo->pixel_clock, crtcInfo->refresh_rate));
18639c7faa4SAxel Dörfler
187b4c8ccc3SAxel Dörfler	crtcInfo->flags = 0;
188b4c8ccc3SAxel Dörfler	if (timing.sync == 3) {
189b4c8ccc3SAxel Dörfler		// TODO: this switches the default sync when sync != 3 (compared to
190b4c8ccc3SAxel Dörfler		// create_display_modes().
191b4c8ccc3SAxel Dörfler		if ((timing.misc & 1) == 0)
192b4c8ccc3SAxel Dörfler			crtcInfo->flags |= CRTC_NEGATIVE_HSYNC;
193b4c8ccc3SAxel Dörfler		if ((timing.misc & 2) == 0)
194b4c8ccc3SAxel Dörfler			crtcInfo->flags |= CRTC_NEGATIVE_VSYNC;
195b4c8ccc3SAxel Dörfler	}
196b4c8ccc3SAxel Dörfler	if (timing.interlaced)
197b4c8ccc3SAxel Dörfler		crtcInfo->flags |= CRTC_INTERLACED;
198b4c8ccc3SAxel Dörfler
199b4c8ccc3SAxel Dörfler	return crtcInfo;
200b4c8ccc3SAxel Dörfler}
201b4c8ccc3SAxel Dörfler
202b4c8ccc3SAxel Dörfler
203b4c8ccc3SAxel Dörflerstatic crtc_info_block*
204b4c8ccc3SAxel Dörflerget_crtc_info_block(edid1_std_timing& timing)
205b4c8ccc3SAxel Dörfler{
206b4c8ccc3SAxel Dörfler	// TODO: implement me!
207b4c8ccc3SAxel Dörfler	return NULL;
208b4c8ccc3SAxel Dörfler}
209b4c8ccc3SAxel Dörfler
210b4c8ccc3SAxel Dörfler
211b4c8ccc3SAxel Dörflerstatic video_mode*
212b4c8ccc3SAxel Dörflerfind_edid_mode(edid1_info& info, bool allowPalette)
213cedc3f1eSAxel Dörfler{
214cedc3f1eSAxel Dörfler	video_mode *mode = NULL;
215cedc3f1eSAxel Dörfler
216cedc3f1eSAxel Dörfler	// try detailed timing first
217cedc3f1eSAxel Dörfler	for (int32 i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; i++) {
218b4c8ccc3SAxel Dörfler		edid1_detailed_monitor& monitor = info.detailed_monitor[i];
219cedc3f1eSAxel Dörfler
220cedc3f1eSAxel Dörfler		if (monitor.monitor_desc_type == EDID1_IS_DETAILED_TIMING) {
221cedc3f1eSAxel Dörfler			mode = find_video_mode(,
222cedc3f1eSAxel Dörfler, allowPalette);
223b4c8ccc3SAxel Dörfler			if (mode != NULL) {
224b4c8ccc3SAxel Dörfler				mode->timing
225b4c8ccc3SAxel Dörfler					= get_crtc_info_block(;
226cedc3f1eSAxel Dörfler				return mode;
227b4c8ccc3SAxel Dörfler			}
228cedc3f1eSAxel Dörfler		}
229cedc3f1eSAxel Dörfler	}
230cedc3f1eSAxel Dörfler
231b4c8ccc3SAxel Dörfler	int32 best = -1;
232b4c8ccc3SAxel Dörfler
233cedc3f1eSAxel Dörfler	// try standard timings next
234cedc3f1eSAxel Dörfler	for (int32 i = 0; i < EDID1_NUM_STD_TIMING; i++) {
235cedc3f1eSAxel Dörfler		if (info.std_timing[i].h_size <= 256)
236cedc3f1eSAxel Dörfler			continue;
237cedc3f1eSAxel Dörfler
238b4c8ccc3SAxel Dörfler		video_mode* found = find_video_mode(info.std_timing[i].h_size,
239cedc3f1eSAxel Dörfler			info.std_timing[i].v_size, allowPalette);
240cedc3f1eSAxel Dörfler		if (found != NULL) {
241cedc3f1eSAxel Dörfler			if (mode != NULL) {
242cedc3f1eSAxel Dörfler				// prefer higher resolutions
243b4c8ccc3SAxel Dörfler				if (found->width > mode->width) {
244cedc3f1eSAxel Dörfler					mode = found;
245b4c8ccc3SAxel Dörfler					best = i;
246b4c8ccc3SAxel Dörfler				}
247b4c8ccc3SAxel Dörfler			} else {
248cedc3f1eSAxel Dörfler				mode = found;
249b4c8ccc3SAxel Dörfler				best = i;
250b4c8ccc3SAxel Dörfler			}
251cedc3f1eSAxel Dörfler		}
252cedc3f1eSAxel Dörfler	}
253cedc3f1eSAxel Dörfler
254b4c8ccc3SAxel Dörfler	if (best >= 0)
255b4c8ccc3SAxel Dörfler		mode->timing = get_crtc_info_block(info.std_timing[best]);
256b4c8ccc3SAxel Dörfler
257ca6210d5SAxel Dörfler	return mode;
258cedc3f1eSAxel Dörfler}
259cedc3f1eSAxel Dörfler
260cedc3f1eSAxel Dörfler
2615d7d960fSAxel Dörflerstatic bool
262d5062208SAxel Dörflerget_mode_from_settings(void)
263d5062208SAxel Dörfler{
264d5062208SAxel Dörfler	if (sSettingsLoaded)
2655d7d960fSAxel Dörfler		return true;
266d5062208SAxel Dörfler
267d5062208SAxel Dörfler	void *handle = load_driver_settings("vesa");
268d5062208SAxel Dörfler	if (handle == NULL)
2695d7d960fSAxel Dörfler		return false;
2705d7d960fSAxel Dörfler
2715d7d960fSAxel Dörfler	bool found = false;
272d5062208SAxel Dörfler
273d5062208SAxel Dörfler	const driver_settings *settings = get_driver_settings(handle);
274d5062208SAxel Dörfler	if (settings == NULL)
275d5062208SAxel Dörfler		goto out;
276d5062208SAxel Dörfler
277d5062208SAxel Dörfler	sSettingsLoaded = true;
278d5062208SAxel Dörfler
279d5062208SAxel Dörfler	for (int32 i = 0; i < settings->parameter_count; i++) {
280d5062208SAxel Dörfler		driver_parameter &parameter = settings->parameters[i];
281d5062208SAxel Dörfler
282d5062208SAxel Dörfler		if (!strcmp(, "mode") && parameter.value_count > 2) {
283d5062208SAxel Dörfler			// parameter found, now get its values
284d5062208SAxel Dörfler			int32 width = strtol(parameter.values[0], NULL, 0);
285d5062208SAxel Dörfler			int32 height = strtol(parameter.values[1], NULL, 0);
286d5062208SAxel Dörfler			int32 depth = strtol(parameter.values[2], NULL, 0);
287d5062208SAxel Dörfler
288d5062208SAxel Dörfler			// search mode that fits
289d5062208SAxel Dörfler
2906328832fSAxel Dörfler			video_mode *mode = closest_video_mode(width, height, depth);
2915d7d960fSAxel Dörfler			if (mode != NULL) {
2925d7d960fSAxel Dörfler				found = true;
293d5062208SAxel Dörfler				sMode = mode;
2945d7d960fSAxel Dörfler			}
295d5062208SAxel Dörfler		}
296d5062208SAxel Dörfler	}
297d5062208SAxel Dörfler
298d5062208SAxel Dörflerout:
299d5062208SAxel Dörfler	unload_driver_settings(handle);
3005d7d960fSAxel Dörfler	return found;
301d5062208SAxel Dörfler}
302d5062208SAxel Dörfler
303d5062208SAxel Dörfler
304d5062208SAxel Dörfler//	#pragma mark - vga
305d5062208SAxel Dörfler
306d5062208SAxel Dörfler
307eefe4b1dSAxel Dörflerstatic void
308eefe4b1dSAxel Dörflervga_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries)
309eefe4b1dSAxel Dörfler{
310d3ff9cc3SAxel Dörfler	out8(firstIndex, VGA_COLOR_WRITE_MODE);
311eefe4b1dSAxel Dörfler	// write VGA palette
312eefe4b1dSAxel Dörfler	for (int32 i = firstIndex; i < numEntries; i++) {
313eefe4b1dSAxel Dörfler		// VGA (usually) has only 6 bits per gun
314d3ff9cc3SAxel Dörfler		out8(palette[i * 3 + 0] >> 2, VGA_COLOR_DATA);
315d3ff9cc3SAxel Dörfler		out8(palette[i * 3 + 1] >> 2, VGA_COLOR_DATA);
316d3ff9cc3SAxel Dörfler		out8(palette[i * 3 + 2] >> 2, VGA_COLOR_DATA);
317eefe4b1dSAxel Dörfler	}
318eefe4b1dSAxel Dörfler}
319eefe4b1dSAxel Dörfler
320eefe4b1dSAxel Dörfler
3218c3e1399SAxel Dörflerstatic void
3228c3e1399SAxel Dörflervga_enable_bright_background_colors(void)
3238c3e1399SAxel Dörfler{
3248c3e1399SAxel Dörfler	// reset attribute controller
325d3ff9cc3SAxel Dörfler	in8(VGA_INPUT_STATUS_1);
3268c3e1399SAxel Dörfler
3278c3e1399SAxel Dörfler	// select mode control register
328d3ff9cc3SAxel Dörfler	out8(0x30, VGA_ATTRIBUTE_WRITE);
3298c3e1399SAxel Dörfler
3308c3e1399SAxel Dörfler	// read mode control register, change it (we need to clear bit 3), and write it back
331d3ff9cc3SAxel Dörfler	uint8 mode = in8(VGA_ATTRIBUTE_READ) & 0xf7;
332d3ff9cc3SAxel Dörfler	out8(mode, VGA_ATTRIBUTE_WRITE);
3338c3e1399SAxel Dörfler}
3348c3e1399SAxel Dörfler
3358c3e1399SAxel Dörfler
3368cd812c1SAxel Dörfler//	#pragma mark - vesa
337eefe4b1dSAxel Dörfler
338eefe4b1dSAxel Dörfler
3395d7d960fSAxel Dörflerstatic status_t
3405d7d960fSAxel Dörflervesa_get_edid(edid1_info *info)
3415d7d960fSAxel Dörfler{
3425d7d960fSAxel Dörfler	struct bios_regs regs;
3435d7d960fSAxel Dörfler	regs.eax = 0x4f15;
3445d7d960fSAxel Dörfler	regs.ebx = 0;
3455d7d960fSAxel Dörfler		// report DDC service
3465d7d960fSAxel Dörfler	regs.ecx = 0;
3475d7d960fSAxel Dörfler = 0;
3485d7d960fSAxel Dörfler	regs.edi = 0;
3495d7d960fSAxel Dörfler	call_bios(0x10, &regs);
3505d7d960fSAxel Dörfler
35160642f87SAxel Dörfler	TRACE(("EDID1: %lx\n", regs.eax));
3525d7d960fSAxel Dörfler	// %ah contains the error code
3530e35d5d2SJohn Scipione	// %al determines whether or not the function is supported
354d6edf65bSAxel Dörfler	if (regs.eax != 0x4f)
3555d7d960fSAxel Dörfler		return B_NOT_SUPPORTED;
3565d7d960fSAxel Dörfler
35760642f87SAxel Dörfler	TRACE(("EDID2: ebx %lx\n", regs.ebx));
358d6edf65bSAxel Dörfler	// test if DDC is supported by the monitor
359d6edf65bSAxel Dörfler	if ((regs.ebx & 3) == 0)
3605d7d960fSAxel Dörfler		return B_NOT_SUPPORTED;
3615d7d960fSAxel Dörfler
3625d7d960fSAxel Dörfler	edid1_raw edidRaw;
3635d7d960fSAxel Dörfler
3645d7d960fSAxel Dörfler	regs.eax = 0x4f15;
3655d7d960fSAxel Dörfler	regs.ebx = 1;
3665d7d960fSAxel Dörfler		// read EDID
3675d7d960fSAxel Dörfler	regs.ecx = 0;
3685d7d960fSAxel Dörfler	regs.edx = 0;
3695d7d960fSAxel Dörfler = ADDRESS_SEGMENT(&edidRaw);
3705d7d960fSAxel Dörfler	regs.edi = ADDRESS_OFFSET(&edidRaw);
3715d7d960fSAxel Dörfler	call_bios(0x10, &regs);
37260642f87SAxel Dörfler	TRACE(("EDID3: %lx\n", regs.eax));
3735d7d960fSAxel Dörfler
374d6edf65bSAxel Dörfler	if (regs.eax != 0x4f)
3755d7d960fSAxel Dörfler		return B_NOT_SUPPORTED;
3765d7d960fSAxel Dörfler
3775d7d960fSAxel Dörfler	// retrieved EDID - now parse it
3785d7d960fSAxel Dörfler	edid_decode(info, &edidRaw);
37960642f87SAxel Dörfler
38060642f87SAxel Dörfler#ifdef TRACE_VIDEO
3815d7d960fSAxel Dörfler	edid_dump(info);
38260642f87SAxel Dörfler#endif
3835d7d960fSAxel Dörfler	return B_OK;
3845d7d960fSAxel Dörfler}
3855d7d960fSAxel Dörfler
3865d7d960fSAxel Dörfler
387eefe4b1dSAxel Dörflerstatic status_t
388eefe4b1dSAxel Dörflervesa_get_mode_info(uint16 mode, struct vbe_mode_info *modeInfo)
389eefe4b1dSAxel Dörfler{
390133c5b73SAxel Dörfler	memset(modeInfo, 0, sizeof(vbe_mode_info));
391133c5b73SAxel Dörfler
392eefe4b1dSAxel Dörfler	struct bios_regs regs;
393eefe4b1dSAxel Dörfler	regs.eax = 0x4f01;
394eefe4b1dSAxel Dörfler	regs.ecx = mode;
3954c179368SAxel Dörfler = ADDRESS_SEGMENT(modeInfo);
3964c179368SAxel Dörfler	regs.edi = ADDRESS_OFFSET(modeInfo);
397eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
398eefe4b1dSAxel Dörfler
399133c5b73SAxel Dörfler	// %ah contains the error code
400133c5b73SAxel Dörfler	if ((regs.eax & 0xff00) != 0)
401eefe4b1dSAxel Dörfler		return B_ENTRY_NOT_FOUND;
402eefe4b1dSAxel Dörfler
403eefe4b1dSAxel Dörfler	return B_OK;
404eefe4b1dSAxel Dörfler}
405eefe4b1dSAxel Dörfler
406eefe4b1dSAxel Dörfler
407eefe4b1dSAxel Dörflerstatic status_t
408ce5cf7b3SAxel Dörflervesa_get_vbe_info_block(vbe_info_block *info)
409eefe4b1dSAxel Dörfler{
410eefe4b1dSAxel Dörfler	memset(info, 0, sizeof(vbe_info_block));
411eefe4b1dSAxel Dörfler	info->signature = VBE2_SIGNATURE;
412eefe4b1dSAxel Dörfler
413eefe4b1dSAxel Dörfler	struct bios_regs regs;
414eefe4b1dSAxel Dörfler	regs.eax = 0x4f00;
415ce5cf7b3SAxel Dörfler = ADDRESS_SEGMENT(info);
416ce5cf7b3SAxel Dörfler	regs.edi = ADDRESS_OFFSET(info);
417eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
418eefe4b1dSAxel Dörfler
419133c5b73SAxel Dörfler	// %ah contains the error code
420133c5b73SAxel Dörfler	if ((regs.eax & 0xff00) != 0)
421eefe4b1dSAxel Dörfler		return B_ERROR;
422eefe4b1dSAxel Dörfler
423eefe4b1dSAxel Dörfler	if (info->signature != VESA_SIGNATURE)
424eefe4b1dSAxel Dörfler		return B_ERROR;
425eefe4b1dSAxel Dörfler
42655be2751SAxel Dörfler	dprintf("VESA version = %d.%d, capabilities %lx\n", info->version.major,
42755be2751SAxel Dörfler		info->version.minor, info->capabilities);
428eefe4b1dSAxel Dörfler
429eefe4b1dSAxel Dörfler	if (info->version.major < 2) {
43013a81299SAxel Dörfler		dprintf("VESA support too old\n");
431eefe4b1dSAxel Dörfler		return B_ERROR;
432eefe4b1dSAxel Dörfler	}
433eefe4b1dSAxel Dörfler
434ce5cf7b3SAxel Dörfler	info->oem_string = SEGMENTED_TO_LINEAR(info->oem_string);
435ce5cf7b3SAxel Dörfler	info->mode_list = SEGMENTED_TO_LINEAR(info->mode_list);
43660642f87SAxel Dörfler	dprintf("OEM string: %s\n", (const char *)info->oem_string);
437eefe4b1dSAxel Dörfler
438ce5cf7b3SAxel Dörfler	return B_OK;
439ce5cf7b3SAxel Dörfler}
440ce5cf7b3SAxel Dörfler
441ce5cf7b3SAxel Dörfler
442ce5cf7b3SAxel Dörflerstatic status_t
443f42302bcSAxel Dörflervesa_init(vbe_info_block *info, video_mode **_standardMode)
444ce5cf7b3SAxel Dörfler{
445ce5cf7b3SAxel Dörfler	if (vesa_get_vbe_info_block(info) != B_OK)
446ce5cf7b3SAxel Dörfler		return B_ERROR;
447eefe4b1dSAxel Dörfler
4480752edcfSAxel Dörfler	// fill mode list and find standard video mode
449f42302bcSAxel Dörfler
450f42302bcSAxel Dörfler	video_mode *standardMode = NULL;
451f42302bcSAxel Dörfler
452133c5b73SAxel Dörfler	for (int32 i = 0; true; i++) {
453133c5b73SAxel Dörfler		uint16 mode = ((uint16 *)info->mode_list)[i];
454eefe4b1dSAxel Dörfler		if (mode == 0xffff)
455eefe4b1dSAxel Dörfler			break;
456eefe4b1dSAxel Dörfler
457eefe4b1dSAxel Dörfler		struct vbe_mode_info modeInfo;
458eefe4b1dSAxel Dörfler		if (vesa_get_mode_info(mode, &modeInfo) == B_OK) {
459746efef3SFrançois Revol			TRACE((" 0x%03x: %u x %u x %u (a = %d, mem = %d, phy = %lx, p = %d, b = %d)\n", mode,
460746efef3SFrançois Revol				   modeInfo.width, modeInfo.height, modeInfo.bits_per_pixel, modeInfo.attributes,
461746efef3SFrançois Revol				   modeInfo.memory_model, modeInfo.physical_base, modeInfo.num_planes,
462746efef3SFrançois Revol				   modeInfo.num_banks));
463746efef3SFrançois Revol			TRACE(("	mask: r: %d %d g: %d %d b: %d %d dcmi: %d\n",
464746efef3SFrançois Revol				   modeInfo.red_mask_size, modeInfo.red_field_position,
4653872a2d2SIngo Weinhold				   modeInfo.green_mask_size, modeInfo.green_field_position,
466746efef3SFrançois Revol				   modeInfo.blue_mask_size, modeInfo.blue_field_position,
467746efef3SFrançois Revol				   modeInfo.direct_color_mode_info));
4683872a2d2SIngo Weinhold
4699b13056bSAxel Dörfler			const uint32 requiredAttributes = MODE_ATTR_AVAILABLE
4719b13056bSAxel Dörfler				| MODE_ATTR_LINEAR_BUFFER;
472eefe4b1dSAxel Dörfler
473f42302bcSAxel Dörfler			if (modeInfo.width >= 640
474eefe4b1dSAxel Dörfler				&& modeInfo.physical_base != 0
475eefe4b1dSAxel Dörfler				&& modeInfo.num_planes == 1
476eefe4b1dSAxel Dörfler				&& (modeInfo.memory_model == MODE_MEMORY_PACKED_PIXEL
477eefe4b1dSAxel Dörfler					|| modeInfo.memory_model == MODE_MEMORY_DIRECT_COLOR)
4789b13056bSAxel Dörfler				&& (modeInfo.attributes & requiredAttributes)
4799b13056bSAxel Dörfler					== requiredAttributes) {
480f42302bcSAxel Dörfler				// this mode fits our needs
4819b13056bSAxel Dörfler				video_mode *videoMode = (video_mode *)malloc(
4829b13056bSAxel Dörfler					sizeof(struct video_mode));
483f42302bcSAxel Dörfler				if (videoMode == NULL)
484f42302bcSAxel Dörfler					continue;
485f42302bcSAxel Dörfler
486f42302bcSAxel Dörfler				videoMode->mode = mode;
4875845b6ecSAxel Dörfler				videoMode->bytes_per_row = modeInfo.bytes_per_row;
488f42302bcSAxel Dörfler				videoMode->width = modeInfo.width;
489f42302bcSAxel Dörfler				videoMode->height = modeInfo.height;
490f42302bcSAxel Dörfler				videoMode->bits_per_pixel = modeInfo.bits_per_pixel;
491b4c8ccc3SAxel Dörfler				videoMode->timing = NULL;
492b4c8ccc3SAxel Dörfler
4935845b6ecSAxel Dörfler				if (modeInfo.bits_per_pixel == 16
4945845b6ecSAxel Dörfler					&& modeInfo.red_mask_size + modeInfo.green_mask_size
4955845b6ecSAxel Dörfler						+ modeInfo.blue_mask_size == 15) {
4965845b6ecSAxel Dörfler					// this is really a 15-bit mode
4975845b6ecSAxel Dörfler					videoMode->bits_per_pixel = 15;
4985845b6ecSAxel Dörfler				}
499f42302bcSAxel Dörfler
500d5062208SAxel Dörfler				add_video_mode(videoMode);
501eefe4b1dSAxel Dörfler			}
502eefe4b1dSAxel Dörfler		} else
503746efef3SFrançois Revol			TRACE((" 0x%03x: (failed)\n", mode));
504eefe4b1dSAxel Dörfler	}
505eefe4b1dSAxel Dörfler
506652c8526SAxel Dörfler	// Choose default resolution (when no EDID information is available)
507e146dee3SAxel Dörfler	const uint32 kPreferredWidth = 1024;
508e146dee3SAxel Dörfler	const uint32 kFallbackWidth = 800;
509e146dee3SAxel Dörfler
510e146dee3SAxel Dörfler	standardMode = find_video_mode(kPreferredWidth, -1, false);
511e146dee3SAxel Dörfler	if (standardMode == NULL) {
512e146dee3SAxel Dörfler		standardMode = find_video_mode(kFallbackWidth, -1, false);
513e146dee3SAxel Dörfler		if (standardMode == NULL) {
514e146dee3SAxel Dörfler			standardMode = find_video_mode(kPreferredWidth, -1, true);
515e146dee3SAxel Dörfler			if (standardMode == NULL)
516e146dee3SAxel Dörfler				standardMode = find_video_mode(kFallbackWidth, -1, true);
517e146dee3SAxel Dörfler		}
518e146dee3SAxel Dörfler	}
519e146dee3SAxel Dörfler	if (standardMode == NULL) {
520e146dee3SAxel Dörfler		// just take any mode
521e146dee3SAxel Dörfler		standardMode = (video_mode *)list_get_first_item(&sModeList);
522e146dee3SAxel Dörfler	}
523652c8526SAxel Dörfler
524f42302bcSAxel Dörfler	if (standardMode == NULL) {
525f42302bcSAxel Dörfler		// no usable VESA mode found...
526f42302bcSAxel Dörfler		return B_ERROR;
527f42302bcSAxel Dörfler	}
528f42302bcSAxel Dörfler
529746efef3SFrançois Revol	TRACE(("Using mode 0x%03x\n", standardMode->mode));
530f42302bcSAxel Dörfler	*_standardMode = standardMode;
531f42302bcSAxel Dörfler	return B_OK;
532eefe4b1dSAxel Dörfler}
533eefe4b1dSAxel Dörfler
534eefe4b1dSAxel Dörfler
535eefe4b1dSAxel Dörfler#if 0
536eefe4b1dSAxel Dörflerstatic status_t
537eefe4b1dSAxel Dörflervesa_get_mode(uint16 *_mode)
538eefe4b1dSAxel Dörfler{
539eefe4b1dSAxel Dörfler	struct bios_regs regs;
540eefe4b1dSAxel Dörfler	regs.eax = 0x4f03;
541eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
542eefe4b1dSAxel Dörfler
543eefe4b1dSAxel Dörfler	if ((regs.eax & 0xffff) != 0x4f)
544eefe4b1dSAxel Dörfler		return B_ERROR;
545eefe4b1dSAxel Dörfler
546eefe4b1dSAxel Dörfler	*_mode = regs.ebx & 0xffff;
547eefe4b1dSAxel Dörfler	return B_OK;
548eefe4b1dSAxel Dörfler}
549eefe4b1dSAxel Dörfler#endif
550eefe4b1dSAxel Dörfler
551eefe4b1dSAxel Dörfler
552eefe4b1dSAxel Dörflerstatic status_t
55339c7faa4SAxel Dörflervesa_set_mode(video_mode* mode, bool useTiming)
554eefe4b1dSAxel Dörfler{
555eefe4b1dSAxel Dörfler	struct bios_regs regs;
556eefe4b1dSAxel Dörfler	regs.eax = 0x4f02;
557b4c8ccc3SAxel Dörfler	regs.ebx = (mode->mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER;
558b4c8ccc3SAxel Dörfler
55939c7faa4SAxel Dörfler	if (useTiming && mode->timing != NULL) {
560b4c8ccc3SAxel Dörfler		regs.ebx |= SET_MODE_SPECIFY_CRTC;
561b4c8ccc3SAxel Dörfler = ADDRESS_SEGMENT(mode->timing);
562b4c8ccc3SAxel Dörfler		regs.edi = ADDRESS_OFFSET(mode->timing);
563b4c8ccc3SAxel Dörfler	}
564b4c8ccc3SAxel Dörfler
565eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
566eefe4b1dSAxel Dörfler
567eefe4b1dSAxel Dörfler	if ((regs.eax & 0xffff) != 0x4f)
568eefe4b1dSAxel Dörfler		return B_ERROR;
569eefe4b1dSAxel Dörfler
570eefe4b1dSAxel Dörfler#if 0
571eefe4b1dSAxel Dörfler	// make sure we have 8 bits per color channel
572eefe4b1dSAxel Dörfler	regs.eax = 0x4f08;
573eefe4b1dSAxel Dörfler	regs.ebx = 8 << 8;
574eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
575eefe4b1dSAxel Dörfler#endif
576eefe4b1dSAxel Dörfler
577eefe4b1dSAxel Dörfler	return B_OK;
578eefe4b1dSAxel Dörfler}
579eefe4b1dSAxel Dörfler
580eefe4b1dSAxel Dörfler
581eefe4b1dSAxel Dörflerstatic status_t
582eefe4b1dSAxel Dörflervesa_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries)
583eefe4b1dSAxel Dörfler{
584eefe4b1dSAxel Dörfler	// is this an 8 bit indexed color mode?
5858c3e1399SAxel Dörfler	if (gKernelArgs.frame_buffer.depth != 8)
586eefe4b1dSAxel Dörfler		return B_BAD_TYPE;
5878c3e1399SAxel Dörfler
58892e0317cSAxel Dörfler#if 0
589eefe4b1dSAxel Dörfler	struct bios_regs regs;
590eefe4b1dSAxel Dörfler	regs.eax = 0x4f09;
591eefe4b1dSAxel Dörfler	regs.ebx = 0;
592eefe4b1dSAxel Dörfler	regs.ecx = numEntries;
593eefe4b1dSAxel Dörfler	regs.edx = firstIndex;
594eefe4b1dSAxel Dörfler = (addr_t)palette >> 4;
595eefe4b1dSAxel Dörfler	regs.edi = (addr_t)palette & 0xf;
596eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
597eefe4b1dSAxel Dörfler
598eefe4b1dSAxel Dörfler	if ((regs.eax & 0xffff) != 0x4f) {
59992e0317cSAxel Dörfler#endif
600eefe4b1dSAxel Dörfler		// the VESA call does not work, just try good old VGA mechanism
601eefe4b1dSAxel Dörfler		vga_set_palette(palette, firstIndex, numEntries);
60292e0317cSAxel Dörfler#if 0
603eefe4b1dSAxel Dörfler		return B_ERROR;
604eefe4b1dSAxel Dörfler	}
60592e0317cSAxel Dörfler#endif
606eefe4b1dSAxel Dörfler	return B_OK;
607eefe4b1dSAxel Dörfler}
608eefe4b1dSAxel Dörfler
609eefe4b1dSAxel Dörfler
610eefe4b1dSAxel Dörfler//	#pragma mark -
611eefe4b1dSAxel Dörfler
612eefe4b1dSAxel Dörfler
613a104674fSAxel Dörflerbool
614a104674fSAxel Dörflervideo_mode_hook(Menu *menu, MenuItem *item)
615a104674fSAxel Dörfler{
616a104674fSAxel Dörfler	// find selected mode
617a104674fSAxel Dörfler	video_mode *mode = NULL;
618a104674fSAxel Dörfler
619a104674fSAxel Dörfler	menu = item->Submenu();
620a104674fSAxel Dörfler	item = menu->FindMarked();
621d3ff9cc3SAxel Dörfler	if (item != NULL) {
622d3ff9cc3SAxel Dörfler		switch (menu->IndexOf(item)) {
623d3ff9cc3SAxel Dörfler			case 0:
624d3ff9cc3SAxel Dörfler				// "Default" mode special
625d3ff9cc3SAxel Dörfler				sMode = sDefaultMode;
626d3ff9cc3SAxel Dörfler				sModeChosen = false;
627d3ff9cc3SAxel Dörfler				return true;
628d3ff9cc3SAxel Dörfler			case 1:
629d3ff9cc3SAxel Dörfler				// "Standard VGA" mode special
630d3ff9cc3SAxel Dörfler				// sets sMode to NULL which triggers VGA mode
631d3ff9cc3SAxel Dörfler				break;
632d3ff9cc3SAxel Dörfler			default:
633d3ff9cc3SAxel Dörfler				mode = (video_mode *)item->Data();
634d3ff9cc3SAxel Dörfler				break;
635d3ff9cc3SAxel Dörfler		}
636d3ff9cc3SAxel Dörfler	}
637a104674fSAxel Dörfler
638a104674fSAxel Dörfler	if (mode != sMode) {
639a104674fSAxel Dörfler		// update standard mode
640a104674fSAxel Dörfler		// ToDo: update fb settings!
641a104674fSAxel Dörfler		sMode = mode;
642a104674fSAxel Dörfler	}
643a104674fSAxel Dörfler
644486c7eddSAxel Dörfler	sModeChosen = true;
645a104674fSAxel Dörfler	return true;
646a104674fSAxel Dörfler}
647a104674fSAxel Dörfler
648a104674fSAxel Dörfler
649a104674fSAxel DörflerMenu *
650a104674fSAxel Dörflervideo_mode_menu()
651a104674fSAxel Dörfler{
65282029bdaSMarcus Overhagen	Menu *menu = new(nothrow) Menu(CHOICE_MENU, "Select Video Mode");
653a104674fSAxel Dörfler	MenuItem *item;
654a104674fSAxel Dörfler
65582029bdaSMarcus Overhagen	menu->AddItem(item = new(nothrow) MenuItem("Default"));
656a104674fSAxel Dörfler	item->SetMarked(true);
657a104674fSAxel Dörfler	item->Select(true);
6589b13056bSAxel Dörfler	item->SetHelpText("The Default video mode is the one currently configured "
6599b13056bSAxel Dörfler		"in the system. If there is no mode configured yet, a viable mode will "
6609b13056bSAxel Dörfler		"be chosen automatically.");
661a104674fSAxel Dörfler
66282029bdaSMarcus Overhagen	menu->AddItem(new(nothrow) MenuItem("Standard VGA"));
663a104674fSAxel Dörfler
664a104674fSAxel Dörfler	video_mode *mode = NULL;
665a104674fSAxel Dörfler	while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) != NULL) {
666a104674fSAxel Dörfler		char label[64];
667b51ec9deSIngo Weinhold		snprintf(label, sizeof(label), "%ux%u %u bit", mode->width,
668b51ec9deSIngo Weinhold			mode->height, mode->bits_per_pixel);
669a104674fSAxel Dörfler
67082029bdaSMarcus Overhagen		menu->AddItem(item = new(nothrow) MenuItem(label));
671a104674fSAxel Dörfler		item->SetData(mode);
672a104674fSAxel Dörfler	}
673a104674fSAxel Dörfler
674a104674fSAxel Dörfler	menu->AddSeparatorItem();
67582029bdaSMarcus Overhagen	menu->AddItem(item = new(nothrow) MenuItem("Return to main menu"));
676a104674fSAxel Dörfler	item->SetType(MENU_ITEM_NO_CHOICE);
677a104674fSAxel Dörfler
678a104674fSAxel Dörfler	return menu;
679a104674fSAxel Dörfler}
680a104674fSAxel Dörfler
681a104674fSAxel Dörfler
682d3ff9cc3SAxel Dörflerstatic void
683d3ff9cc3SAxel Dörflerset_vga_mode(void)
684d3ff9cc3SAxel Dörfler{
685d3ff9cc3SAxel Dörfler	// sets 640x480 16 colors graphics mode
686d3ff9cc3SAxel Dörfler	bios_regs regs;
687119b7dccSAxel Dörfler	regs.eax = 0x0012;
688d3ff9cc3SAxel Dörfler	call_bios(0x10, &regs);
689d3ff9cc3SAxel Dörfler}
690d3ff9cc3SAxel Dörfler
691d3ff9cc3SAxel Dörfler
692133c5b73SAxel Dörflerstatic void
693133c5b73SAxel Dörflerset_text_mode(void)
694133c5b73SAxel Dörfler{
695d3ff9cc3SAxel Dörfler	// sets 80x25 text console
696133c5b73SAxel Dörfler	bios_regs regs;
697119b7dccSAxel Dörfler	regs.eax = 0x0003;
698119b7dccSAxel Dörfler	call_bios(0x10, &regs);
699119b7dccSAxel Dörfler
700d2b49a00SRene Gollent	video_hide_text_cursor();
701d2b49a00SRene Gollent}
702d2b49a00SRene Gollent
703d2b49a00SRene Gollent
704d2b49a00SRene Gollentvoid
705d2b49a00SRene Gollentvideo_move_text_cursor(int x, int y)
706d2b49a00SRene Gollent{
707d2b49a00SRene Gollent	bios_regs regs;
708d2b49a00SRene Gollent	regs.eax = 0x0200;
709d2b49a00SRene Gollent	regs.ebx = 0;
710d2b49a00SRene Gollent	regs.edx = (y << 8) | x;
711d2b49a00SRene Gollent	call_bios(0x10, &regs);
712d2b49a00SRene Gollent}
713d2b49a00SRene Gollent
714d2b49a00SRene Gollent
715d2b49a00SRene Gollentvoid
716d2b49a00SRene Gollentvideo_show_text_cursor(void)
717d2b49a00SRene Gollent{
718d2b49a00SRene Gollent	bios_regs regs;
719d2b49a00SRene Gollent	regs.eax = 0x0100;
720d2b49a00SRene Gollent	regs.ecx = 0x0607;
721d2b49a00SRene Gollent	call_bios(0x10, &regs);
722d2b49a00SRene Gollent}
723d2b49a00SRene Gollent
724d2b49a00SRene Gollent
725d2b49a00SRene Gollentvoid
726d2b49a00SRene Gollentvideo_hide_text_cursor(void)
727d2b49a00SRene Gollent{
728d2b49a00SRene Gollent	bios_regs regs;
729119b7dccSAxel Dörfler	regs.eax = 0x0100;
730119b7dccSAxel Dörfler	regs.ecx = 0x2000;
731133c5b73SAxel Dörfler	call_bios(0x10, &regs);
732133c5b73SAxel Dörfler}
733133c5b73SAxel Dörfler
734133c5b73SAxel Dörfler
7358bd36612SAxel Dörfler//	#pragma mark - blit
7368bd36612SAxel Dörfler
7378bd36612SAxel Dörfler
7380573d397SFrançois Revolvoid
7397db9fbfeSFrançois Revolplatform_blit4(addr_t frameBuffer, const uint8 *data,
7400573d397SFrançois Revol	uint16 width, uint16 height, uint16 imageWidth, uint16 left, uint16 top)
7418bd36612SAxel Dörfler{
7420573d397SFrançois Revol	if (!data)
74355ef60a5SStephan Aßmus		return;
7448bd36612SAxel Dörfler	// ToDo: no boot logo yet in VGA mode
7458bd36612SAxel Dörfler#if 1
7468bd36612SAxel Dörfler// this draws 16 big rectangles in all the available colors
7477db9fbfeSFrançois Revol	uint8 *bits = (uint8 *)frameBuffer;
7487db9fbfeSFrançois Revol	uint32 bytesPerRow = 80;
7498bd36612SAxel Dörfler	for (int32 i = 0; i < 32; i++) {
7508bd36612SAxel Dörfler		bits[9 * bytesPerRow + i + 2] = 0x55;
7518bd36612SAxel Dörfler		bits[30 * bytesPerRow + i + 2] = 0xaa;
7528bd36612SAxel Dörfler	}
7538bd36612SAxel Dörfler
7548bd36612SAxel Dörfler	for (int32 y = 10; y < 30; y++) {
7558bd36612SAxel Dörfler		for (int32 i = 0; i < 16; i++) {
7568bd36612SAxel Dörfler			out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX);
7578bd36612SAxel Dörfler			bits[32 * bytesPerRow + i*2 + 2] = i;
7588bd36612SAxel Dörfler
7598bd36612SAxel Dörfler			if (i & 1) {
7608bd36612SAxel Dörfler				out16((1 << 8) | 0x02, VGA_SEQUENCER_INDEX);
7618bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 2] = 0xff;
7628bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 3] = 0xff;
7638bd36612SAxel Dörfler			}
7648bd36612SAxel Dörfler			if (i & 2) {
7658bd36612SAxel Dörfler				out16((2 << 8) | 0x02, VGA_SEQUENCER_INDEX);
7668bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 2] = 0xff;
7678bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 3] = 0xff;
7688bd36612SAxel Dörfler			}
7698bd36612SAxel Dörfler			if (i & 4) {
7708bd36612SAxel Dörfler				out16((4 << 8) | 0x02, VGA_SEQUENCER_INDEX);
7718bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 2] = 0xff;
7728bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 3] = 0xff;
7738bd36612SAxel Dörfler			}
7748bd36612SAxel Dörfler			if (i & 8) {
7758bd36612SAxel Dörfler				out16((8 << 8) | 0x02, VGA_SEQUENCER_INDEX);
7768bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 2] = 0xff;
7778bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 3] = 0xff;
7788bd36612SAxel Dörfler			}
7798bd36612SAxel Dörfler		}
7808bd36612SAxel Dörfler	}
7818bd36612SAxel Dörfler
7828bd36612SAxel Dörfler	// enable all planes again
7838bd36612SAxel Dörfler	out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX);
7848bd36612SAxel Dörfler#endif
7858bd36612SAxel Dörfler}
7868bd36612SAxel Dörfler
7878bd36612SAxel Dörfler
7887db9fbfeSFrançois Revolextern "C" void
7897db9fbfeSFrançois Revolplatform_set_palette(const uint8 *palette)
7908bd36612SAxel Dörfler{
7918bd36612SAxel Dörfler	switch (gKernelArgs.frame_buffer.depth) {
7928bd36612SAxel Dörfler		case 4:
7930573d397SFrançois Revol			//vga_set_palette((const uint8 *)kPalette16, 0, 16);
7940573d397SFrançois Revol			break;
7958bd36612SAxel Dörfler		case 8:
7960573d397SFrançois Revol			if (vesa_set_palette((const uint8 *)palette, 0, 256) != B_OK)
7970573d397SFrançois Revol				dprintf("set palette failed!\n");
798d0fc7c65SStephan Aßmus
7990573d397SFrançois Revol			break;
8000573d397SFrançois Revol		default:
8010573d397SFrançois Revol			break;
802ec56835fSStephan Aßmus	}
803ec56835fSStephan Aßmus}
804ec56835fSStephan Aßmus
805ec56835fSStephan Aßmus
806aa727f66SStephan Aßmus//	#pragma mark -
807a104674fSAxel Dörfler
808eefe4b1dSAxel Dörflerextern "C" void
809eefe4b1dSAxel Dörflerplatform_switch_to_logo(void)
810eefe4b1dSAxel Dörfler{
811a7fb02e6SAxel Dörfler	// in debug mode, we'll never show the logo
812a7fb02e6SAxel Dörfler	if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0)
813a7fb02e6SAxel Dörfler		return;
814a7fb02e6SAxel Dörfler
815d3ff9cc3SAxel Dörfler	addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start;
816d3ff9cc3SAxel Dörfler	size_t lastSize = gKernelArgs.frame_buffer.physical_buffer.size;
817eefe4b1dSAxel Dörfler
818d3ff9cc3SAxel Dörfler	if (sVesaCompatible && sMode != NULL) {
819d3ff9cc3SAxel Dörfler		if (!sModeChosen)
820d3ff9cc3SAxel Dörfler			get_mode_from_settings();
82185f02010SStephan Aßmus
82239c7faa4SAxel Dörfler		// On some BIOS / chipset / monitor combinations, there seems to be a
82339c7faa4SAxel Dörfler		// timing issue between getting the EDID data and setting the video
82439c7faa4SAxel Dörfler		// mode. As such we wait here briefly to give everything enough time
82539c7faa4SAxel Dörfler		// to settle.
8260d69c837SRene Gollent		spin(1000);
82739c7faa4SAxel Dörfler
82839c7faa4SAxel Dörfler		if ((sMode->timing == NULL || vesa_set_mode(sMode, true) != B_OK)
82939c7faa4SAxel Dörfler			&& vesa_set_mode(sMode, false) != B_OK)
830d3ff9cc3SAxel Dörfler			goto fallback;
831d3ff9cc3SAxel Dörfler
832d3ff9cc3SAxel Dörfler		struct vbe_mode_info modeInfo;
833d3ff9cc3SAxel Dörfler		if (vesa_get_mode_info(sMode->mode, &modeInfo) != B_OK)
834d3ff9cc3SAxel Dörfler			goto fallback;
835d3ff9cc3SAxel Dörfler
836d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.width = modeInfo.width;
837d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.height = modeInfo.height;
8385845b6ecSAxel Dörfler		gKernelArgs.frame_buffer.bytes_per_row = modeInfo.bytes_per_row;
839d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.depth = modeInfo.bits_per_pixel;
8403872a2d2SIngo Weinhold		gKernelArgs.frame_buffer.physical_buffer.size
8413872a2d2SIngo Weinhold			= (phys_size_t)modeInfo.bytes_per_row
8423872a2d2SIngo Weinhold				* (phys_size_t)gKernelArgs.frame_buffer.height;
843d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.physical_buffer.start = modeInfo.physical_base;
844d3ff9cc3SAxel Dörfler	} else {
845d3ff9cc3SAxel Dörflerfallback:
846d3ff9cc3SAxel Dörfler		// use standard VGA mode 640x480x4
847d3ff9cc3SAxel Dörfler		set_vga_mode();
848d3ff9cc3SAxel Dörfler
849d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.width = 640;
850d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.height = 480;
85113247f3aSAxel Dörfler		gKernelArgs.frame_buffer.bytes_per_row = 80;
852d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.depth = 4;
8539b13056bSAxel Dörfler		gKernelArgs.frame_buffer.physical_buffer.size
8543872a2d2SIngo Weinhold			= (phys_size_t)gKernelArgs.frame_buffer.width
8553872a2d2SIngo Weinhold				* (phys_size_t)gKernelArgs.frame_buffer.height / 2;
856d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.physical_buffer.start = 0xa0000;
857d3ff9cc3SAxel Dörfler	}
858eefe4b1dSAxel Dörfler
8599b13056bSAxel Dörfler	dprintf("video mode: %ux%ux%u\n", gKernelArgs.frame_buffer.width,
8609b13056bSAxel Dörfler		gKernelArgs.frame_buffer.height, gKernelArgs.frame_buffer.depth);
8619b13056bSAxel Dörfler
8625845b6ecSAxel Dörfler	gKernelArgs.frame_buffer.enabled = true;
863eefe4b1dSAxel Dörfler
864d3ff9cc3SAxel Dörfler	// If the new frame buffer is either larger than the old one or located at
865d3ff9cc3SAxel Dörfler	// a different address, we need to remap it, so we first have to throw
866d3ff9cc3SAxel Dörfler	// away its previous mapping
867d3ff9cc3SAxel Dörfler	if (lastBase != 0
868d3ff9cc3SAxel Dörfler		&& (lastBase != gKernelArgs.frame_buffer.physical_buffer.start
869d3ff9cc3SAxel Dörfler			|| lastSize < gKernelArgs.frame_buffer.physical_buffer.size)) {
870d3ff9cc3SAxel Dörfler		mmu_free((void *)sFrameBuffer, lastSize);
871d3ff9cc3SAxel Dörfler		lastBase = 0;
872a7fb02e6SAxel Dörfler	}
873a7fb02e6SAxel Dörfler	if (lastBase == 0) {
874eefe4b1dSAxel Dörfler		// the graphics memory has not been mapped yet!
8755845b6ecSAxel Dörfler		sFrameBuffer = mmu_map_physical_memory(
8765845b6ecSAxel Dörfler			gKernelArgs.frame_buffer.physical_buffer.start,
8775845b6ecSAxel Dörfler			gKernelArgs.frame_buffer.physical_buffer.size, kDefaultPageFlags);
878eefe4b1dSAxel Dörfler	}
879eefe4b1dSAxel Dörfler
8807db9fbfeSFrançois Revol	video_display_splash(sFrameBuffer);
881eefe4b1dSAxel Dörfler}
882eefe4b1dSAxel Dörfler
883eefe4b1dSAxel Dörfler
884eefe4b1dSAxel Dörflerextern "C" void
885eefe4b1dSAxel Dörflerplatform_switch_to_text_mode(void)
886eefe4b1dSAxel Dörfler{
8878c3e1399SAxel Dörfler	if (!gKernelArgs.frame_buffer.enabled) {
8888c3e1399SAxel Dörfler		vga_enable_bright_background_colors();
889eefe4b1dSAxel Dörfler		return;
8908c3e1399SAxel Dörfler	}
891eefe4b1dSAxel Dörfler
892133c5b73SAxel Dörfler	set_text_mode();
893a3a08080SAxel Dörfler	gKernelArgs.frame_buffer.enabled = 0;
8948c3e1399SAxel Dörfler
8958c3e1399SAxel Dörfler	vga_enable_bright_background_colors();
896eefe4b1dSAxel Dörfler}
897eefe4b1dSAxel Dörfler
898eefe4b1dSAxel Dörfler
8995973fcdfSStephan Aßmusextern "C" status_t
900f42302bcSAxel Dörflerplatform_init_video(void)
901eefe4b1dSAxel Dörfler{
902a3a08080SAxel Dörfler	gKernelArgs.frame_buffer.enabled = 0;
903f42302bcSAxel Dörfler	list_init(&sModeList);
904eefe4b1dSAxel Dörfler
905133c5b73SAxel Dörfler	set_text_mode();
906133c5b73SAxel Dörfler		// You may wonder why we do this here:
907133c5b73SAxel Dörfler		// Obviously, some graphics card BIOS implementations don't
908133c5b73SAxel Dörfler		// report all available modes unless you've done this before
909133c5b73SAxel Dörfler		// getting the VESA information.
910d3ff9cc3SAxel Dörfler		// One example of those is the SiS 630 chipset in my laptop.
911133c5b73SAxel Dörfler
912d3ff9cc3SAxel Dörfler	sVesaCompatible = vesa_init(&sInfo, &sDefaultMode) == B_OK;
913eefe4b1dSAxel Dörfler	if (!sVesaCompatible) {
914b1cd9d2dSAxel Dörfler		TRACE(("No VESA compatible graphics!\n"));
91555be2751SAxel Dörfler		gKernelArgs.vesa_capabilities = 0;
916eefe4b1dSAxel Dörfler		return B_ERROR;
917eefe4b1dSAxel Dörfler	}
918eefe4b1dSAxel Dörfler
919bb693d77SAxel Dörfler	gKernelArgs.vesa_capabilities = sInfo.capabilities;
920bb693d77SAxel Dörfler
921b1cd9d2dSAxel Dörfler	TRACE(("VESA compatible graphics!\n"));
922b1cd9d2dSAxel Dörfler
9236328832fSAxel Dörfler	// store VESA modes into kernel args
9246328832fSAxel Dörfler	vesa_mode *modes = (vesa_mode *)kernel_args_malloc(
9256328832fSAxel Dörfler		sModeCount * sizeof(vesa_mode));
9266328832fSAxel Dörfler	if (modes != NULL) {
9276328832fSAxel Dörfler		video_mode *mode = NULL;
9286328832fSAxel Dörfler		uint32 i = 0;
9296328832fSAxel Dörfler		while ((mode = (video_mode *)list_get_next_item(&sModeList, mode))
9306328832fSAxel Dörfler				!= NULL) {
9319f161845SAxel Dörfler			modes[i].mode = mode->mode;
9326328832fSAxel Dörfler			modes[i].width = mode->width;
9336328832fSAxel Dörfler			modes[i].height = mode->height;
9346328832fSAxel Dörfler			modes[i].bits_per_pixel = mode->bits_per_pixel;
9356328832fSAxel Dörfler			i++;
9366328832fSAxel Dörfler		}
9376328832fSAxel Dörfler