/*
 *  framebuffer.c
 */


#include <std.h>
#include "mailbox.h"
#include "tokliBIOS.h"
#include <string.h>

#define MBUF_LENGTH                     0x1000 // multiple of 2k words

struct col {
	Uns bg;
	Uns fg;
} col[8] = {
	{ 0xf800, 0xffff }, /* red */
	{ 0x07e0, 0xffff }, /* green */
	{ 0x001f, 0xffff }, /* blue */
	{ 0xffe0, 0x0000 }, /* yellow */
	{ 0x07ff, 0x0000 }, /* cyan */
	{ 0xf81f, 0x0000 }, /* magenta */
	{ 0xffff, 0x0000 }, /* white */
	{ 0x0000, 0xffff }, /* black */
};

struct fbinfo {
	Void *adr;
	Uns width;
	Uns height;
	Uns bpp;
	Uns pad;
};

struct fbinfo fbinfo = {
	(Void *)0x80000,	/* adr */
	100,			/* width */
	100,			/* height */
	16			/* bpp */
};

struct framebuffer_udata {
    unsigned char *shared_memory;
    unsigned short shared_memory_length;
    struct fbinfo *fbinfo;
};

#pragma DATA_SECTION(shmem, "sharedmem_mmap_buffer");
static unsigned char shmem[MBUF_LENGTH/2]; /* halve this as then it's the same length as the ARM side */

#pragma DATA_SECTION(fbmem, "fb_section");
static unsigned char fbmem[384000];

static struct framebuffer_udata udata = { shmem,  MBUF_LENGTH,  &fbinfo};

static struct mmap_info framebuffer_mmap_info = {
       &shmem, // start
       MBUF_LENGTH // length
};

#define OMAP_DSP_MBCMD_FBCTL_UPD	0x0000

/* signalled by the ARM that we have a message */
static Uns rcv_wdsnd(struct dsptask *task, Uns data)
{
    /* data is ready for us to process */
    struct framebuffer_udata *udata = task->udata;
    unsigned char *shmem;
	Uns x, y;

    shmem = udata->shared_memory;
    
    if (data==0)
    {
    	// grab the fbinfo struct
    	memcpy(&fbinfo, shmem, sizeof(struct fbinfo));
    	fbinfo.adr = &fbmem;
    	return 0;
    }
    
    
	// lock the framebuffer
	fb_lock();
	/* BPP = 16 */
	for (y = 0; y < fbinfo.height; y++) {
		for (x = 0; x < fbinfo.width; x++) {
			*(Uns *)((LgUns)fbinfo.adr +
				 (LgUns)fbinfo.width * y + x) = col[data].bg;
		}
	}

	// release the framebuffer
	fb_unlock();
	
	// see if this will do an update!
	kfunc(MBCMD_KFUNC_FBCTL, OMAP_DSP_MBCMD_FBCTL_UPD, 0, 0);
    return 0;
}


static Uns rcv_tctl(struct dsptask *task, Uns ctlcmd, Uns *ret, Uns arg)
{
        struct framebuffer_udata *udata = task->udata;
	switch (ctlcmd) {
		case MBCMD_TCTL_TINIT:
                    memset(udata->shared_memory, 0xdead, MBUF_LENGTH/2);
                    //wdsnd(task, 0);
                    return 0;
		case MBCMD_TCTL_TCLR:
		case MBCMD_TCTL_TKILL:
			/*
			 * cleanup code here
			 */
			return 0;
		default:
			return MBCMD_EID_BADTCTL;
	}
}

#pragma DATA_SECTION(task_framebuffer, "dspgw_task")
struct dsptask task_framebuffer = {
	TID_MAGIC,	/* tid */
	"framebuffer",	/* name */
	MBCMD_TTYP_WDDM | MBCMD_TTYP_WDMD |
	MBCMD_TTYP_ASND | MBCMD_TTYP_PRCV,
			/* ttyp: active word snd, passive word rcv */
	rcv_wdsnd,	/* rcv_snd - this is called when a message comes from the ARM side */
	NULL,		/* rcv_req */
	rcv_tctl,	/* rcv_tctl */
	NULL,		/* tsk_attrs */
	&framebuffer_mmap_info,	/* mmap_info */
	&udata		/* udata */
};



