/**************************************************************************************
$Id: schedule.c,v 1.12 2002/04/20 11:52:03 reddawg Exp $


**************************************************************************************/

#include <ubixos/schedule.h>
#include <ubixos/io.h>
#include <ubixos/video.h>
#include <ubixos/gdt.h>
#include <mm/paging.h>
#include <temp.h> //just temp

int currentProc;

struct taskStruct taskList[NO_TASKS];
struct taskStruct *_current,*_usedMath = 0x0;

extern union DT_entry GDT[7];

void initScheduler(void) {
  int i;
  for (i=0;i<NO_TASKS;i++) {
    taskList[i].id = i;
    taskList[i].status = AVAILABLE;
    taskList[i].usedMath = 0;
    }
  currentProc = -1;
  }

/* Finds A Free Task */
int findTask() {
  int i;
  for (i=0;i<NO_TASKS;i++) {
    if (taskList[i].status == AVAILABLE) {
      return(i);
      }
    }
  return(-1);
  }

void schedule() {
  int i,proc = -1,memAddr;
  outportb(0x20, 0x20);
  for (i=currentProc;i<NO_TASKS;i++) {
    if (taskList[i].status == RUNABLE) {
      proc = i;
      break;
      }
    else if ((taskList[i].status == ACTIVE) && (i != currentProc)) {
      proc = i;
      break;
      }
    if (i+1 >= NO_TASKS) { i = -1; }
    }
  if (proc != -1) {
    currentProc = proc;
    _current = &taskList[proc];
    taskList[proc].status = ACTIVE;
    memAddr = (unsigned int)&taskList[proc].tss;
    GDT[4].desc.access = 0x89;
    GDT[4].desc.base_low = (memAddr & 0xFFFF);
    GDT[4].desc.base_med = ((memAddr >> 16) & 0xff);
    GDT[4].desc.base_high = (memAddr >> 24);
    asm("ljmp $0x20,$0\n");
    }
  }



/* Timer Interupt */
asm (
  ".globl timerINT         \n"
  "timerINT:               \n"
  "  pusha                 \n"
  "  call schedule         \n"
  "  popa                  \n"
  "  iret                  \n"
  );
