1eefe4b1dSAxel Dörfler/*
213247f3aSAxel Dörfler * Copyright 2004-2009, Axel D��rfler, axeld@pinc-software.de.
3636bff2fSStephan Aßmus * Copyright 2008, Stephan A��mus <superstippi@gmx.de>
4636bff2fSStephan Aßmus * Copyright 2008, Philippe Saint-Pierre <stpere@gmail.com>
5d2b49a00SRene Gollent * Copyright 2011, Rene Gollent, rene@gollent.com.
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(monitor.data.detailed_timing.h_active,
222cedc3f1eSAxel Dörfler				monitor.data.detailed_timing.v_active, allowPalette);
223b4c8ccc3SAxel Dörfler			if (mode != NULL) {
224b4c8ccc3SAxel Dörfler				mode->timing
225b4c8ccc3SAxel Dörfler					= get_crtc_info_block(monitor.data.detailed_timing);
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
26125de7c1bSFrançois Revolstatic void
26225de7c1bSFrançois Revolvesa_fixups(void *settings)
26325de7c1bSFrançois Revol{
26425de7c1bSFrançois Revol	const char *oem_string = (const char *)sInfo.oem_string;
26525de7c1bSFrançois Revol
26625de7c1bSFrançois Revol	if (!strcmp(oem_string, "NVIDIA")) {
26725de7c1bSFrançois Revol		const char *arg = NULL;
26825de7c1bSFrançois Revol		int32 scaling = -1;
26925de7c1bSFrançois Revol
27025de7c1bSFrançois Revol		if (settings != NULL)
27125de7c1bSFrançois Revol			arg = get_driver_parameter(settings, "nvidia_scaling", NULL, "1");
27225de7c1bSFrançois Revol		if (arg != NULL)
27325de7c1bSFrançois Revol			scaling = strtol(arg, NULL, 0);
27425de7c1bSFrançois Revol
27525de7c1bSFrançois Revol		if (scaling > -1) {
27625de7c1bSFrançois Revol			dprintf("Setting nvidia scaling mode to %" B_PRId32 "\n", scaling);
27725de7c1bSFrançois Revol			struct bios_regs regs;
27825de7c1bSFrançois Revol			regs.eax = 0x4f14;
27925de7c1bSFrançois Revol			regs.ebx = 0x0102;
28025de7c1bSFrançois Revol			regs.ecx = scaling;
28125de7c1bSFrançois Revol			call_bios(0x10, &regs);
28225de7c1bSFrançois Revol		}
28325de7c1bSFrançois Revol	}
28425de7c1bSFrançois Revol
28525de7c1bSFrançois Revol}
28625de7c1bSFrançois Revol
28725de7c1bSFrançois Revol
2885d7d960fSAxel Dörflerstatic bool
289d5062208SAxel Dörflerget_mode_from_settings(void)
290d5062208SAxel Dörfler{
291d5062208SAxel Dörfler	if (sSettingsLoaded)
2925d7d960fSAxel Dörfler		return true;
293d5062208SAxel Dörfler
294d5062208SAxel Dörfler	void *handle = load_driver_settings("vesa");
295d5062208SAxel Dörfler	if (handle == NULL)
2965d7d960fSAxel Dörfler		return false;
2975d7d960fSAxel Dörfler
29825de7c1bSFrançois Revol	vesa_fixups(handle);
29925de7c1bSFrançois Revol
3005d7d960fSAxel Dörfler	bool found = false;
301d5062208SAxel Dörfler
302d5062208SAxel Dörfler	const driver_settings *settings = get_driver_settings(handle);
303d5062208SAxel Dörfler	if (settings == NULL)
304d5062208SAxel Dörfler		goto out;
305d5062208SAxel Dörfler
306d5062208SAxel Dörfler	sSettingsLoaded = true;
307d5062208SAxel Dörfler
308d5062208SAxel Dörfler	for (int32 i = 0; i < settings->parameter_count; i++) {
309d5062208SAxel Dörfler		driver_parameter &parameter = settings->parameters[i];
310d5062208SAxel Dörfler
311d5062208SAxel Dörfler		if (!strcmp(parameter.name, "mode") && parameter.value_count > 2) {
312d5062208SAxel Dörfler			// parameter found, now get its values
313d5062208SAxel Dörfler			int32 width = strtol(parameter.values[0], NULL, 0);
314d5062208SAxel Dörfler			int32 height = strtol(parameter.values[1], NULL, 0);
315d5062208SAxel Dörfler			int32 depth = strtol(parameter.values[2], NULL, 0);
316d5062208SAxel Dörfler
317d5062208SAxel Dörfler			// search mode that fits
318d5062208SAxel Dörfler
3196328832fSAxel Dörfler			video_mode *mode = closest_video_mode(width, height, depth);
3205d7d960fSAxel Dörfler			if (mode != NULL) {
3215d7d960fSAxel Dörfler				found = true;
322d5062208SAxel Dörfler				sMode = mode;
3235d7d960fSAxel Dörfler			}
324d5062208SAxel Dörfler		}
325d5062208SAxel Dörfler	}
326d5062208SAxel Dörfler
327d5062208SAxel Dörflerout:
328d5062208SAxel Dörfler	unload_driver_settings(handle);
3295d7d960fSAxel Dörfler	return found;
330d5062208SAxel Dörfler}
331d5062208SAxel Dörfler
332d5062208SAxel Dörfler
333d5062208SAxel Dörfler//	#pragma mark - vga
334d5062208SAxel Dörfler
335d5062208SAxel Dörfler
336eefe4b1dSAxel Dörflerstatic void
337eefe4b1dSAxel Dörflervga_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries)
338eefe4b1dSAxel Dörfler{
339d3ff9cc3SAxel Dörfler	out8(firstIndex, VGA_COLOR_WRITE_MODE);
340eefe4b1dSAxel Dörfler	// write VGA palette
341eefe4b1dSAxel Dörfler	for (int32 i = firstIndex; i < numEntries; i++) {
342eefe4b1dSAxel Dörfler		// VGA (usually) has only 6 bits per gun
343d3ff9cc3SAxel Dörfler		out8(palette[i * 3 + 0] >> 2, VGA_COLOR_DATA);
344d3ff9cc3SAxel Dörfler		out8(palette[i * 3 + 1] >> 2, VGA_COLOR_DATA);
345d3ff9cc3SAxel Dörfler		out8(palette[i * 3 + 2] >> 2, VGA_COLOR_DATA);
346eefe4b1dSAxel Dörfler	}
347eefe4b1dSAxel Dörfler}
348eefe4b1dSAxel Dörfler
349eefe4b1dSAxel Dörfler
3508c3e1399SAxel Dörflerstatic void
3518c3e1399SAxel Dörflervga_enable_bright_background_colors(void)
3528c3e1399SAxel Dörfler{
3538c3e1399SAxel Dörfler	// reset attribute controller
354d3ff9cc3SAxel Dörfler	in8(VGA_INPUT_STATUS_1);
3558c3e1399SAxel Dörfler
3568c3e1399SAxel Dörfler	// select mode control register
357d3ff9cc3SAxel Dörfler	out8(0x30, VGA_ATTRIBUTE_WRITE);
3588c3e1399SAxel Dörfler
3598c3e1399SAxel Dörfler	// read mode control register, change it (we need to clear bit 3), and write it back
360d3ff9cc3SAxel Dörfler	uint8 mode = in8(VGA_ATTRIBUTE_READ) & 0xf7;
361d3ff9cc3SAxel Dörfler	out8(mode, VGA_ATTRIBUTE_WRITE);
3628c3e1399SAxel Dörfler}
3638c3e1399SAxel Dörfler
3648c3e1399SAxel Dörfler
3658cd812c1SAxel Dörfler//	#pragma mark - vesa
366eefe4b1dSAxel Dörfler
367eefe4b1dSAxel Dörfler
3685d7d960fSAxel Dörflerstatic status_t
3695d7d960fSAxel Dörflervesa_get_edid(edid1_info *info)
3705d7d960fSAxel Dörfler{
3715d7d960fSAxel Dörfler	struct bios_regs regs;
3725d7d960fSAxel Dörfler	regs.eax = 0x4f15;
3735d7d960fSAxel Dörfler	regs.ebx = 0;
3745d7d960fSAxel Dörfler		// report DDC service
3755d7d960fSAxel Dörfler	regs.ecx = 0;
3765d7d960fSAxel Dörfler	regs.es = 0;
3775d7d960fSAxel Dörfler	regs.edi = 0;
3785d7d960fSAxel Dörfler	call_bios(0x10, &regs);
3795d7d960fSAxel Dörfler
38060642f87SAxel Dörfler	TRACE(("EDID1: %lx\n", regs.eax));
3815d7d960fSAxel Dörfler	// %ah contains the error code
3820e35d5d2SJohn Scipione	// %al determines whether or not the function is supported
383d6edf65bSAxel Dörfler	if (regs.eax != 0x4f)
3845d7d960fSAxel Dörfler		return B_NOT_SUPPORTED;
3855d7d960fSAxel Dörfler
38660642f87SAxel Dörfler	TRACE(("EDID2: ebx %lx\n", regs.ebx));
387d6edf65bSAxel Dörfler	// test if DDC is supported by the monitor
388d6edf65bSAxel Dörfler	if ((regs.ebx & 3) == 0)
3895d7d960fSAxel Dörfler		return B_NOT_SUPPORTED;
3905d7d960fSAxel Dörfler
3915d7d960fSAxel Dörfler	edid1_raw edidRaw;
3925d7d960fSAxel Dörfler
3935d7d960fSAxel Dörfler	regs.eax = 0x4f15;
3945d7d960fSAxel Dörfler	regs.ebx = 1;
3955d7d960fSAxel Dörfler		// read EDID
3965d7d960fSAxel Dörfler	regs.ecx = 0;
3975d7d960fSAxel Dörfler	regs.edx = 0;
3985d7d960fSAxel Dörfler	regs.es = ADDRESS_SEGMENT(&edidRaw);
3995d7d960fSAxel Dörfler	regs.edi = ADDRESS_OFFSET(&edidRaw);
4005d7d960fSAxel Dörfler	call_bios(0x10, &regs);
40160642f87SAxel Dörfler	TRACE(("EDID3: %lx\n", regs.eax));
4025d7d960fSAxel Dörfler
403d6edf65bSAxel Dörfler	if (regs.eax != 0x4f)
4045d7d960fSAxel Dörfler		return B_NOT_SUPPORTED;
4055d7d960fSAxel Dörfler
4065d7d960fSAxel Dörfler	// retrieved EDID - now parse it
4075d7d960fSAxel Dörfler	edid_decode(info, &edidRaw);
40860642f87SAxel Dörfler
40960642f87SAxel Dörfler#ifdef TRACE_VIDEO
4105d7d960fSAxel Dörfler	edid_dump(info);
41160642f87SAxel Dörfler#endif
4125d7d960fSAxel Dörfler	return B_OK;
4135d7d960fSAxel Dörfler}
4145d7d960fSAxel Dörfler
4155d7d960fSAxel Dörfler
416eefe4b1dSAxel Dörflerstatic status_t
417eefe4b1dSAxel Dörflervesa_get_mode_info(uint16 mode, struct vbe_mode_info *modeInfo)
418eefe4b1dSAxel Dörfler{
419133c5b73SAxel Dörfler	memset(modeInfo, 0, sizeof(vbe_mode_info));
420133c5b73SAxel Dörfler
421eefe4b1dSAxel Dörfler	struct bios_regs regs;
422eefe4b1dSAxel Dörfler	regs.eax = 0x4f01;
423eefe4b1dSAxel Dörfler	regs.ecx = mode;
4244c179368SAxel Dörfler	regs.es = ADDRESS_SEGMENT(modeInfo);
4254c179368SAxel Dörfler	regs.edi = ADDRESS_OFFSET(modeInfo);
426eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
427eefe4b1dSAxel Dörfler
428133c5b73SAxel Dörfler	// %ah contains the error code
429133c5b73SAxel Dörfler	if ((regs.eax & 0xff00) != 0)
430eefe4b1dSAxel Dörfler		return B_ENTRY_NOT_FOUND;
431eefe4b1dSAxel Dörfler
432eefe4b1dSAxel Dörfler	return B_OK;
433eefe4b1dSAxel Dörfler}
434eefe4b1dSAxel Dörfler
435eefe4b1dSAxel Dörfler
436eefe4b1dSAxel Dörflerstatic status_t
437ce5cf7b3SAxel Dörflervesa_get_vbe_info_block(vbe_info_block *info)
438eefe4b1dSAxel Dörfler{
439eefe4b1dSAxel Dörfler	memset(info, 0, sizeof(vbe_info_block));
440eefe4b1dSAxel Dörfler	info->signature = VBE2_SIGNATURE;
441eefe4b1dSAxel Dörfler
442eefe4b1dSAxel Dörfler	struct bios_regs regs;
443eefe4b1dSAxel Dörfler	regs.eax = 0x4f00;
444ce5cf7b3SAxel Dörfler	regs.es = ADDRESS_SEGMENT(info);
445ce5cf7b3SAxel Dörfler	regs.edi = ADDRESS_OFFSET(info);
446eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
447eefe4b1dSAxel Dörfler
448133c5b73SAxel Dörfler	// %ah contains the error code
449133c5b73SAxel Dörfler	if ((regs.eax & 0xff00) != 0)
450eefe4b1dSAxel Dörfler		return B_ERROR;
451eefe4b1dSAxel Dörfler
452eefe4b1dSAxel Dörfler	if (info->signature != VESA_SIGNATURE)
453eefe4b1dSAxel Dörfler		return B_ERROR;
454eefe4b1dSAxel Dörfler
45555be2751SAxel Dörfler	dprintf("VESA version = %d.%d, capabilities %lx\n", info->version.major,
45655be2751SAxel Dörfler		info->version.minor, info->capabilities);
457eefe4b1dSAxel Dörfler
458eefe4b1dSAxel Dörfler	if (info->version.major < 2) {
45913a81299SAxel Dörfler		dprintf("VESA support too old\n");
460eefe4b1dSAxel Dörfler		return B_ERROR;
461eefe4b1dSAxel Dörfler	}
462eefe4b1dSAxel Dörfler
463ce5cf7b3SAxel Dörfler	info->oem_string = SEGMENTED_TO_LINEAR(info->oem_string);
464ce5cf7b3SAxel Dörfler	info->mode_list = SEGMENTED_TO_LINEAR(info->mode_list);
46560642f87SAxel Dörfler	dprintf("OEM string: %s\n", (const char *)info->oem_string);
466eefe4b1dSAxel Dörfler
467ce5cf7b3SAxel Dörfler	return B_OK;
468ce5cf7b3SAxel Dörfler}
469ce5cf7b3SAxel Dörfler
470ce5cf7b3SAxel Dörfler
471ce5cf7b3SAxel Dörflerstatic status_t
472f42302bcSAxel Dörflervesa_init(vbe_info_block *info, video_mode **_standardMode)
473ce5cf7b3SAxel Dörfler{
474ce5cf7b3SAxel Dörfler	if (vesa_get_vbe_info_block(info) != B_OK)
475ce5cf7b3SAxel Dörfler		return B_ERROR;
476eefe4b1dSAxel Dörfler
4770752edcfSAxel Dörfler	// fill mode list and find standard video mode
478f42302bcSAxel Dörfler
479f42302bcSAxel Dörfler	video_mode *standardMode = NULL;
480f42302bcSAxel Dörfler
481133c5b73SAxel Dörfler	for (int32 i = 0; true; i++) {
482133c5b73SAxel Dörfler		uint16 mode = ((uint16 *)info->mode_list)[i];
483eefe4b1dSAxel Dörfler		if (mode == 0xffff)
484eefe4b1dSAxel Dörfler			break;
485eefe4b1dSAxel Dörfler
486eefe4b1dSAxel Dörfler		struct vbe_mode_info modeInfo;
487eefe4b1dSAxel Dörfler		if (vesa_get_mode_info(mode, &modeInfo) == B_OK) {
488746efef3SFrançois Revol			TRACE((" 0x%03x: %u x %u x %u (a = %d, mem = %d, phy = %lx, p = %d, b = %d)\n", mode,
489746efef3SFrançois Revol				   modeInfo.width, modeInfo.height, modeInfo.bits_per_pixel, modeInfo.attributes,
490746efef3SFrançois Revol				   modeInfo.memory_model, modeInfo.physical_base, modeInfo.num_planes,
491746efef3SFrançois Revol				   modeInfo.num_banks));
492746efef3SFrançois Revol			TRACE(("	mask: r: %d %d g: %d %d b: %d %d dcmi: %d\n",
493746efef3SFrançois Revol				   modeInfo.red_mask_size, modeInfo.red_field_position,
4943872a2d2SIngo Weinhold				   modeInfo.green_mask_size, modeInfo.green_field_position,
495746efef3SFrançois Revol				   modeInfo.blue_mask_size, modeInfo.blue_field_position,
496746efef3SFrançois Revol				   modeInfo.direct_color_mode_info));
4973872a2d2SIngo Weinhold
4989b13056bSAxel Dörfler			const uint32 requiredAttributes = MODE_ATTR_AVAILABLE
5009b13056bSAxel Dörfler				| MODE_ATTR_LINEAR_BUFFER;
501eefe4b1dSAxel Dörfler
502f42302bcSAxel Dörfler			if (modeInfo.width >= 640
503eefe4b1dSAxel Dörfler				&& modeInfo.physical_base != 0
504eefe4b1dSAxel Dörfler				&& modeInfo.num_planes == 1
505eefe4b1dSAxel Dörfler				&& (modeInfo.memory_model == MODE_MEMORY_PACKED_PIXEL
506eefe4b1dSAxel Dörfler					|| modeInfo.memory_model == MODE_MEMORY_DIRECT_COLOR)
5079b13056bSAxel Dörfler				&& (modeInfo.attributes & requiredAttributes)
5089b13056bSAxel Dörfler					== requiredAttributes) {
509f42302bcSAxel Dörfler				// this mode fits our needs
5109b13056bSAxel Dörfler				video_mode *videoMode = (video_mode *)malloc(
5119b13056bSAxel Dörfler					sizeof(struct video_mode));
512f42302bcSAxel Dörfler				if (videoMode == NULL)
513f42302bcSAxel Dörfler					continue;
514f42302bcSAxel Dörfler
515f42302bcSAxel Dörfler				videoMode->mode = mode;
5165845b6ecSAxel Dörfler				videoMode->bytes_per_row = modeInfo.bytes_per_row;
517f42302bcSAxel Dörfler				videoMode->width = modeInfo.width;
518f42302bcSAxel Dörfler				videoMode->height = modeInfo.height;
519f42302bcSAxel Dörfler				videoMode->bits_per_pixel = modeInfo.bits_per_pixel;
520b4c8ccc3SAxel Dörfler				videoMode->timing = NULL;
521b4c8ccc3SAxel Dörfler
5225845b6ecSAxel Dörfler				if (modeInfo.bits_per_pixel == 16
5235845b6ecSAxel Dörfler					&& modeInfo.red_mask_size + modeInfo.green_mask_size
5245845b6ecSAxel Dörfler						+ modeInfo.blue_mask_size == 15) {
5255845b6ecSAxel Dörfler					// this is really a 15-bit mode
5265845b6ecSAxel Dörfler					videoMode->bits_per_pixel = 15;
5275845b6ecSAxel Dörfler				}
528f42302bcSAxel Dörfler
529d5062208SAxel Dörfler				add_video_mode(videoMode);
530eefe4b1dSAxel Dörfler			}
531eefe4b1dSAxel Dörfler		} else
532746efef3SFrançois Revol			TRACE((" 0x%03x: (failed)\n", mode));
533eefe4b1dSAxel Dörfler	}
534eefe4b1dSAxel Dörfler
535652c8526SAxel Dörfler	// Choose default resolution (when no EDID information is available)
536e146dee3SAxel Dörfler	const uint32 kPreferredWidth = 1024;
537e146dee3SAxel Dörfler	const uint32 kFallbackWidth = 800;
538e146dee3SAxel Dörfler
539e146dee3SAxel Dörfler	standardMode = find_video_mode(kPreferredWidth, -1, false);
540e146dee3SAxel Dörfler	if (standardMode == NULL) {
541e146dee3SAxel Dörfler		standardMode = find_video_mode(kFallbackWidth, -1, false);
542e146dee3SAxel Dörfler		if (standardMode == NULL) {
543e146dee3SAxel Dörfler			standardMode = find_video_mode(kPreferredWidth, -1, true);
544e146dee3SAxel Dörfler			if (standardMode == NULL)
545e146dee3SAxel Dörfler				standardMode = find_video_mode(kFallbackWidth, -1, true);
546e146dee3SAxel Dörfler		}
547e146dee3SAxel Dörfler	}
548e146dee3SAxel Dörfler	if (standardMode == NULL) {
549e146dee3SAxel Dörfler		// just take any mode
550e146dee3SAxel Dörfler		standardMode = (video_mode *)list_get_first_item(&sModeList);
551e146dee3SAxel Dörfler	}
552652c8526SAxel Dörfler
553f42302bcSAxel Dörfler	if (standardMode == NULL) {
554f42302bcSAxel Dörfler		// no usable VESA mode found...
555f42302bcSAxel Dörfler		return B_ERROR;
556f42302bcSAxel Dörfler	}
557f42302bcSAxel Dörfler
558746efef3SFrançois Revol	TRACE(("Using mode 0x%03x\n", standardMode->mode));
559f42302bcSAxel Dörfler	*_standardMode = standardMode;
560f42302bcSAxel Dörfler	return B_OK;
561eefe4b1dSAxel Dörfler}
562eefe4b1dSAxel Dörfler
563eefe4b1dSAxel Dörfler
564eefe4b1dSAxel Dörfler#if 0
565eefe4b1dSAxel Dörflerstatic status_t
566eefe4b1dSAxel Dörflervesa_get_mode(uint16 *_mode)
567eefe4b1dSAxel Dörfler{
568eefe4b1dSAxel Dörfler	struct bios_regs regs;
569eefe4b1dSAxel Dörfler	regs.eax = 0x4f03;
570eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
571eefe4b1dSAxel Dörfler
572eefe4b1dSAxel Dörfler	if ((regs.eax & 0xffff) != 0x4f)
573eefe4b1dSAxel Dörfler		return B_ERROR;
574eefe4b1dSAxel Dörfler
575eefe4b1dSAxel Dörfler	*_mode = regs.ebx & 0xffff;
576eefe4b1dSAxel Dörfler	return B_OK;
577eefe4b1dSAxel Dörfler}
578eefe4b1dSAxel Dörfler#endif
579eefe4b1dSAxel Dörfler
580eefe4b1dSAxel Dörfler
581eefe4b1dSAxel Dörflerstatic status_t
58239c7faa4SAxel Dörflervesa_set_mode(video_mode* mode, bool useTiming)
583eefe4b1dSAxel Dörfler{
584eefe4b1dSAxel Dörfler	struct bios_regs regs;
585eefe4b1dSAxel Dörfler	regs.eax = 0x4f02;
586b4c8ccc3SAxel Dörfler	regs.ebx = (mode->mode & SET_MODE_MASK) | SET_MODE_LINEAR_BUFFER;
587b4c8ccc3SAxel Dörfler
58839c7faa4SAxel Dörfler	if (useTiming && mode->timing != NULL) {
589b4c8ccc3SAxel Dörfler		regs.ebx |= SET_MODE_SPECIFY_CRTC;
590b4c8ccc3SAxel Dörfler		regs.es = ADDRESS_SEGMENT(mode->timing);
591b4c8ccc3SAxel Dörfler		regs.edi = ADDRESS_OFFSET(mode->timing);
592b4c8ccc3SAxel Dörfler	}
593b4c8ccc3SAxel Dörfler
594eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
595eefe4b1dSAxel Dörfler
596eefe4b1dSAxel Dörfler	if ((regs.eax & 0xffff) != 0x4f)
597eefe4b1dSAxel Dörfler		return B_ERROR;
598eefe4b1dSAxel Dörfler
599eefe4b1dSAxel Dörfler#if 0
600eefe4b1dSAxel Dörfler	// make sure we have 8 bits per color channel
601eefe4b1dSAxel Dörfler	regs.eax = 0x4f08;
602eefe4b1dSAxel Dörfler	regs.ebx = 8 << 8;
603eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
604eefe4b1dSAxel Dörfler#endif
605eefe4b1dSAxel Dörfler
606eefe4b1dSAxel Dörfler	return B_OK;
607eefe4b1dSAxel Dörfler}
608eefe4b1dSAxel Dörfler
609eefe4b1dSAxel Dörfler
610eefe4b1dSAxel Dörflerstatic status_t
611eefe4b1dSAxel Dörflervesa_set_palette(const uint8 *palette, int32 firstIndex, int32 numEntries)
612eefe4b1dSAxel Dörfler{
613eefe4b1dSAxel Dörfler	// is this an 8 bit indexed color mode?
6148c3e1399SAxel Dörfler	if (gKernelArgs.frame_buffer.depth != 8)
615eefe4b1dSAxel Dörfler		return B_BAD_TYPE;
6168c3e1399SAxel Dörfler
61792e0317cSAxel Dörfler#if 0
618eefe4b1dSAxel Dörfler	struct bios_regs regs;
619eefe4b1dSAxel Dörfler	regs.eax = 0x4f09;
620eefe4b1dSAxel Dörfler	regs.ebx = 0;
621eefe4b1dSAxel Dörfler	regs.ecx = numEntries;
622eefe4b1dSAxel Dörfler	regs.edx = firstIndex;
623eefe4b1dSAxel Dörfler	regs.es = (addr_t)palette >> 4;
624eefe4b1dSAxel Dörfler	regs.edi = (addr_t)palette & 0xf;
625eefe4b1dSAxel Dörfler	call_bios(0x10, &regs);
626eefe4b1dSAxel Dörfler
627eefe4b1dSAxel Dörfler	if ((regs.eax & 0xffff) != 0x4f) {
62892e0317cSAxel Dörfler#endif
629eefe4b1dSAxel Dörfler		// the VESA call does not work, just try good old VGA mechanism
630eefe4b1dSAxel Dörfler		vga_set_palette(palette, firstIndex, numEntries);
63192e0317cSAxel Dörfler#if 0
632eefe4b1dSAxel Dörfler		return B_ERROR;
633eefe4b1dSAxel Dörfler	}
63492e0317cSAxel Dörfler#endif
635eefe4b1dSAxel Dörfler	return B_OK;
636eefe4b1dSAxel Dörfler}
637eefe4b1dSAxel Dörfler
638eefe4b1dSAxel Dörfler
639eefe4b1dSAxel Dörfler//	#pragma mark -
640eefe4b1dSAxel Dörfler
641eefe4b1dSAxel Dörfler
642a104674fSAxel Dörflerbool
643a104674fSAxel Dörflervideo_mode_hook(Menu *menu, MenuItem *item)
644a104674fSAxel Dörfler{
645a104674fSAxel Dörfler	// find selected mode
646a104674fSAxel Dörfler	video_mode *mode = NULL;
647a104674fSAxel Dörfler
648bb6e4f5dSAdrien Destugues	Menu* submenu = item->Submenu();
649bb6e4f5dSAdrien Destugues	MenuItem* subitem = submenu->FindMarked();
650bb6e4f5dSAdrien Destugues	if (subitem != NULL) {
651bb6e4f5dSAdrien Destugues		switch (submenu->IndexOf(subitem)) {
652d3ff9cc3SAxel Dörfler			case 0:
653d3ff9cc3SAxel Dörfler				// "Default" mode special
654d3ff9cc3SAxel Dörfler				sMode = sDefaultMode;
655d3ff9cc3SAxel Dörfler				sModeChosen = false;
656d3ff9cc3SAxel Dörfler				return true;
657d3ff9cc3SAxel Dörfler			case 1:
658d3ff9cc3SAxel Dörfler				// "Standard VGA" mode special
659d3ff9cc3SAxel Dörfler				// sets sMode to NULL which triggers VGA mode
660d3ff9cc3SAxel Dörfler				break;
661d3ff9cc3SAxel Dörfler			default:
662bb6e4f5dSAdrien Destugues				mode = (video_mode *)subitem->Data();
663d3ff9cc3SAxel Dörfler				break;
664d3ff9cc3SAxel Dörfler		}
665d3ff9cc3SAxel Dörfler	}
666a104674fSAxel Dörfler
667a104674fSAxel Dörfler	if (mode != sMode) {
668a104674fSAxel Dörfler		// update standard mode
669a104674fSAxel Dörfler		// ToDo: update fb settings!
670a104674fSAxel Dörfler		sMode = mode;
671a104674fSAxel Dörfler	}
672a104674fSAxel Dörfler
673486c7eddSAxel Dörfler	sModeChosen = true;
674a104674fSAxel Dörfler	return true;
675a104674fSAxel Dörfler}
676a104674fSAxel Dörfler
677a104674fSAxel Dörfler
678a104674fSAxel DörflerMenu *
679a104674fSAxel Dörflervideo_mode_menu()
680a104674fSAxel Dörfler{
68182029bdaSMarcus Overhagen	Menu *menu = new(nothrow) Menu(CHOICE_MENU, "Select Video Mode");
682a104674fSAxel Dörfler	MenuItem *item;
683a104674fSAxel Dörfler
68482029bdaSMarcus Overhagen	menu->AddItem(item = new(nothrow) MenuItem("Default"));
685a104674fSAxel Dörfler	item->SetMarked(true);
686a104674fSAxel Dörfler	item->Select(true);
6879b13056bSAxel Dörfler	item->SetHelpText("The Default video mode is the one currently configured "
6889b13056bSAxel Dörfler		"in the system. If there is no mode configured yet, a viable mode will "
6899b13056bSAxel Dörfler		"be chosen automatically.");
690a104674fSAxel Dörfler
69182029bdaSMarcus Overhagen	menu->AddItem(new(nothrow) MenuItem("Standard VGA"));
692a104674fSAxel Dörfler
693a104674fSAxel Dörfler	video_mode *mode = NULL;
694a104674fSAxel Dörfler	while ((mode = (video_mode *)list_get_next_item(&sModeList, mode)) != NULL) {
695a104674fSAxel Dörfler		char label[64];
696b51ec9deSIngo Weinhold		snprintf(label, sizeof(label), "%ux%u %u bit", mode->width,
697b51ec9deSIngo Weinhold			mode->height, mode->bits_per_pixel);
698a104674fSAxel Dörfler
69982029bdaSMarcus Overhagen		menu->AddItem(item = new(nothrow) MenuItem(label));
700a104674fSAxel Dörfler		item->SetData(mode);
701a104674fSAxel Dörfler	}
702a104674fSAxel Dörfler
703a104674fSAxel Dörfler	menu->AddSeparatorItem();
70482029bdaSMarcus Overhagen	menu->AddItem(item = new(nothrow) MenuItem("Return to main menu"));
705a104674fSAxel Dörfler	item->SetType(MENU_ITEM_NO_CHOICE);
706a104674fSAxel Dörfler
707a104674fSAxel Dörfler	return menu;
708a104674fSAxel Dörfler}
709a104674fSAxel Dörfler
710a104674fSAxel Dörfler
711d3ff9cc3SAxel Dörflerstatic void
712d3ff9cc3SAxel Dörflerset_vga_mode(void)
713d3ff9cc3SAxel Dörfler{
714d3ff9cc3SAxel Dörfler	// sets 640x480 16 colors graphics mode
715d3ff9cc3SAxel Dörfler	bios_regs regs;
716119b7dccSAxel Dörfler	regs.eax = 0x0012;
717d3ff9cc3SAxel Dörfler	call_bios(0x10, &regs);
718d3ff9cc3SAxel Dörfler}
719d3ff9cc3SAxel Dörfler
720d3ff9cc3SAxel Dörfler
721133c5b73SAxel Dörflerstatic void
722133c5b73SAxel Dörflerset_text_mode(void)
723133c5b73SAxel Dörfler{
724d3ff9cc3SAxel Dörfler	// sets 80x25 text console
725133c5b73SAxel Dörfler	bios_regs regs;
726119b7dccSAxel Dörfler	regs.eax = 0x0003;
727119b7dccSAxel Dörfler	call_bios(0x10, &regs);
728119b7dccSAxel Dörfler
729d2b49a00SRene Gollent	video_hide_text_cursor();
730d2b49a00SRene Gollent}
731d2b49a00SRene Gollent
732d2b49a00SRene Gollent
733d2b49a00SRene Gollentvoid
734d2b49a00SRene Gollentvideo_move_text_cursor(int x, int y)
735d2b49a00SRene Gollent{
736d2b49a00SRene Gollent	bios_regs regs;
737d2b49a00SRene Gollent	regs.eax = 0x0200;
738d2b49a00SRene Gollent	regs.ebx = 0;
739d2b49a00SRene Gollent	regs.edx = (y << 8) | x;
740d2b49a00SRene Gollent	call_bios(0x10, &regs);
741d2b49a00SRene Gollent}
742d2b49a00SRene Gollent
743d2b49a00SRene Gollent
744d2b49a00SRene Gollentvoid
745d2b49a00SRene Gollentvideo_show_text_cursor(void)
746d2b49a00SRene Gollent{
747d2b49a00SRene Gollent	bios_regs regs;
748d2b49a00SRene Gollent	regs.eax = 0x0100;
749d2b49a00SRene Gollent	regs.ecx = 0x0607;
750d2b49a00SRene Gollent	call_bios(0x10, &regs);
751d2b49a00SRene Gollent}
752d2b49a00SRene Gollent
753d2b49a00SRene Gollent
754d2b49a00SRene Gollentvoid
755d2b49a00SRene Gollentvideo_hide_text_cursor(void)
756d2b49a00SRene Gollent{
757d2b49a00SRene Gollent	bios_regs regs;
758119b7dccSAxel Dörfler	regs.eax = 0x0100;
759119b7dccSAxel Dörfler	regs.ecx = 0x2000;
760133c5b73SAxel Dörfler	call_bios(0x10, &regs);
761133c5b73SAxel Dörfler}
762133c5b73SAxel Dörfler
763133c5b73SAxel Dörfler
7648bd36612SAxel Dörfler//	#pragma mark - blit
7658bd36612SAxel Dörfler
7668bd36612SAxel Dörfler
7670573d397SFrançois Revolvoid
7687db9fbfeSFrançois Revolplatform_blit4(addr_t frameBuffer, const uint8 *data,
7690573d397SFrançois Revol	uint16 width, uint16 height, uint16 imageWidth, uint16 left, uint16 top)
7708bd36612SAxel Dörfler{
7710573d397SFrançois Revol	if (!data)
77255ef60a5SStephan Aßmus		return;
7738bd36612SAxel Dörfler	// ToDo: no boot logo yet in VGA mode
7748bd36612SAxel Dörfler#if 1
7758bd36612SAxel Dörfler// this draws 16 big rectangles in all the available colors
7767db9fbfeSFrançois Revol	uint8 *bits = (uint8 *)frameBuffer;
7777db9fbfeSFrançois Revol	uint32 bytesPerRow = 80;
7788bd36612SAxel Dörfler	for (int32 i = 0; i < 32; i++) {
7798bd36612SAxel Dörfler		bits[9 * bytesPerRow + i + 2] = 0x55;
7808bd36612SAxel Dörfler		bits[30 * bytesPerRow + i + 2] = 0xaa;
7818bd36612SAxel Dörfler	}
7828bd36612SAxel Dörfler
7838bd36612SAxel Dörfler	for (int32 y = 10; y < 30; y++) {
7848bd36612SAxel Dörfler		for (int32 i = 0; i < 16; i++) {
7858bd36612SAxel Dörfler			out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX);
7868bd36612SAxel Dörfler			bits[32 * bytesPerRow + i*2 + 2] = i;
7878bd36612SAxel Dörfler
7888bd36612SAxel Dörfler			if (i & 1) {
7898bd36612SAxel Dörfler				out16((1 << 8) | 0x02, VGA_SEQUENCER_INDEX);
7908bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 2] = 0xff;
7918bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 3] = 0xff;
7928bd36612SAxel Dörfler			}
7938bd36612SAxel Dörfler			if (i & 2) {
7948bd36612SAxel Dörfler				out16((2 << 8) | 0x02, VGA_SEQUENCER_INDEX);
7958bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 2] = 0xff;
7968bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 3] = 0xff;
7978bd36612SAxel Dörfler			}
7988bd36612SAxel Dörfler			if (i & 4) {
7998bd36612SAxel Dörfler				out16((4 << 8) | 0x02, VGA_SEQUENCER_INDEX);
8008bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 2] = 0xff;
8018bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 3] = 0xff;
8028bd36612SAxel Dörfler			}
8038bd36612SAxel Dörfler			if (i & 8) {
8048bd36612SAxel Dörfler				out16((8 << 8) | 0x02, VGA_SEQUENCER_INDEX);
8058bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 2] = 0xff;
8068bd36612SAxel Dörfler				bits[y * bytesPerRow + i*2 + 3] = 0xff;
8078bd36612SAxel Dörfler			}
8088bd36612SAxel Dörfler		}
8098bd36612SAxel Dörfler	}
8108bd36612SAxel Dörfler
8118bd36612SAxel Dörfler	// enable all planes again
8128bd36612SAxel Dörfler	out16((15 << 8) | 0x02, VGA_SEQUENCER_INDEX);
8138bd36612SAxel Dörfler#endif
8148bd36612SAxel Dörfler}
8158bd36612SAxel Dörfler
8168bd36612SAxel Dörfler
8177db9fbfeSFrançois Revolextern "C" void
8187db9fbfeSFrançois Revolplatform_set_palette(const uint8 *palette)
8198bd36612SAxel Dörfler{
8208bd36612SAxel Dörfler	switch (gKernelArgs.frame_buffer.depth) {
8218bd36612SAxel Dörfler		case 4:
8220573d397SFrançois Revol			//vga_set_palette((const uint8 *)kPalette16, 0, 16);
8230573d397SFrançois Revol			break;
8248bd36612SAxel Dörfler		case 8:
8250573d397SFrançois Revol			if (vesa_set_palette((const uint8 *)palette, 0, 256) != B_OK)
8260573d397SFrançois Revol				dprintf("set palette failed!\n");
827d0fc7c65SStephan Aßmus
8280573d397SFrançois Revol			break;
8290573d397SFrançois Revol		default:
8300573d397SFrançois Revol			break;
831ec56835fSStephan Aßmus	}
832ec56835fSStephan Aßmus}
833ec56835fSStephan Aßmus
834ec56835fSStephan Aßmus
835aa727f66SStephan Aßmus//	#pragma mark -
836a104674fSAxel Dörfler
837eefe4b1dSAxel Dörflerextern "C" void
838eefe4b1dSAxel Dörflerplatform_switch_to_logo(void)
839eefe4b1dSAxel Dörfler{
840a7fb02e6SAxel Dörfler	// in debug mode, we'll never show the logo
841a7fb02e6SAxel Dörfler	if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) != 0)
842a7fb02e6SAxel Dörfler		return;
843a7fb02e6SAxel Dörfler
844d3ff9cc3SAxel Dörfler	addr_t lastBase = gKernelArgs.frame_buffer.physical_buffer.start;
845d3ff9cc3SAxel Dörfler	size_t lastSize = gKernelArgs.frame_buffer.physical_buffer.size;
846eefe4b1dSAxel Dörfler
847d3ff9cc3SAxel Dörfler	if (sVesaCompatible && sMode != NULL) {
848d3ff9cc3SAxel Dörfler		if (!sModeChosen)
849d3ff9cc3SAxel Dörfler			get_mode_from_settings();
85085f02010SStephan Aßmus
85139c7faa4SAxel Dörfler		// On some BIOS / chipset / monitor combinations, there seems to be a
85239c7faa4SAxel Dörfler		// timing issue between getting the EDID data and setting the video
85339c7faa4SAxel Dörfler		// mode. As such we wait here briefly to give everything enough time
85439c7faa4SAxel Dörfler		// to settle.
8550d69c837SRene Gollent		spin(1000);
85639c7faa4SAxel Dörfler
85739c7faa4SAxel Dörfler		if ((sMode->timing == NULL || vesa_set_mode(sMode, true) != B_OK)
85839c7faa4SAxel Dörfler			&& vesa_set_mode(sMode, false) != B_OK)
859d3ff9cc3SAxel Dörfler			goto fallback;
860d3ff9cc3SAxel Dörfler
861d3ff9cc3SAxel Dörfler		struct vbe_mode_info modeInfo;
862d3ff9cc3SAxel Dörfler		if (vesa_get_mode_info(sMode->mode, &modeInfo) != B_OK)
863d3ff9cc3SAxel Dörfler			goto fallback;
864d3ff9cc3SAxel Dörfler
865d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.width = modeInfo.width;
866d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.height = modeInfo.height;
8675845b6ecSAxel Dörfler		gKernelArgs.frame_buffer.bytes_per_row = modeInfo.bytes_per_row;
868d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.depth = modeInfo.bits_per_pixel;
8693872a2d2SIngo Weinhold		gKernelArgs.frame_buffer.physical_buffer.size
8703872a2d2SIngo Weinhold			= (phys_size_t)modeInfo.bytes_per_row
8713872a2d2SIngo Weinhold				* (phys_size_t)gKernelArgs.frame_buffer.height;
872d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.physical_buffer.start = modeInfo.physical_base;
873d3ff9cc3SAxel Dörfler	} else {
874d3ff9cc3SAxel Dörflerfallback:
875d3ff9cc3SAxel Dörfler		// use standard VGA mode 640x480x4
876d3ff9cc3SAxel Dörfler		set_vga_mode();
877d3ff9cc3SAxel Dörfler
878d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.width = 640;
879d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.height = 480;
88013247f3aSAxel Dörfler		gKernelArgs.frame_buffer.bytes_per_row = 80;
881d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.depth = 4;
8829b13056bSAxel Dörfler		gKernelArgs.frame_buffer.physical_buffer.size
8833872a2d2SIngo Weinhold			= (phys_size_t)gKernelArgs.frame_buffer.width
8843872a2d2SIngo Weinhold				* (phys_size_t)gKernelArgs.frame_buffer.height / 2;
885d3ff9cc3SAxel Dörfler		gKernelArgs.frame_buffer.physical_buffer.start = 0xa0000;
886d3ff9cc3SAxel Dörfler	}
887eefe4b1dSAxel Dörfler
8889b13056bSAxel Dörfler	dprintf("video mode: %ux%ux%u\n", gKernelArgs.frame_buffer.width,
8899b13056bSAxel Dörfler		gKernelArgs.frame_buffer.height, gKernelArgs.frame_buffer.depth);
8909b13056bSAxel Dörfler
8915845b6ecSAxel Dörfler	gKernelArgs.frame_buffer.enabled = true;
892eefe4b1dSAxel Dörfler
893d3ff9cc3SAxel Dörfler	// If the new frame buffer is either larger than the old one or located at
894d3ff9cc3SAxel Dörfler	// a different address, we need to remap it, so we first have to throw
895d3ff9cc3SAxel Dörfler	// away its previous mapping
896d3ff9cc3SAxel Dörfler	if (lastBase != 0
897d3ff9cc3SAxel Dörfler		&& (lastBase != gKernelArgs.frame_buffer.physical_buffer.start
898d3ff9cc3SAxel Dörfler			|| lastSize < gKernelArgs.frame_buffer.physical_buffer.size)) {
899d3ff9cc3SAxel Dörfler		mmu_free((void *)sFrameBuffer, lastSize);
900d3ff9cc3SAxel Dörfler		lastBase = 0;
901a7fb02e6SAxel Dörfler	}
902a7fb02e6SAxel Dörfler	if (lastBase == 0) {
903eefe4b1dSAxel Dörfler		// the graphics memory has not been mapped yet!
9045845b6ecSAxel Dörfler		sFrameBuffer = mmu_map_physical_memory(
9055845b6ecSAxel Dörfler			gKernelArgs.frame_buffer.physical_buffer.start,
9065845b6ecSAxel Dörfler			gKernelArgs.frame_buffer.physical_buffer.size, kDefaultPageFlags);
907eefe4b1dSAxel Dörfler	}
908eefe4b1dSAxel Dörfler
90904cbc258SFredrik Holmqvist	video_display_splash(sFrameBuffer);
910eefe4b1dSAxel Dörfler}
911eefe4b1dSAxel Dörfler
912eefe4b1dSAxel Dörfler
913eefe4b1dSAxel Dörflerextern "C" void
914eefe4b1dSAxel Dörflerplatform_switch_to_text_mode(void)
915eefe4b1dSAxel Dörfler{
9168c3e1399SAxel Dörfler	if (!gKernelArgs.frame_buffer.enabled) {
9178c3e1399SAxel Dörfler		vga_enable_bright_background_colors();
918eefe4b1dSAxel Dörfler		return;