 /*
 * interrupt.c
 *
 *  Created on: Apr 30, 2012
 *      Author: xw795
 */

#ifndef MODULE
#define MODULE
#endif

#ifndef __KERNEL__
#define __KERNEL__
#endif

#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <rtai.h>
#include <rtai_sched.h>
#include <linux/time.h>
#include <rtai_fifos.h>

MODULE_LICENSE("GPL");

RT_TASK rttask;
RTIME period;

unsigned long *ptr1, *ptr2;
unsigned long *pfdr, *pfddr;
unsigned long *pbdr, *pbddr;
unsigned long *VIC2IntEnable, *VIC2SoftIntClear;
unsigned long *GPIOBEOI, *GPIOBIntEn;
unsigned long *GPIOBIntType1,*GPIOBIntType2;  // level or edge sensitive
int index;
char buf[3];

static void rt_process(int t)
{
	while(1)
	{
		*pfdr ^= 0x02;
		rt_task_wait_period();

	}
}

static void irq_handler1(unsigned irq, void* cookie)
{
	rt_disable_irq(63);

	rtf_get(1, &buf, sizeof(buf));
	if(strncmp(buf,'T',1)==0)
	{
		index = 10;
	}
	
	if(strncmp(buf, "ABC",3) == 0)
	{
		index = 10000;
	}

	rt_task_make_periodic(&rttask, rt_get_time()+period, index*period);
	*VIC2SoftIntClear = *VIC2SoftIntClear | 0x80000000;

	rt_enable_irq(63);

}

static void irq_handler2(unsigned irq, void* cookie)
{
	rt_disable_irq(59);

	if(*pbdr == 0x1E)
	{
			index = 10000;
	}

	rt_task_make_periodic(&rttask, rt_get_time()+period, index*period);

	*GPIOBEOI = *GPIOBEOI | 0x1F;
	rt_enable_irq(59);
}


int init_module(void)
{
	int retval1, retval2;

	ptr1 = (unsigned long *) __ioremap(0x80840000, 4096, 0);

	pfdr = ptr1 + 0x0c;   // offsets to port F
	pfddr = ptr1 + 0x0d;
	*pfddr = *pfddr | 0x02;  // set I/O of port F
	*pfdr = *pfdr | 0x02;   // set bit 1 of port F high

	pbdr = ptr1 + 0x01;   // offsets to port B
	pbddr = ptr1 + 0x05;
	*pbddr = *pbddr | 0xE0;       // set I/O of port B

	GPIOBIntEn = ptr1 + 0x2E;  // 0x8084_00B8 ->  Port B interrupt
	GPIOBEOI = ptr1 + 0x2D;   // 0x8084_00B4  ->  Port B interrupt
	GPIOBIntType1 = ptr1 + 0x2B;   // 0x8084_00AC  ->  Port B interrupt
	GPIOBIntType2 = ptr1 + 0x2C;     // 0X8084_00B0 -> Port B interrupt

	*GPIOBIntEn = *GPIOBIntEn | 0x1F;   // enable the interrupt of Port B
	*GPIOBIntType1 = *GPIOBIntType1 | 0x1F; // edge sensitive
	*GPIOBIntType2 = *GPIOBIntType2 & 0xFFFFFFE0; // falling sensitive

	ptr2 = (unsigned long *) __ioremap(0x800C0000, 4096, 0);
	VIC2IntEnable = ptr2 + 0x04;    // 0x800c_0010 software interrupt
	VIC2SoftIntClear = ptr2 + 0x07;  // 0x800c_001c

	*VIC2IntEnable = *VIC2IntEnable | 0x80000000;

	rt_set_periodic_mode();
	period= start_rt_timer(nano2count(100000));     // start timer
	retval1=rt_task_init(&rttask, rt_process,0,1000,0,0,0);

	if(retval1 !=0)     // check the establishing of real-time task
	{
		printk("Fail to create realtime task\n");
	}

	rt_task_make_periodic(&rttask, rt_get_time()+period, 10000*period);

	retval2=rtf_create(1,100);

	if(retval2 !=0)   // check fifo 0
	{
		printk("Fail to create fifo\n");
	}

	rt_request_irq(63, irq_handler1, NULL ,1);

	rt_enable_irq(63);

	rt_request_irq(59, irq_handler2, NULL ,1);

	rt_enable_irq(59);

	return 0;
}


void cleanup_module(void)    // remove function
{
	*VIC2SoftIntClear = *VIC2SoftIntClear | 0x80000000;
	*GPIOBEOI = *GPIOBEOI | 0x1F;
	rt_task_delete(& rttask);
	rt_disable_irq(63);
	rt_release_irq(63);
	rt_disable_irq(59);
	rt_release_irq(59);
	stop_rt_timer();

}

