aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/dev/vesa.c
blob: 6b23a34f79434ae1c0a3498b5c67a402614a6df6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <string.h>

#include <dev/vesa.h>
#include <dev/v86.h>

//  ---- VESA data structures

typedef struct {
	char vbe_signature[4];				// == "VESA"
	uint16_t vbe_version;
	v86_farptr_t oem_string_ptr;
	uint8_t capabilities[4];
	v86_farptr_t video_mode_ptr;
	uint16_t total_memory;				// as # of 64KB blocks
} __attribute__((packed)) vbe_info_block_t;

typedef struct {
	uint16_t attributes;
	uint8_t winA, winB;
	uint16_t granularity;
	uint16_t winsize;
	uint16_t segmentA, segmentB;
	v86_farptr_t real_fct_ptr;
	uint16_t pitch; // bytes per scanline

	uint16_t Xres, Yres;
	uint8_t Wchar, Ychar, planes, bpp, banks;
	uint8_t memory_model, bank_size, image_pages;
	uint8_t reserved0;

	uint8_t red_mask, red_position;
	uint8_t green_mask, green_position;
	uint8_t blue_mask, blue_position;
	uint8_t rsv_mask, rsv_position;
	uint8_t directcolor_attributes;

	uint32_t physbase;		// the offset of the framebuffer in physical memory!
	uint32_t reserved1;
	uint16_t reserved2;
} __attribute__((packed)) vbe_mode_info_block_t;

//  ---- VESA code

void vesa_detect(fs_t *iofs) {
	if (!v86_begin_session()) return;
	
	vbe_info_block_t *i = (vbe_info_block_t*)v86_alloc(512);
	memset(i, 0, 512);
	strncpy(i->vbe_signature, "VBE2", 4);

	v86_regs.ax = 0x4F00;
	v86_regs.es = V86_SEG_OF_LIN(i);
	v86_regs.di = V86_OFF_OF_LIN(i);

	if (v86_bios_int(0x10)) {
		if (v86_regs.ax == 0x004F) {
			dbg_printf("Detected VESA (sig %s, ver 0x%x, oem %s) with %d kb ram.\n",
				i->vbe_signature, i->vbe_version, v86_lin_of_fp(i->oem_string_ptr), 64 * i->total_memory);

			vbe_mode_info_block_t *mi = (vbe_mode_info_block_t*)v86_alloc(256);

			uint16_t *modes = (uint16_t*)v86_lin_of_fp(i->video_mode_ptr);
			for (int n = 0; modes[n] != 0xFFFF; n++) {
				v86_regs.ax = 0x4F01;
				v86_regs.cx = modes[n];
				v86_regs.es = V86_SEG_OF_LIN(mi);
				v86_regs.di = V86_OFF_OF_LIN(mi);
				if (v86_bios_int(0x10) && v86_regs.ax == 0x004F) {
					dbg_printf("Mode 0x%x : %dx%dx%d at 0x%p\n", modes[n], mi->Xres, mi->Yres, mi->bpp, mi->physbase);
				} else {
					dbg_printf("Mode 0x%x : could not get info\n", modes[n]);
				}
			}
		} else {
			dbg_printf("Error in BIOS int 0x10/0x4F00.\n");
		}
	} else {
		dbg_printf("Could not call BIOS int 0x10.\n");
	}

	v86_end_session();
}

/* vim: set ts=4 sw=4 tw=0 noet :*/