#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <dev/wscons/wsconsio.h>
#include <sys/mman.h>
#include <stdio.h>

struct {
	int wstype;
	char *module;
	int fbsize;
	int fboff;
} tclist[] = {
/*	{ 1,  "pmax mono",  0x100000, 0 },	*/
	{ 2,  "pmax color", 0x100000, 0 },
	{ 3,  "PMAG-B",	    0x100000, 0 },
	{ 4,  "PMAG-DV",    0x100000, 0 },
/*	{ 5,  "PMAG-A",	    0x200000, 0 },	*/
	{ 6,  "PMAGB-B",    0x200000, 0x201000 },
	{ 15, "PMAG-J",	    0x200000, 0 },
};
	
main(argc, argv)
	int argc;
	char *argv[];
{
	int ws, rv, i, j;
	size_t mapsize;
	off_t mapoff;
	char *wsdisplay;
	caddr_t base;
	u_int32_t *p;
	u_char color;
	u_char ocolor[3];
	struct wsdisplay_cmap cmap;
	struct wsdisplay_fbinfo fbi;
	struct winsize win;

	wsdisplay = (argc == 2) ? argv[1] : "/dev/ttyE0";
	ws = open(wsdisplay, 2);
	if (ws < 0) {
		perror(wsdisplay);
		exit(1);
	}
	if (ioctl(ws, WSDISPLAYIO_GTYPE, &rv) < 0) {
		perror("WSDISPLAY_GTYPE");
		exit(1);
	}
	for (i = 0; i < sizeof(tclist)/sizeof(tclist[0]); i++) {
		if (tclist[i].wstype == rv)
			goto found;
	}
	printf("Unknown display type %d\n", rv);
	exit(1);
found:
	printf("%s ", tclist[i].module);
	mapsize = tclist[i].fbsize;
	mapoff = tclist[i].fboff;

	ioctl(ws, TIOCGWINSZ, &win);
	ioctl(ws, WSDISPLAYIO_GINFO, &fbi);
	printf("row %d col %d emulation with %d x %d screen (%d x %d)\n",
		win.ws_row, win.ws_col, win.ws_xpixel, win.ws_ypixel,
		fbi.width, fbi.height);

	rv = WSDISPLAYIO_MODE_MAPPED;
	if (ioctl(ws, WSDISPLAYIO_SMODE, &rv) == -1)
		perror("WSDISPLAYIO_SMODE");

	base = mmap(0, mapsize, PROT_READ|PROT_WRITE, MAP_PRIVATE, ws, mapoff);
	if (base == MAP_FAILED) {
		perror("mmap MAP_PRIVATE");
		base = mmap(0, mapsize, PROT_READ|PROT_WRITE, MAP_SHARED, ws, mapoff);
		if (base == MAP_FAILED) {
			perror("mmap MAP_SHARED");
			exit(1);
		}
	}

	for (i = 0; i < fbi.height; i++) {
		p = (u_int32_t *)(base + i * fbi.width);
		for (j = 0; j < fbi.width / sizeof(u_int32_t); j++)
			*p++ = 0x01010101;
	}

	cmap.index = 1;
	cmap.count = 1;
	cmap.red = &ocolor[0];
	cmap.green = &ocolor[1];
	cmap.blue = &ocolor[2];
	ioctl(ws, WSDISPLAYIO_GETCMAP, &cmap);

	cmap.red = cmap.green = cmap.blue = &color;
	for (i = 7; i < 256; i += 8) {
		color = i;
		ioctl(ws, WSDISPLAYIO_PUTCMAP, &cmap);
		usleep(50000);
	}
	for (i = 255; i >= 0; i -= 8) {
		color = i;
		ioctl(ws, WSDISPLAYIO_PUTCMAP, &cmap);
		usleep(50000);
	}

	p = (u_int32_t *)base;
	for (i = 0; i < mapsize / sizeof(u_int32_t); i++)
		*p++ = 0;

	cmap.red = &ocolor[0];
	cmap.green = &ocolor[1];
	cmap.blue = &ocolor[2];
	ioctl(ws, WSDISPLAYIO_PUTCMAP, &cmap);

	rv = WSDISPLAYIO_MODE_EMUL;
	if (ioctl(ws, WSDISPLAYIO_SMODE, &rv) == -1)
		perror("WSDISPLAYIO_SMODE");

	close(ws);
	exit(0);
}