view gsm-fw/gpf/osl/os_tim_ir.c @ 468:6389bfe95f23

os_tim_ir.c: os_StartTimer(): polish
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Thu, 26 Jun 2014 06:15:10 +0000
parents aa9aec3ba437
children 5031958cea52
line wrap: on
line source

/*
 * This C module is a reconstruction based on the disassembly of
 * os_tim.obj in frame_na7_db_ir.lib from the Leonardo package.
 */

/* set of included headers from COFF symtab: */
#include <stdio.h>
#include "gpfconf.h"	/* FreeCalypso addition */
#include "../../nucleus/nucleus.h"
#include "typedefs.h"
#include "os.h"
#include "gdi.h"
#include "os_types.h"
#include "os_glob.h"

extern T_OS_TIMER_ENTRY TimerTable[];
extern T_OS_TIMER_TABLE_ENTRY *p_list[];

extern unsigned os_time_to_tick_multiplier;
extern unsigned os_tick_to_time_multiplier;

extern unsigned t_start_ticks;
extern T_OS_TIMER_TABLE_ENTRY * volatile t_running;
extern int used_timers;
extern int next_t_handle;
extern int volatile t_list_access;
extern int max_used_timers;
extern NU_SEMAPHORE TimSemCB;
extern NU_TIMER os_timer_cb;

void
timer_error(int err)
{
}

/*
 * The following function reconstructions have been contributed by Das Signal.
 * The code passes gcc, but some polish is still likely needed.
 */

void
os_Timeout(UNSIGNED t_handle)	/* argument is unused */
{
	ULONG s_ticks;
	OS_HANDLE task_handle, e_handle;
	USHORT t_index;
	int i, done;
	T_OS_TIMER_TABLE_ENTRY **t_r4;
	T_OS_TIMER_TABLE_ENTRY *timer;
	void (*timeout_func) (OS_HANDLE, OS_HANDLE, USHORT);
	OS_TIME resched_time;

	if (t_list_access) {
		t_start_ticks++;
		NU_Reset_Timer(&os_timer_cb, os_Timeout, 1, 0,
				NU_ENABLE_TIMER);
		return;
	}

	t_list_access = 1;
	timer = t_running;
	if (timer) {
		s_ticks = 0;
		done = 0;
		i = 0;
		do {
			timeout_func = timer->TimeoutProc;
			if (timer->p_ticks)
				p_list[i++] = timer;
			task_handle = timer->task_handle;
			e_handle = timer->entity_handle;
			t_index = timer->t_index;
			timer->status = 1;
			if (timer->next == timer) {
				t_running = NULL;
				done = 1;
			} else {
				timer->prev->next = timer->next;
				timer->next->prev = timer->prev;
				if (timer->next->r_ticks) {
					t_running = timer->next;
					s_ticks = timer->next->r_ticks;
					done = 1;
				} else
					timer = timer->next;
			}
			timeout_func(task_handle, e_handle, t_index);
		}
		while (!done);

		if (s_ticks) {
			t_start_ticks = NU_Retrieve_Clock();
			NU_Reset_Timer(&os_timer_cb, os_Timeout, s_ticks, 0,
				       NU_ENABLE_TIMER);
		}
	}
	for (t_r4 = p_list; *t_r4; t_r4++) {
		timer = *t_r4;
		resched_time = SYSTEM_TICKS_TO_TIME(timer->p_ticks);
		os_StartTimer(timer->entity_handle, timer->t_handle,
				timer->t_index, resched_time, resched_time);
		*t_r4 = NULL;
	}

	t_list_access = 0;
	return;
}

static int
os_remove_timer_from_list(T_OS_TIMER_TABLE_ENTRY *timer)
{
	OS_TICK c_ticks;

	if (timer != t_running) {
		if (timer->next != t_running)
			timer->next->r_ticks += timer->r_ticks;
	} else {
		c_ticks = NU_Retrieve_Clock();
		if (timer->next == timer) {
			t_running = 0;
		} else {
			timer->next->r_ticks =
			    t_start_ticks + timer->r_ticks +
			    timer->next->r_ticks - c_ticks;
			t_running = timer->next;
		}
		NU_Control_Timer(&os_timer_cb, NU_DISABLE_TIMER);
		if (t_running != NULL) {
			t_start_ticks = c_ticks;
			if (t_running->r_ticks != 0)
				NU_Reset_Timer(&os_timer_cb, os_Timeout,
						t_running->r_ticks, 0,
						NU_ENABLE_TIMER);
		}
	}
	if (timer->next != timer) {
		timer->prev->next = timer->next;
		timer->next->prev = timer->prev;
	}
	timer->next = NULL;
	timer->prev = NULL;
	timer->status = 1;
	return 1;
}

static unsigned
os_add_timer_to_list(T_OS_TIMER_TABLE_ENTRY *timer, OS_TICK ticks)
{
	T_OS_TIMER_TABLE_ENTRY *t_list;
	OS_TICK c_ticks, r1_ticks, return_ticks;

	if (ticks == 0)
		ticks = 1;

	c_ticks = NU_Retrieve_Clock();
	t_list = t_running;
	if (t_list != NULL) {
		if (t_list->r_ticks >= c_ticks - t_start_ticks) {
			r1_ticks = t_list->r_ticks - c_ticks + t_start_ticks;
			t_list->r_ticks = r1_ticks;
		} else {
			r1_ticks = 0;
			t_list->r_ticks = 0;
		}
		t_start_ticks = c_ticks;
		return_ticks = 0;
		while (ticks >= r1_ticks) {
			ticks -= r1_ticks;
			t_list = t_list->next;
			if (t_list == t_running)
				goto out;
			r1_ticks = t_list->r_ticks;
		}
		t_list->r_ticks -= ticks;
		if (t_list == t_running) {
			t_running = timer;
			t_start_ticks = c_ticks;
			NU_Control_Timer(&os_timer_cb, NU_DISABLE_TIMER);
			return_ticks = ticks;
		}
out:
		timer->next = t_list;
		timer->prev = t_list->prev;
		t_list->prev->next = timer;
		t_list->prev = timer;
		timer->r_ticks = ticks;
	} else {
		timer->next = timer;
		timer->prev = timer;
		timer->r_ticks = ticks;
		t_start_ticks = c_ticks;
		t_running = timer;
		return_ticks = ticks;
	}
	timer->status = 2;
	return return_ticks;
}

GLOBAL LONG os_StartTimer(OS_HANDLE TaskHandle, OS_HANDLE TimerHandle,
				USHORT Index, OS_TIME InitialTime,
				OS_TIME RescheduleTime)
{
	T_OS_TIMER_TABLE_ENTRY *timer;
	OS_TICK ticks;
	USHORT status;
	STATUS sts;

	t_list_access = 1;
	timer = &TimerTable[TimerHandle].entry;
	if (TimerHandle > MaxSimultaneousTimer || timer->status == 0) {
		t_list_access = 0;
		return OS_ERROR;
	}

	sts = NU_Obtain_Semaphore(&TimSemCB, NU_SUSPEND);
	/* Disassembly reveals this bogon in the original code:
		if (sts != NU_SUCCESS)
			os_MyHandle();
	*/
	status = timer->status;
	if (status == 2)
		status = os_remove_timer_from_list(timer);
	timer->t_handle = TimerHandle;
	timer->task_handle = os_MyHandle();
	timer->entity_handle = TaskHandle;
	timer->t_index = Index;
	timer->p_ticks = TIME_TO_SYSTEM_TICKS(RescheduleTime);
	ticks = os_add_timer_to_list(timer, TIME_TO_SYSTEM_TICKS(InitialTime));
	if (ticks)
		NU_Reset_Timer(&os_timer_cb, os_Timeout, ticks, 0,
				NU_ENABLE_TIMER);
	if (sts == NU_SUCCESS)
		NU_Release_Semaphore(&TimSemCB);
	t_list_access = 0;
	return OS_OK;
}

/* FIXME: TaskHandle is unused?! */
GLOBAL LONG os_StopTimer(OS_HANDLE TaskHandle, OS_HANDLE TimerHandle)
{
	T_OS_TIMER_ENTRY *timer_e;
	STATUS sts;

	t_list_access = 1;
	timer_e = &TimerTable[TimerHandle];
	if (TimerHandle > MaxSimultaneousTimer || timer_e->entry.status == 0) {
		t_list_access = 0;
		return OS_ERROR;
	}
	sts = NU_Obtain_Semaphore(&TimSemCB, NU_SUSPEND);
	if (timer_e->entry.status == 2)
		os_remove_timer_from_list(&timer_e->entry);
	if (sts == NU_SUCCESS)
		NU_Release_Semaphore(&TimSemCB);
	t_list_access = 0;
	return OS_OK;
}

GLOBAL LONG os_IncrementTick(OS_TICK ticks)
{
	return OS_OK;
}

/* FIXME: TaskHandle is unused?! */
GLOBAL LONG os_DestroyTimer(OS_HANDLE TaskHandle, OS_HANDLE TimerHandle)
{
	STATUS sts;
	T_OS_TIMER_ENTRY *timer_e;

	t_list_access = 1;
	sts = NU_Obtain_Semaphore(&TimSemCB, NU_SUSPEND);
	timer_e = &TimerTable[TimerHandle];
	if (TimerHandle > MaxSimultaneousTimer || timer_e->entry.status == 0) {
		if (sts == NU_SUCCESS)
			NU_Release_Semaphore(&TimSemCB);
		t_list_access = 0;
		return OS_ERROR;
	}
	timer_e->next_t_handle = next_t_handle;
	timer_e->entry.status = 0;
	used_timers--;
	t_list_access = 0;
	if (sts == NU_SUCCESS)
		NU_Release_Semaphore(&TimSemCB);
	return OS_OK;
}

/* FIXME: TaskHandle and MemPoolHandle are unused?! */
GLOBAL LONG os_CreateTimer(OS_HANDLE TaskHandle,
			   void (*TimeoutProc) (OS_HANDLE, OS_HANDLE, USHORT),
			   OS_HANDLE *TimerHandle, OS_HANDLE MemPoolHandle)
{
	STATUS sts;
	OS_HANDLE orig_next_t_handle;
	T_OS_TIMER_ENTRY *timer_e;

	t_list_access = 1;
	sts = NU_Obtain_Semaphore(&TimSemCB, NU_SUSPEND);
	orig_next_t_handle = next_t_handle;
	if (next_t_handle == 0) { /* INVALID_HANDLE */
		if (sts == NU_SUCCESS)
			NU_Release_Semaphore(&TimSemCB);
		t_list_access = 0;
		return OS_ERROR;
	}

	timer_e = &TimerTable[next_t_handle];
	timer_e->entry.status = 1;
	timer_e->entry.TimeoutProc = TimeoutProc;
	*TimerHandle = orig_next_t_handle;
	next_t_handle = timer_e->next_t_handle;
	used_timers++;
	if (max_used_timers < used_timers)
		max_used_timers = used_timers;
	if (sts == NU_SUCCESS)
		NU_Release_Semaphore(&TimSemCB);
	t_list_access = 0;
	return OS_OK;
}