#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#include <unistd.h>
#include <stropts.h>
#include <string.h>
extern int errno;
volatile unsigned long *memregs32;
volatile unsigned short *memregs16;
int memfd;
void *trymmap (void *start, size_t length, int prot, int flags, int fd, off_t offset)
{
	char *p;
	int aa;
	printf ("mmap(%X, %X, %X, %X, %X, %X) ... ", (unsigned int)start, length, prot, flags, fd, (unsigned int)offset);
	p = mmap (start, length, prot, flags, fd, offset);
	if (p == (char *)0xFFFFFFFF)
	{
  aa = errno;
  printf ("failed. errno = %d\n", aa);
	}
	else
	{
  printf ("OK! (%X)\n", (unsigned int)p);
	}
	return p;
}
unsigned char initphys (void)
{
	memfd = open("/dev/mem", O_RDWR);
	if (memfd == -1)
	{
  printf ("Open failed\n");
  return 0;
	}
	printf ("/dev/mem opened successfully - fd = %d\n", memfd);
	return 1;
}
void closephys (void)
{
	close (memfd);
}
 
#define MESGDSTCTRL 0
#define MESGDSTADDR 1
#define MESGDSTSTRIDE 2
#define MESGSRCCTRL 3
#define MESGSRCADDR 4
#define MESGSRCSTRIDE 5
#define MESGSRCFORCOLOR 6
#define MESGSRCBACKCOLOR 7
#define MESGPATCTRL 8
#define MESGFORCOLOR 9
#define MESGBACKCOLOR 10
#define MESGSIZE 11
#define MESGCTRL 12
#define MESGSTATUS 13
#define MESGFIFOSTATUS 14
#define MESGFIFO 15
#define MESGPAT 32
 
int main(void)
{
	int i, x, y;
	char str[256];
	unsigned short *fb0;
	unsigned int *ac;
	
	if (!initphys()) return 0;
	printf ("Moose!\n");
	sleep (1);
	memregs32 = trymmap(0, 0x10000, PROT_READ|PROT_WRITE, MAP_SHARED, memfd, 0xc0000000);
	if (memregs32 == (unsigned long *)0xFFFFFFFF) return 0;
	memregs16 = (unsigned short *)memregs32;
	fb0 = trymmap(0, 320*240*2, PROT_READ|PROT_WRITE, MAP_SHARED, memfd, 0x3101000);
	if (memregs32 == (unsigned long *)0xFFFFFFFF) return 0;
	ac = trymmap(0, 256, PROT_READ|PROT_WRITE, MAP_SHARED, memfd, 0xE0020000);
	if (ac == (unsigned int *)0xFFFFFFFF) return 0;
	sleep (2);
	// paint the screen redish
	for (i = 0; i < 320*240; i ++) fb0[i] = 0xF800;
	
	// draw a white block in the upper left corner
	for (x = 0; x < 52; x ++)
  for (y = 0; y < 52; y ++)
  	fb0[(y*320)+x] = 0xFFFF;
  	
	// enable all video and graphic devices
	memregs16[0x090a >> 1] = 0xFFFF;
  	
	printf ("...\n");
	
	sleep (1);
	
	printf ("0904 == %04X\n", memregs16[0x0904 >> 1]);
	memregs16[0x0904 >> 1] |= (1 << 10);
	
	sleep (1);
  	
	printf ("Giraffe! (%X)\n", ac[MESGSTATUS]);
	sleep (5);	
	
	printf ("Go! Go! Go!\n");
	ac[MESGDSTCTRL] = 1 << 5;
	ac[MESGDSTADDR] = 0x3105B00;
	ac[MESGDSTSTRIDE] = 67;
	ac[MESGSRCCTRL] = (1 << 8) | (1 << 7) | (1 << 5);
	ac[MESGSRCADDR] = 0x3101000;
	ac[MESGSRCSTRIDE] = 67;
	ac[MESGPATCTRL] = 0;
	ac[MESGSIZE] = (52 << 16) | (52 << 0);
	ac[MESGCTRL] = (1 << 10) | (1 << 9) | (1 << 8) | 0xCC;
	
	printf ("Elephant! (%X)\n", ac[MESGSTATUS]);
	sleep (1);	
	
	ac[MESGDSTCTRL] = 1 << 5;
	ac[MESGDSTADDR] = 0x3105B00;
	ac[MESGDSTSTRIDE] = 67;
	ac[MESGSRCCTRL] = (1 << 8) | (1 << 7) | (1 << 5);
	ac[MESGSRCADDR] = 0x3101000;
	ac[MESGSRCSTRIDE] = 67;
	ac[MESGPATCTRL] = 0;
	ac[MESGSIZE] = (52 << 16) | (52 << 0);
	ac[MESGCTRL] = (1 << 10) | (1 << 9) | (1 << 8) | 0xCC;
	printf ("Sheep! (%X)\n", ac[MESGSTATUS]);
	sleep (1);	
  
	closephys();
	printf("test complete\n");
	return 0;
}