#include "io.h"
#include "driver.h"

static void x_interrupt_cleanup(void *arg)
{
	InterruptDetach((int)arg);
}

static void * x_interrupt_thread(void *args)
{
	snd_irq_t *irq = (snd_irq_t *)args;
	struct sigevent	event;
		
	memset(&event, 0, sizeof(event));
	event.sigev_notify = SIGEV_INTR;
	irq->id = InterruptAttachEvent(irq->irq, &event, _NTO_INTR_FLAGS_TRK_MSK );
	pthread_cleanup_push(x_interrupt_cleanup, (void *)irq->id);
	while(1) {
		InterruptWait(0, NULL);
		irq->handler(irq->dev_id);		
		InterruptUnmask(irq->irq, irq->id);
	}
	pthread_cleanup_pop(1);
}

static int x_attach_interrupts(snd_irq_t *irqptr)
{
	int policy, err;
	pthread_attr_t attr;
	struct sched_param param;

    pthread_attr_init( &attr );
	pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED );
	pthread_getschedparam(pthread_self(), &policy, &param);
	param.sched_priority += 5;
	pthread_attr_setschedparam( &attr, &param );
	pthread_attr_setschedpolicy( &attr, SCHED_RR );
   
	if ((err = pthread_create( &irqptr->tid, &attr, x_interrupt_thread, irqptr )) != EOK ) {
		snd_printk("unable to attach IRQ %i for %s (%s)\n", irqptr->irq, irqptr->name, strerror(err));
		return -err;
	}
	return 0;
}

void snd_enable_irq(snd_irq_t *irq)
{
	if ( irq->id == 0 ) {
		if ( x_attach_interrupts(irq) == 0 ) {
			InterruptUnmask(irq->irq, irq->id);
			snd_printd("IRQ %d Enabled - %d\n",irq->irq, irq->id);
		}
	}
}

void snd_disable_irq(snd_irq_t *irq)
{
	InterruptMask(irq->irq, irq->id);
	snd_printd("IRQ %d Disabled - %d\n", irq->irq, irq->id);
}

