BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / blob / 1628fcfdfdf2978ed9ccac96ee7d13bb3dc43a01 / drivers / vga / bga.c

// Related

Orion

Barry Keyboard/Mouse drivers + POSIX names for structs 1628fcf (2 years, 4 months ago)
/*
 * 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);
void bga_mmap(File *file, void *addr, size_t len, off_t offset);

FileOps bgaFileOps = {
	.write = bga_write,
	.ioctl = bga_ioctl,
	.mmap = bga_mmap,
};

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;
	}
}

/* Map the linear frame buffer into memory */
void
bga_mmap(File *file, void *addr, size_t len, off_t offset)
{
	if (offset >= bgaWidth*bgaHeight*(bgaBpp/8))
		return;
	if (len + offset > bgaWidth*bgaHeight*(bgaBpp/8))
		len = (bgaWidth*bgaHeight*(bgaBpp/8)) - offset;

	page_t *pg, new;
	size_t max, count = 0;
	while (len) {
		max = (len < 0x1000) ? len : 0x1000;
		pg = get_page(addr + count);
		new = PG_ATTR(*pg);
		free_page(pg);
		alloc_page(pg, PG_ATTR(new), 0xFD000000 + offset + count);
		count += max;
		len -= max;
	}
}