#include "event.h"
#include "interrupt.h"
#include "types.h"
#include "log.h"

event_handler *event_handler_table[EVENT_MAX+1];

#define EVENT_WORDS ((EVENT_MAX+1+31)/32)

unsigned int event_pending[EVENT_WORDS];

#define EVENT_WORDLEN	32
#define EVENT_WORD(x)	(x/EVENT_WORDLEN)
#define EVENT_BIT(x)	(x%EVENT_WORDLEN)
#define EVENT_MASK(x)	(1<<EVENT_BIT(x))

/*
 * This function must be called with interrupts disabled.
 * This will normally be the case as it is typically called from within
 * an interrupt handler anyway.
 */

void event_set(unsigned int event)
{
	if (event > EVENT_MAX)
		return;

	event_pending[EVENT_WORD(event)] |= EVENT_MASK(event);
}

static int bitset(unsigned int x)
{
	x = 0xffffffff - (x-1);
	x = x - ((x >> 1) & 0x55555555);
	x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
	x = (x + (x >> 4)) & 0x0F0F0F0F;
	x = x + (x << 8);
	x = x + (x << 16);
	return 32 - (x >> 24);
}

bool event_get(unsigned int *event)
{
	int i;
	unsigned int p;

	for (i = 0; i < EVENT_WORDS; i++) {
		if ((p = event_pending[i]) != 0) {
			p = p & (-p);
			*event = bitset(p) + EVENT_WORDLEN*i;
			return TRUE;
		}
	}
	return FALSE;
}

void event_clear(unsigned int event)
{
	interrupt_block();
	event_pending[EVENT_WORD(event)] &= ~EVENT_MASK(event);
	interrupt_unblock();
}

bool event_dispatch(void)
{
	unsigned int event;

	if (event_get(&event)) {
		event_clear(event);
		if (event_handler_table[event] != NULL) {
			log_mark_busy();
			(event_handler_table[event])();
			log_mark_idle();
		}
		return TRUE;
	}

	return FALSE;
}

void event_register(unsigned int event, event_handler *handler)
{
	if (event > EVENT_MAX)
		return;
	event_handler_table[event] = handler;
}
