/****************************************************************************
 * os_abstr_time.h
 *
 * Author:
 *
 * ==========================================================================
 * July 17, 2010 		Initial Version
 ****************************************************************************
 */

#ifndef	__OS_ABSTR_TIME_H
# define __OS_ABSTR_TIME_H

#if defined(OS_KERNEL)

#if defined(__Linux__)
typedef struct timer_list	os_timer_info_t;
typedef void 			(os_timer_func_t)(unsigned long);
typedef unsigned long		os_timer_arg_t;
#elif defined(__FreeBSD__)
typedef struct callout_handle	os_timer_info_t;
typedef timeout_t		os_timer_func_t;
typedef void*			os_timer_arg_t;
#elif defined(__OpenBSD__)
typedef struct timeout		os_timer_info_t;
typedef void 			(os_timer_func_t)(void*);
typedef void*			os_timer_arg_t;
#elif defined(__NetBSD__)
typedef struct callout		os_timer_info_t;
typedef void 			(os_timer_func_t)(void*);
typedef void*			os_timer_arg_t;
#endif

/*
** TIMER structure
*/
#if !defined(__WINDOWS__)
typedef struct _os_timer
{
#define NDIS_TIMER_TAG 0xBEEF0005
	unsigned long           Tag;
	os_timer_func_t		*MiniportTimerFunction;
	void *                  MiniportTimerContext;
	void *                  MiniportAdapterHandle;
	os_timer_info_t		timer_info;
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
	os_timer_func_t		*timer_func;
#endif
	void*			timer_arg;
} os_timer_t;
#endif


static __inline int os_getcurrenttime(os_time_t *sec, os_suseconds_t *usec)
{
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
	struct timeval 	tv;
	microtime(&tv);
	if (sec) *sec = tv.tv_sec;
	if (usec) *usec = tv.tv_usec;
	return 0;
#elif defined(__Linux__)
	struct timeval 	tv;
	do_gettimeofday(&tv);
	if (sec) *sec = tv.tv_sec;
	if (usec) *usec = tv.tv_usec;
	return 0;
#elif defined(__WINDOWS__)
	struct timeval 	tv;
	do_gettimeofday(&tv);
	if (sec) *sec = tv.tv_sec;
	if (usec) *usec = tv.tv_usec;
	return 0;
#else
# error "wan_getcurrenttime() function is not supported yet!"
#endif
}

/*
** os_init_timer
*/
static __inline void
os_init_timer(os_timer_t* tm, os_timer_func_t *func, os_timer_arg_t arg)
{
#if defined(__Linux__)
	init_timer(&tm->timer_info);
	tm->timer_info.function = func;
	tm->timer_info.data = arg;
#elif defined(__FreeBSD__)
	/* FIXME_ADSL_TIMER */
	callout_handle_init(&tm->timer_info);
	tm->timer_func = func;
	tm->timer_arg  = arg;
#elif defined(__OpenBSD__)
	timeout_set(&tm->timer_info, func, (void*)arg);
	tm->timer_func = func;
	tm->timer_arg  = arg;
#elif defined(__NetBSD__)
	callout_init(&tm->timer_info);
	tm->timer_func = func;
	tm->timer_arg  = arg;
#elif defined(__WINDOWS__)
	tm->timer_func = func;
	tm->timer_arg  = arg;
	KeInitializeDpc(&tm->timer_info.TimerDpcObject,
			tm->timer_func, tm->timer_arg);
	KeInitializeTimer(&tm->timer_info.Timer);
#else
# error "os_init_timer() function is not supported yet!"
#endif /* linux */
}

/*
** os_del_timer
*/
static __inline void
os_del_timer(os_timer_t* tm)
{
#if defined(__Linux__)
	if (!tm->timer_info.function){
		DEBUG_EVENT("Warning[%s:%d]: Timer del error: func=%p\n",
				__FUNCTION__,__LINE__,
				tm->timer_info.function);
		return;
	}
	del_timer(&tm->timer_info);
#elif defined(__FreeBSD__)
	untimeout(tm->timer_func,
		  (void*)tm->timer_arg, 
		  tm->timer_info);
	callout_handle_init(&tm->timer_info);
#elif defined(__OpenBSD__)
	timeout_del(&tm->timer_info);
#elif defined(__NetBSD__)
	callout_stop(&tm->timer_info);
#elif defined(__WINDOWS__)
	KeCancelTimer(&tm->timer_info.Timer);
#else
# error "os_del_timer() function is not supported yet!"
#endif /* linux */
}

/*
** os_add_timer
*/
static __inline int 
os_add_timer(os_timer_t* tm, unsigned long delay_ms)
{
	int delay	= (delay_ms * HZ) / 1000;

#if defined(__Linux__)
	if (timer_pending(&tm->timer_info) ||
	    !tm->timer_info.function){
		DEBUG_EVENT("Warning[%s:%d]: Timer add error: pending or func=%p\n",
				__FUNCTION__,__LINE__,
				tm->timer_info.function);
		return -EINVAL;
	}
    	tm->timer_info.expires = OS_SYSTEM_TICKS + delay;
    	add_timer(&tm->timer_info);
#elif defined(__FreeBSD__)
	tm->timer_info = 
			timeout(tm->timer_func,
				(void*)tm->timer_arg, 
				delay);
	OS_ASSERT(tm->timer_info.callout == NULL);
#elif defined(__OpenBSD__)
	timeout_add(&tm->timer_info, delay);
#elif defined(__NetBSD__)
	tm->timer_info.c_time = delay;
	callout_reset(&tm->timer_info,
			delay,
			tm->timer_func,
			tm->timer_arg); 
#elif defined(__WINDOWS__)
	LARGE_INTEGER	CurrentTime;

	/* The 'delay' is in SYSTEM TICKS! */

	/* 10 000 000
	 * System time is a count of 100-nanosecond intervals
	 * since January 1, 1601. System time is typically
	 * updated approximately every ten milliseconds. (on Intel 32bit) */
	KeQuerySystemTime(&CurrentTime);

	CurrentTime.QuadPart = CurrentTime.QuadPart + delay * KeQueryTimeIncrement();

	KeSetTimer(&tm->timer_info.Timer, CurrentTime,
			&tm->timer_info.TimerDpcObject);

#else
# error "os_add_timer() function is not supported yet!"
#endif /* linux */
	return 0;
}





#endif  /* OS_KERNEL */
#endif	/* __OS_ABSTR_TIME_H */
