BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / drivers / vga

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
diff --git a/drivers/vga/bga.c b/drivers/vga/bga.c
new file mode 100644
index 0000000..aff91aa
--- /dev/null
+++ b/drivers/vga/bga.c
@@ -0,0 +1,131 @@
+/*
+ * This file implements the driver for the Bochs Graphics Adapter video card.
+ * It is a simple card available in virtual machines.  It creates a framebuffer
+ * device node, and handles the reading/writing to it, and also mapping the
+ * framebuffer into memory.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <sys/fb.h>
+#include "../drivers.h"
+#include "../pci.h"
+#include "../../mem/paging.h"
+#include "../../vfs/vfs.h"
+#include "../../io.h"
+
+size_t bga_write(File *file, char *buf, size_t size, off_t offset);
+int bga_ioctl(File *file, unsigned long request, uintptr_t argp);
+
+FileOps bgaFileOps = {
+	.write = bga_write,
+	.ioctl = bga_ioctl,
+};
+
+Driver bgaDriver = {
+	.major = 3,
+	.ops = &bgaFileOps,
+	.next = NULL,
+};
+
+static uint32_t bgaWidth, bgaHeight, bgaBpp;
+static uintptr_t lfb;
+
+enum BGAIndex {
+	BGA_INDEX_ID,
+	BGA_INDEX_XRES,
+	BGA_INDEX_YRES,
+	BGA_INDEX_BPP,
+	BGA_INDEX_ENABLE,
+	BGA_INDEX_BANK,
+	BGA_INDEX_VIRT_WIDTH,
+	BGA_INDEX_VIRT_HEIGHT,
+	BGA_INDEX_XOFF,
+	BGA_INDEX_YOFF,
+};
+
+/* Write a BGA register */
+void
+bga_write_register(uint16_t index, uint16_t data)
+{
+	outw(0x1CE, index);
+	outw(0x1CF, data);
+}
+
+/* Set the video mode */
+void
+bga_set_mode(uint32_t width, uint32_t height, uint32_t bpp)
+{
+	bgaWidth = width;
+	bgaHeight = height;
+	bgaBpp = bpp;
+	bga_write_register(BGA_INDEX_ENABLE, 0);
+	bga_write_register(BGA_INDEX_XRES, width);
+	bga_write_register(BGA_INDEX_YRES, height);
+	bga_write_register(BGA_INDEX_BPP, bpp);
+	bga_write_register(BGA_INDEX_ENABLE, 1 | 0x40);
+	/* 0x40 for framebuffer */
+}
+
+/* Initialise the BGA card */
+void
+bga_init(uint8_t bus, uint8_t slot, uint8_t func)
+{
+	register_driver(&bgaDriver);
+
+	const int width = 1280;
+	const int height = 720;
+	const int bpp = 32;
+	bga_set_mode(width, height, bpp);
+	lfb = pci_read_dword(bus, slot, func, 0x10) & 0xFFFFFFF0;
+	for (uintptr_t i = 0; i < width*height*(bpp/8); i += 0x1000)
+		*get_page((void *) lfb + i) = (0xFD000000 + i) | PTE_PRESENT
+		                            | PTE_WRITE | PTE_GLOBAL;
+	/* use the MMAP method to map pages of it into a page dir */
+	mknod("/dev/fb", S_IFCHR | 0600, MKDEV(bgaDriver.major, 0));
+}
+
+/* Write to the BGA framebuffer */
+size_t
+bga_write(File *file, char *buf, size_t size, off_t offset)
+{
+	size_t max, count = 0;
+	page_t oldpg;
+	while (size) {
+		max = (size < 0x1000) ? size : 0x1000;
+		acquire(&quickPageLock);
+		oldpg = quick_page(lfb + PG_ADDR(offset) + count);
+		memcpy(QUICK_PAGE, buf + count, max);
+		quick_page(oldpg);
+		release(&quickPageLock);
+		count += max;
+		size -= max;
+	}
+	return count;
+}
+
+/* Control the BGA framebuffer/device */
+int
+bga_ioctl(File *file, unsigned long request, uintptr_t argp)
+{
+	FBVarInfo *vinfo;
+	FBFixInfo *finfo;
+
+	switch (request) {
+	case FBIOGET_VSCREENINFO:
+		vinfo = (void *) argp;
+		vinfo->xres = bgaWidth;
+		vinfo->yres = bgaHeight;
+		vinfo->bpp = bgaBpp;
+		return 0;
+	case FBIOPUT_VSCREENINFO:
+		vinfo = (void *) argp;
+		bga_set_mode(vinfo->xres, vinfo->yres, vinfo->bpp);
+		return 0;
+	case FBIOGET_FSCREENINFO:
+		finfo = (void *) argp;
+		finfo->fbmem = 0xFD000000; // lfb;
+		finfo->fbmemLen = bgaWidth*bgaHeight*(bgaBpp/8);
+		return 0;
+	}
+}