/*
 * sp.c
 *
 * Copyright 2002, Minoru Murashima. All rights reserved.
 * Distributed under the terms of the BSD License.
 *
 * シングルプロセッサシステムの初期化
 */


#include"types.h"
#include"config.h"
#include"lib.h"
#include"interrupt.h"
#include"time.h"
#include"sp.h"


enum{
	BEGIN_VECT=0x20		/* 割り込みベクタの開始番号 */
};


static void release_pic_mask(uchar);
static void init_pic();
static int task_handler();
static void sp_eoi(uchar);
static void release_pic_mask(uchar);
static void set_pic_mask(uchar);


/*
 * IRQ0割り込みハンドラー
 * spシステムのタスキングを行う
 * returns : Task switch on
 */
int task_handler()
{
/*******************************************/
	{
		static char value[MAX_CPU]={0,0,0,0};
		char *p=(char*)(0xb8000+80);
		int cpu;

		cpu=get_current_cpu();
		*(p+cpu*2)=(++value[cpu]%10)+'0';
	}
/********************************************/

	return 1;
}


/*
 * ハード割り込み用EOI関数
 */
void sp_eoi(uchar irq)
{
	if(irq<8)outb(OCW2M,irq|0x20);
	else
	{
		outb(OCW3S,0xa);	/* Read ISR */
		if(inb(0xa0))outb(OCW2S,(irq-8)|0x20);
		else
		{
			outb(OCW2S,(irq-8)|0x20);
			outb(OCW2M,2|0x20);
		}
	}
}


/*
 * Release interrupt mask
 * parameters : IRQ number
 */
void release_pic_mask(uchar irq)
{
	if(irq<8)
		outb(OCW1M,inb(OCW1M)&~(1<<irq));
	else
		outb(OCW1S,inb(OCW1S)&~(1<<(irq-8)));
}


/*
 * Set interrupt mask
 * parameters : IRQ number
 */
void set_pic_mask(uchar irq)
{
	if(irq<8)
		outb(OCW1M,inb(OCW1M)|(1<<irq));
	else
		outb(OCW1S,inb(OCW1S)|(1<<(irq-8)));
}


/********************************************************************************************************
 *
 * 初期化
 *
 *********************************************************************************************************/


/*
 * SPシステムの初期化
 * 返り値 : 通常 0、エラー -1
 */
int init_sp()
{
	/* PICを初期化する */
	init_pic();

	/* タスキングの初期化 */
	init_sp_task();

	/* ハード割り込みのEOI関数を設定する */
	irq_eoi=sp_eoi;

	/* ハード割り込みマスク解除関数,マスク関数を設定する */
	release_irq_mask=release_pic_mask;
	set_irq_mask=set_pic_mask;

	release_pic_mask(0);

	return 0;
}


/*
 * PICを初期化する
 */
void init_pic()
{
	/* picの初期化 */
	outb(ICW1M,0x11);			/* cascade mode */
	outb(ICW1S,0x11);			/* ICW1 slave */
	outb(ICW2M,BEGIN_VECT);		/* begin master interrupt from 0x20 */
	outb(ICW2S,BEGIN_VECT+8);	/* begin slave interrupt from 0x28 */
	outb(ICW3M,0x04);			/* IR2(2bit) slave connect */
	outb(ICW3S,0x02);			/* slave connect IR-number */
	outb(ICW4M,0x11);			/* 80x86 mode,SFN mode, */
	outb(ICW4S,0x01);			/* 80x86 mode,Normal EOI */
	outb(OCW1M,0xfb);			/* Mask of all IRQ except IRQ2 */
	outb(OCW1S,0xff);			/* Mask of all IRQ */

	/* idtを設定する */
	set_idt(BEGIN_VECT,irq0,IDT_TRAP);
	set_idt(BEGIN_VECT+1,irq1,IDT_TRAP);
	set_idt(BEGIN_VECT+3,irq3,IDT_TRAP);
	set_idt(BEGIN_VECT+4,irq4,IDT_TRAP);
	set_idt(BEGIN_VECT+5,irq5,IDT_TRAP);
	set_idt(BEGIN_VECT+6,irq6,IDT_TRAP);
	set_idt(BEGIN_VECT+7,irq7,IDT_TRAP);
	set_idt(BEGIN_VECT+8,irq8,IDT_TRAP);
	set_idt(BEGIN_VECT+9,irq9,IDT_TRAP);
	set_idt(BEGIN_VECT+10,irq10,IDT_TRAP);
	set_idt(BEGIN_VECT+11,irq11,IDT_TRAP);
	set_idt(BEGIN_VECT+12,irq12,IDT_TRAP);
	set_idt(BEGIN_VECT+13,irq13,IDT_TRAP);
	set_idt(BEGIN_VECT+14,irq14,IDT_TRAP);
	set_idt(BEGIN_VECT+15,irq15,IDT_TRAP);
}


/*
 * タスキングの初期化をする
 * parameters : 時間(ms)
 */
void init_sp_task()
{
	outb(PIT_CTR,0x34);								/* CLK0,LSB.MSB,モード2,binary */
	outb(PIT_CNR0,(PIT_HZ/(1000/TASK_TIME))&0xff);	/* LSB */
	outb(PIT_CNR0,(PIT_HZ/(1000/TASK_TIME))>>8);	/* MSB */

	irq_entry[IRQ0]=task_handler;
}
