BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / 6f4db8dc5c60c748b1d98b3caab8b43ffaf48b41

// Related

Nucleus

Barry Basic BGA driver 6f4db8d (3 years, 2 months ago)
diff --git a/drivers/devices.c b/drivers/devices.c
index a5873df..9e0203a 100644
--- a/drivers/devices.c
+++ b/drivers/devices.c
@@ -16,6 +16,7 @@ struct Device {
 };
 
 void pci_init_ide(uint8_t bus, uint8_t dev, uint8_t func);
+void pci_init_bga(uint8_t bus, uint8_t dev, uint8_t func);
 
 /* Device database */
 struct Device devices[] = {
@@ -32,7 +33,7 @@ struct Device devices[] = {
 
 	/* Virtual devices */
 	{0x1B36, 0x000D, "QEMU XHCI Host Adapter", NULL},
-	{0x1234, 0x1111, "QEMU/Bochs VBE Framebuffer", NULL},
+	{0x1234, 0x1111, "QEMU/Bochs VBE Framebuffer", pci_init_bga},
 };
 
 /* Initialise a PCI device */
@@ -50,14 +51,8 @@ init_pci_device(int bus, int dev, int func)
 		if (devices[d].vendor != vendor
 		 || devices[d].device != device)
 			continue;
-		kprintf("PCI(%d,%d,%d) %s", bus, dev, func,
-		        devices[d].name);
 		if (devices[d].init)
 			devices[d].init(bus, dev, func);
 		return;
 	}
-
-	/* No match */
-	kprintf("PCI(%d,%d,%d) = %#.4x:%#.4x", bus, dev, func,
-	        vendor, device);
 }
diff --git a/drivers/video/bga.c b/drivers/video/bga.c
new file mode 100644
index 0000000..3354d01
--- /dev/null
+++ b/drivers/video/bga.c
@@ -0,0 +1,160 @@
+/*
+ * This file is the driver for the PCI BGA device.  It controls the Bochs
+ * Graphics Adapter card on virtual machines.  It creates a framebuffer device
+ * node in the devfs mount to give access to the rest of the system.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/fb.h>
+#include <fcntl.h>
+#include <io.h>
+#include <nucleus/driver.h>
+#include <nucleus/panic.h>
+#include <nucleus/pci.h>
+#include <nucleus/vfs.h>
+
+/* BGA Register Indicies */
+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_VIRTH_HEIGHT,
+	BGA_INDEX_XOFF,
+	BGA_INDEX_YOFF,
+};
+
+/* Structure for a Video Device */
+struct VideoDev {
+	int width, height, bpp;
+	size_t memSize;
+	uintptr_t lfb;
+};
+
+const uint16_t BGA_LFB = 0x40;
+/* BGA Ports */
+const uint16_t BGA_IO_INDEX = 0x1CE;
+const uint16_t BGA_IO_DATA  = 0x1CF;
+
+size_t bga_dev_write(File *file, char *buf, size_t size, off_t offset);
+int bga_dev_ioctl(File *file, unsigned long request, uintptr_t argp);
+void bga_dev_mmap(File *file, void *addr, size_t len, off_t offset);
+
+/* File Operations for the BGA device nodes */
+FileOps bgaFileOps = {
+	.write = bga_dev_write,
+	.ioctl = bga_dev_ioctl,
+	.mmap = bga_dev_mmap,
+};
+
+static struct VideoDev bgaDev;
+
+/* Write a BGA register */
+static void
+bga_write_register(enum BGAIndex index, uint16_t data)
+{
+	outw(BGA_IO_INDEX, index);
+	outw(BGA_IO_DATA, data);
+}
+
+/* Set the video mode */
+static void
+bga_set_mode(uint32_t width, uint32_t height, uint32_t bpp)
+{
+	bgaDev.width = width;
+	bgaDev.height = height;
+	bgaDev.bpp = bpp;
+	bgaDev.memSize = width * height * (bpp / 8);
+	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 | BGA_LFB);
+}
+
+/* Write to the BGA framebuffer */
+size_t
+bga_dev_write(File *file, char *buf, size_t size, off_t offset)
+{
+	Page *page;
+	char *data;
+	size_t min, count = 0;
+	off_t indent = offset % PAGE_SIZE;
+	off_t pgoff = PAGE_ADDR(offset + count);
+	while (size) {
+		min = (size < PAGE_SIZE) ? size : PAGE_SIZE;
+		page = create_page(file->inode->pages,
+		                   bgaDev.lfb + pgoff, pgoff);
+		data = map_page(page);
+		memcpy(data + indent, buf + count, min);
+		remove(file->inode->pages, page);
+		count += min;
+		size -= min;
+		indent = 0;
+	}
+	return count;
+}
+
+/* Control the BGA device */
+int
+bga_dev_ioctl(File *file, unsigned long request, uintptr_t argp)
+{
+	FBVarInfo *vinfo;
+	FBFixInfo *finfo;
+
+	switch (request) {
+	case FBIOGET_VSCREENINFO:
+		vinfo = (void *) argp;
+		vinfo->xres = bgaDev.width;
+		vinfo->yres = bgaDev.height;
+		vinfo->bpp = bgaDev.bpp;
+		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 = bgaDev.lfb;
+		finfo->fbmemLen = bgaDev.memSize;
+		return 0;
+	}
+}
+
+/* Map the linear frame buffer into memory */
+void
+bga_dev_mmap(File *file, void *addr, size_t len, off_t offset)
+{
+	return;
+}
+
+/* Initialise a PCI BGA device */
+void
+pci_init_bga(uint8_t bus, uint8_t dev, uint8_t func)
+{
+	static int bgaMajor = 0;
+	if (!bgaMajor)
+		bgaMajor = register_driver(2, &bgaFileOps);
+
+	/* Setup device */
+	const int width = 1280;
+	const int height = 720;
+	const int bpp = 32;
+	bga_set_mode(width, height, bpp);
+	bgaDev.lfb = pci_read_dword(bus, dev, func, 0x10) & ~0xF;
+
+	mknod("/dev/fb", S_IFCHR | 0600, MKDEV(bgaMajor, 0));
+
+	uintptr_t ptr;
+	int fd = open("/dev/fb", O_RDONLY);
+	File *file = get(get_file_by_fd(fd));
+	close(fd);
+	for (ptr = 0; ptr < bgaDev.memSize; ptr += PAGE_SIZE)
+		create_page(file->inode->pages, bgaDev.lfb + ptr, ptr);
+}