#include <linux/module.h>
#include <rtai.h>
#include <rtai_sched.h>
#include <rtai_sem.h>
#include <rtai_msg.h>

#define STACK_SIZE 4096
#define TIMERTICKS 100000000 /*  .1 second */
#define HIGH_PRIO 10
#define MEDIUM_PRIO 100
#define LOW_PRIO 200

static RT_TASK task_l, task_m, task_h;

SEM flag;
RTIME tick_period;
int interrupt_count = 0;

static void led_on(int n)
{
	outb(inb(0x378)|(1 << n), 0x378);
}
static void led_off(int n)
{
	outb(inb(0x378) & ~(1 << n), 0x378);
}
static void irq7_handler(void)
{
	interrupt_count++;
	rt_task_resume(&task_m);
}
/* Highest priority */
static void taskh_code(int t)
{
	led_on(3);
	rt_sem_wait(&flag);
	led_off(3);
	rt_sem_signal(&flag);

}
/* Medium Priority */
static void taskm_code(int t)
{
	int i;
	rt_task_suspend(rt_whoami());
	for(i = 0; i < 10; i++){
		rt_busy_sleep(1000000000);
	}
	
}
/* Low priority */
static void taskl_code(int t)
{
	rt_sem_wait(&flag);
	rt_sleep(10*tick_period);
	rt_sleep(10*tick_period);
	rt_sem_signal(&flag);
}
int init_module(void)
{
	RTIME  now;
	
	rt_sem_init(&flag, 1);
	rt_set_periodic_mode();
	outb(0x0, 0x378);
	rt_request_global_irq(7, irq7_handler);
	rt_enable_irq(7);
	outb(inb(0x37a)|0x10, 0x37a);

	rt_task_init(&task_h, taskh_code, 0, STACK_SIZE, HIGH_PRIO, 0, 0);
	rt_task_init(&task_m, taskm_code, 0, STACK_SIZE, MEDIUM_PRIO, 0, 0);
	rt_task_init(&task_l, taskl_code, 0, STACK_SIZE, LOW_PRIO, 0, 0);

	tick_period = start_rt_timer(nano2count(TIMERTICKS));
	now = rt_get_time();
	rt_task_make_periodic(&task_l, now+tick_period, tick_period);
	rt_task_make_periodic(&task_h, now+2*tick_period, tick_period);
	rt_task_make_periodic(&task_m, now+3*tick_period, tick_period);
	return 0;
}
void cleanup_module(void)
{
	stop_rt_timer();
	rt_busy_sleep(10000000);
	rt_sem_delete(&flag);
	outb(inb(0x37a)&~0x10, 0x37a);
	rt_free_global_irq(7);
	rt_task_delete(&task_l);
	rt_task_delete(&task_m);
	rt_task_delete(&task_h);
	rt_printk("interrupt_count: %d\n", interrupt_count);
}
