/*
 * Copyright (c) Rene Ladan <r.c.ladan@gmail.com>, 2-claused BSD license
 *
 * biosfont character device
 *
 * Based on 5.X version of echo device, FreeBSD Architecture Handbook
 */

#include "biosfont.h"

#include <sys/systm.h> /* printf, bootverbose */
#include <sys/module.h>
#include <sys/param.h> /* defines used in kernel.h */
#include <sys/kernel.h> /* types used in module initialization */
#include <sys/conf.h> /* cdevsw struct */
#include <sys/stat.h> /* S_Ixxxx */

#include <vm/vm.h> /* required for vm/pmap.h */
#include <vm/pmap.h> /* required for machine/pmap.h */
#include <machine/pmap.h> /* required for vmparam.h */
#include <machine/vmparam.h> /* KERNBASE */

/* Function prototypes */
static d_ioctl_t biosfont_ioctl;

/* Character device entry points */
static struct cdevsw biosfont_cdevsw = {
	.d_version = D_VERSION,
	.d_flags = D_MEM, /* prevent kernel panic */
	.d_name = "biosfont",
	.d_ioctl = biosfont_ioctl,
};

/* Character device */
static struct cdev *biosfont_dev;

/*
 * Addresses are stored as segment:offset, in little endian, thus
 * 0x000ffa6e aka f000:fa6e is stored as 0x6e 0xfa 0x00 0xf0
 * Absolute address is segment * 16 + offset.
 *
 * XXX This define is i386-specific, but there is a rumour that the font
 * bitmaps only exist on i386
 */
#define SEGOFS(i) (((i & 0xffff0000) >> 12) + ((i & 0x0000ffff)))

static u_long fontbase;

/*
 * This function is called by the kld[un]load(2) system calls to
 * determine what actions to take when a module is loaded or unloaded.
 */
static int
biosfont_loader(struct module *m __unused, int what, void *arg __unused)
{
	int err = 0;
	u_long *p; /* "read-only" variable to prevent garbling memory */

	switch (what) {
	case MOD_LOAD: /* kldload */
		p = (u_long *) (KERNBASE + 0x0000007CL);
		/* correct byte order for i386 */
		fontbase = SEGOFS(*p);
		biosfont_dev = make_dev(&biosfont_cdevsw,
			0, /* auto-minor-device */
			UID_ROOT,
			GID_WHEEL,
			S_IRUSR | S_IRGRP | S_IROTH,
			biosfont_cdevsw.d_name);
		if (bootverbose)
			printf("<biosfont>: upper=%08lx\n", fontbase);
		break;
	case MOD_UNLOAD:
		destroy_dev(biosfont_dev);
		break;
	default:
		err = EINVAL;
		break;
	}
	return(err);
}

int
biosfont_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int fflag __unused, struct thread *td __unused)
{
	u_char i;
	u_long start;
	u_char *p;

	t_biosfont *request = (t_biosfont *) data;
	switch (cmd) {
	case BIOSFONT_ASCII:
		/* determine start of bitmap table */
 		start = (u_long) (KERNBASE + request->nr * 8);
		if (request->nr < 0x80)
			start += 0x000FFA6EL;
		else
			start += (u_long) (fontbase - 1024);
		/* copy bitmap to userland */
		for (i = 0; i < 8; i++) {
			p = (u_char *) (start + i);
			request->bitmap[i] = *p;
		}
		return(0);
	default:
		/* should not happen */
		printf("<biosfont>: cmd, nr = %08lx, %02x\n", cmd, request->nr);
		return(EINVAL);
	}
}

DEV_MODULE(biosfont, biosfont_loader, NULL);


syntax highlighted by Code2HTML, v. 0.9.1