foo
[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 <unistd.h>
22 #include "segm.h"
23 #include "intr.h"
24 #include "mem.h"
25 #include "keyb.h"
26 #include "psaux.h"
27 #include "timer.h"
28 #include "contty.h"
29 #include "video.h"
30 #include "vbe.h"
31 #include "audio.h"
32 #include "panic.h"
33 #include "census/census.h"
34
35 static int video_init(void);
36 static int modecmp(const void *a, const void *b);
37
38 static struct video_mode vmode;
39 static void *fbptr, *backbuf;
40 static int fbsize;
41
42
43 void pcboot_main(void)
44 {
45         init_segm();
46         init_intr();
47
48         con_init();
49         kb_init();
50         init_psaux();
51
52         init_mem();
53
54         /* initialize the timer */
55         init_timer();
56
57         audio_init();
58
59         enable_intr();
60
61         printf("PCBoot kernel initialized\n");
62
63         if(video_init() == -1) {
64                 panic("Failed to find suitable video mode");
65         }
66         fbsize = vmode.width * vmode.height * vmode.bpp / 8;
67         if(!(backbuf = malloc(fbsize))) {
68                 panic("Failed to allocate back buffer");
69         }
70         init_census(backbuf, vmode.width, vmode.height);
71
72         for(;;) {
73                 draw_census();
74
75                 wait_vsync();
76                 memcpy(fbptr, backbuf, fbsize);
77         }
78 }
79
80 static int video_init(void)
81 {
82         struct vbe_edid edid;
83         struct video_mode vinf, *vmodes;
84         int i, xres, yres, nmodes, mode_idx = -1;
85         const char *vendor;
86
87         if(mode_idx == -1 && (vendor = get_video_vendor()) && strstr(vendor, "SeaBIOS")) {
88                 mode_idx = find_video_mode_idx(800, 600, 32);
89         }
90
91         if(mode_idx == -1 && vbe_get_edid(&edid) == 0 && edid_preferred_resolution(&edid, &xres, &yres) == 0) {
92                 printf("EDID: preferred resolution: %dx%d\n", xres, yres);
93                 mode_idx = find_video_mode_idx(xres, yres, 0);
94         }
95
96         nmodes = video_mode_count();
97         if(!(vmodes = malloc(nmodes * sizeof *vmodes))) {
98                 printf("failed to allocate video modes array (%d modes)\n", nmodes);
99                 return -1;
100         }
101
102         for(i=0; i<nmodes; i++) {
103                 video_mode_info(i, &vinf);
104                 vmodes[i] = vinf;
105         }
106
107         if(mode_idx >= 0) {
108                 if(!(fbptr = set_video_mode(vmodes[mode_idx].mode))) {
109                         printf("failed to set video mode: %x (%dx%d %dbpp)\n", mode_idx,
110                                         vmodes[mode_idx].width, vmodes[mode_idx].height, vmodes[mode_idx].bpp);
111                         mode_idx = -1;
112                 } else {
113                         vmode = vmodes[mode_idx];
114                         printf("video mode: %x (%dx%d %dbpp)\n", vmode.mode, vmode.width,
115                                         vmode.height, vmode.bpp);
116                 }
117         }
118
119         if(mode_idx == -1) {
120                 qsort(vmodes, nmodes, sizeof *vmodes, modecmp);
121
122                 for(i=0; i<nmodes; i++) {
123                         printf("trying video mode: %x (%dx%d %dbpp)\n", vmodes[i].mode, vmodes[i].width,
124                                         vmodes[i].height, vmodes[i].bpp);
125                         usleep(5000000);
126                         if((fbptr = set_video_mode(vmodes[i].mode))) {
127                                 vmode = vmodes[i];
128                                 break;
129                         }
130                 }
131                 if(i >= nmodes) {
132                         printf("failed to find a suitable video mode\n");
133                         return -1;
134                 }
135         }
136         free(vmodes);
137
138         return 0;
139 }
140
141
142
143 static int modecmp(const void *a, const void *b)
144 {
145         const struct video_mode *ma = a;
146         const struct video_mode *mb = b;
147         unsigned long aval = ma->width | (ma->height << 16);
148         unsigned long bval = mb->width | (mb->height << 16);
149
150         if(aval != bval) {
151                 return bval - aval;
152         }
153         return mb->bpp - ma->bpp;
154 }