/*
 * Copyright (C) 2002 Luca Abeni
 * This is Free Software; see GPL.txt for details
 */

#include <linux/config.h>
#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
#define MODVERSIONS
#endif
#ifdef MODVERSIONS
#include <linux/modversions.h>
#endif
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/sched.h>

#include <timers.h>
#include <time.h>

#include <linux/hrtime.h>

#define __PROFILE__

void sched_timeout(unsigned long arg)
{
  struct t_data_struct *tdata;
  unsigned long long int time;
#ifdef __PROFILE__
  long long int t;
  static long long int max_t = 0, min_t = 0;
  static int n = 0;
#endif
  
  time = sched_read_clock();
#ifdef __DEBUG__
  printk("Wakeup: %Ld\n", time);
#endif
  tdata = (struct t_data_struct *) arg;
#ifdef __PROFILE__
  t = time - (tdata->requested_interval + tdata->start_time);
  if (t > max_t) {
    max_t = t;
  }
  if (t < min_t) {
    min_t = t;
  }
  if (n++ > 50) {
    printk("Have to sleep for %Lu, slept %Lu.    Skew: %Ld [%Ld %Ld]\n",
		  tdata->requested_interval, time - tdata->start_time,
		  t, min_t, max_t);
    n = 0;
  }
#endif

  tdata->callback(time, tdata->param);
}

void sched_init_timer(struct t_data_struct *tdata)
{
  init_timer(&tdata->timer);
}

void sched_stop_timer(struct t_data_struct *tdata)
{
    del_timer_sync(&(tdata->timer));
}

void sched_set_timer(unsigned long long int t, struct t_data_struct *tdata)
{
  tdata->timer.expires = jiffies;
  tdata->timer.sub_expires = sub_jiffie();

  tdata->timer.sub_expires += t;
  while (tdata->timer.sub_expires >= cycles_per_jiffies) {
    tdata->timer.expires++;
    tdata->timer.sub_expires -= cycles_per_jiffies;
  }

#ifdef __DEBUG__
  printk("[%Ld]     %ld --- %ld %ld\n",
		  sched_read_clock(),
		  jiffies, tdata->timer.expires,
		  tdata->timer.sub_expires);
#endif

  tdata->timer.data = (unsigned long)tdata;
  tdata->timer.function = sched_timeout;
#ifdef __PROFILE__
  tdata->start_time = sched_read_clock();
  tdata->requested_interval = t;
#endif
  add_timer(&(tdata->timer));
}
