+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018 John Tsiombikas <nuclear@member.fsf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY, without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "segm.h"
+#include "intr.h"
+#include "mem.h"
+#include "keyb.h"
+#include "psaux.h"
+#include "timer.h"
#include "contty.h"
+#include "video.h"
+#include "vbe.h"
+#include "audio.h"
+#include "panic.h"
+
+static int video_init(void);
+static int modecmp(const void *a, const void *b);
+
+static struct video_mode vmode;
+static void *fbptr;
-static int foo = 42;
void pcboot_main(void)
{
+ init_segm();
+ init_intr();
+
con_init();
+ kb_init();
+ init_psaux();
+
+ init_mem();
+
+ /* initialize the timer */
+ init_timer();
+
+ audio_init();
+
+ enable_intr();
+
+ printf("PCBoot kernel initialized\n");
+
+ if(video_init() == -1) {
+ panic("Failed to find suitable video mode");
+ }
+
+ for(;;) {
+ wait_vsync();
+ memset(fbptr, 0x80, vmode.width * vmode.height * vmode.bpp / 8);
+ }
+}
+
+static int video_init(void)
+{
+ struct vbe_edid edid;
+ struct video_mode vinf, *vmodes;
+ int i, xres, yres, nmodes, mode_idx = -1;
+ const char *vendor;
+
+ if(mode_idx == -1 && (vendor = get_video_vendor()) && strstr(vendor, "SeaBIOS")) {
+ mode_idx = find_video_mode_idx(800, 600, 0);
+ }
+
+ if(mode_idx == -1 && vbe_get_edid(&edid) == 0 && edid_preferred_resolution(&edid, &xres, &yres) == 0) {
+ printf("EDID: preferred resolution: %dx%d\n", xres, yres);
+ mode_idx = find_video_mode_idx(xres, yres, 0);
+ }
+
+ nmodes = video_mode_count();
+ if(!(vmodes = malloc(nmodes * sizeof *vmodes))) {
+ printf("failed to allocate video modes array (%d modes)\n", nmodes);
+ return -1;
+ }
+
+ for(i=0; i<nmodes; i++) {
+ video_mode_info(i, &vinf);
+ vmodes[i] = vinf;
+ }
+
+ if(mode_idx >= 0) {
+ if(!(fbptr = set_video_mode(vmodes[mode_idx].mode))) {
+ printf("failed to set video mode: %x (%dx%d %dbpp)\n", mode_idx,
+ vmodes[mode_idx].width, vmodes[mode_idx].height, vmodes[mode_idx].bpp);
+ mode_idx = -1;
+ } else {
+ vmode = vmodes[mode_idx];
+ printf("video mode: %x (%dx%d %dbpp)\n", vmode.mode, vmode.width,
+ vmode.height, vmode.bpp);
+ }
+ }
+
+ if(mode_idx == -1) {
+ qsort(vmodes, nmodes, sizeof *vmodes, modecmp);
+
+ for(i=0; i<nmodes; i++) {
+ if((fbptr = set_video_mode(vmodes[i].mode))) {
+ vmode = vmodes[i];
+ printf("video mode: %x (%dx%d %dbpp)\n", vmode.mode, vmode.width,
+ vmode.height, vmode.bpp);
+ break;
+ }
+ }
+ if(i >= nmodes) {
+ printf("failed to find a suitable video mode\n");
+ return -1;
+ }
+ }
+ free(vmodes);
+
+ return 0;
+}
+
+
+
+static int modecmp(const void *a, const void *b)
+{
+ const struct video_mode *ma = a;
+ const struct video_mode *mb = b;
+ unsigned long aval = ma->width | (ma->height << 16);
+ unsigned long bval = mb->width | (mb->height << 16);
- printf("hello world: %d\n", foo);
+ if(aval != bval) {
+ return bval - aval;
+ }
+ return mb->bpp - ma->bpp;
}