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