99104a2880d0e0a34abf3dc9ad67d643c2108234
[bootcensus] / src / kmain.c
1 /*
2 pcboot - bootable PC demo/game kernel
3 Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY, without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 #include <stdio.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include "segm.h"
22 #include "intr.h"
23 #include "mem.h"
24 #include "keyb.h"
25 #include "psaux.h"
26 #include "timer.h"
27 #include "contty.h"
28 #include "video.h"
29 #include "vbe.h"
30 #include "audio.h"
31 #include "panic.h"
32 #include "census/census.h"
33
34 static int video_init(void);
35 static int modecmp(const void *a, const void *b);
36
37 static struct video_mode vmode;
38 static void *fbptr, *backbuf;
39 static int fbsize;
40
41
42 void pcboot_main(void)
43 {
44         init_segm();
45         init_intr();
46
47         con_init();
48         kb_init();
49         init_psaux();
50
51         init_mem();
52
53         /* initialize the timer */
54         init_timer();
55
56         audio_init();
57
58         enable_intr();
59
60         printf("PCBoot kernel initialized\n");
61
62         if(video_init() == -1) {
63                 panic("Failed to find suitable video mode");
64         }
65         fbsize = vmode.width * vmode.height * vmode.bpp / 8;
66         if(!(backbuf = malloc(fbsize))) {
67                 panic("Failed to allocate back buffer");
68         }
69         init_census(backbuf, vmode.width, vmode.height);
70
71         for(;;) {
72                 draw_census();
73
74                 wait_vsync();
75                 memcpy(fbptr, backbuf, fbsize);
76         }
77 }
78
79 static int video_init(void)
80 {
81         struct vbe_edid edid;
82         struct video_mode vinf, *vmodes;
83         int i, xres, yres, nmodes, mode_idx = -1;
84         const char *vendor;
85
86         if(mode_idx == -1 && (vendor = get_video_vendor()) && strstr(vendor, "SeaBIOS")) {
87                 mode_idx = find_video_mode_idx(800, 600, 32);
88         }
89
90         if(mode_idx == -1 && vbe_get_edid(&edid) == 0 && edid_preferred_resolution(&edid, &xres, &yres) == 0) {
91                 printf("EDID: preferred resolution: %dx%d\n", xres, yres);
92                 mode_idx = find_video_mode_idx(xres, yres, 0);
93         }
94
95         nmodes = video_mode_count();
96         if(!(vmodes = malloc(nmodes * sizeof *vmodes))) {
97                 printf("failed to allocate video modes array (%d modes)\n", nmodes);
98                 return -1;
99         }
100
101         for(i=0; i<nmodes; i++) {
102                 video_mode_info(i, &vinf);
103                 vmodes[i] = vinf;
104         }
105
106         if(mode_idx >= 0) {
107                 if(!(fbptr = set_video_mode(vmodes[mode_idx].mode))) {
108                         printf("failed to set video mode: %x (%dx%d %dbpp)\n", mode_idx,
109                                         vmodes[mode_idx].width, vmodes[mode_idx].height, vmodes[mode_idx].bpp);
110                         mode_idx = -1;
111                 } else {
112                         vmode = vmodes[mode_idx];
113                         printf("video mode: %x (%dx%d %dbpp)\n", vmode.mode, vmode.width,
114                                         vmode.height, vmode.bpp);
115                 }
116         }
117
118         if(mode_idx == -1) {
119                 qsort(vmodes, nmodes, sizeof *vmodes, modecmp);
120
121                 for(i=0; i<nmodes; i++) {
122                         if((fbptr = set_video_mode(vmodes[i].mode))) {
123                                 vmode = vmodes[i];
124                                 printf("video mode: %x (%dx%d %dbpp)\n", vmode.mode, vmode.width,
125                                                 vmode.height, vmode.bpp);
126                                 break;
127                         }
128                 }
129                 if(i >= nmodes) {
130                         printf("failed to find a suitable video mode\n");
131                         return -1;
132                 }
133         }
134         free(vmodes);
135
136         return 0;
137 }
138
139
140
141 static int modecmp(const void *a, const void *b)
142 {
143         const struct video_mode *ma = a;
144         const struct video_mode *mb = b;
145         unsigned long aval = ma->width | (ma->height << 16);
146         unsigned long bval = mb->width | (mb->height << 16);
147
148         if(aval != bval) {
149                 return bval - aval;
150         }
151         return mb->bpp - ma->bpp;
152 }