revert between 56095 -> 55830 in arch
[AROS.git] / arch / all-unix / timer / timer_init.c
blob7ebb8554702a24d20c3c2617b93113a6388095a7
1 /*
2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 /*
7 * UNIX-hosted timer driver.
8 * Unix operating systems have only one usable timer, producing SIGALRM.
9 * In this implementation we run the timer with a fixed frequency, which
10 * is a multiple of VBlank frequency.
11 * TODO: Rewrite UNIX-hosted timer.device to use variable delays, for improved accuracy.
14 #include <aros/bootloader.h>
15 #include <aros/debug.h>
16 #include <aros/symbolsets.h>
17 #include <exec/execbase.h>
18 #include <exec/interrupts.h>
19 #include <hardware/intbits.h>
20 #include <proto/arossupport.h>
21 #include <proto/bootloader.h>
22 #include <proto/exec.h>
23 #include <proto/hostlib.h>
24 #include <proto/kernel.h>
26 #include "timer_intern.h"
27 #include "timer_macros.h"
29 #define timeval sys_timeval
31 #include <signal.h>
32 #include <sys/time.h>
33 #include <string.h>
35 #undef timeval
37 /* Android is not a true Linux ;-) */
38 #ifdef HOST_OS_android
39 #undef HOST_OS_linux
40 #endif
42 #ifdef HOST_OS_linux
43 #define LIBC_NAME "libc.so.6"
44 #endif
46 #ifdef HOST_OS_darwin
47 #define LIBC_NAME "libSystem.dylib"
48 #endif
50 #ifndef LIBC_NAME
51 #define LIBC_NAME "libc.so"
52 #endif
55 * In Linux stdlib.h #define's atoi() to something internal, causing link failure
56 * because we link our kickstart binaries against AROS libraries, and not against
57 * host OS ones.
58 * Explicit prototype here avoids this.
60 int atoi(const char *nptr);
62 /* Handle periodic timer and drive exec VBlank */
63 static void TimerTick(struct TimerBase *TimerBase, struct ExecBase *SysBase)
65 /* Increment EClock value and process microhz requests */
66 ADDTIME(&TimerBase->tb_CurrentTime, &TimerBase->tb_Platform.tb_VBlankTime);
67 ADDTIME(&TimerBase->tb_Elapsed, &TimerBase->tb_Platform.tb_VBlankTime);
68 TimerBase->tb_ticks_total++;
70 handleMicroHZ(TimerBase, SysBase);
72 /* Now handle VBlank emulation via divisor */
73 TimerBase->tb_Platform.tb_TimerCount++;
74 if (TimerBase->tb_Platform.tb_TimerCount == TimerBase->tb_Platform.tb_VBlankTicks)
76 vblank_Cause(SysBase);
77 handleVBlank(TimerBase, SysBase);
79 TimerBase->tb_Platform.tb_TimerCount = 0;
83 #define KernelBase TimerBase->tb_KernelBase
85 static int Timer_Init(struct TimerBase *TimerBase)
87 APTR BootLoaderBase;
88 struct itimerval interval;
89 int ret;
91 HostLibBase = OpenResource("hostlib.resource");
92 if (!HostLibBase)
93 return FALSE;
95 TimerBase->tb_Platform.libcHandle = HostLib_Open(LIBC_NAME, NULL);
96 if (!TimerBase->tb_Platform.libcHandle)
97 return FALSE;
99 TimerBase->tb_Platform.setitimer = HostLib_GetPointer(TimerBase->tb_Platform.libcHandle, "setitimer", NULL);
100 if (!TimerBase->tb_Platform.setitimer)
101 return FALSE;
103 /* Install timer IRQ handler */
104 #if DEBUG
105 /* Uses ITIMER_VIRTUAL/SIGVTALRM instead of the
106 * ITIMER_REAL/SIGALRM in debug builds, so
107 * that stepping though code won't have to deal
108 * with constant SIGALRM processing.
110 * NOTE: This will cause the AROS clock to march slower
111 * than the host clock in debug builds!
113 TimerBase->tb_TimerIRQHandle = KrnAddIRQHandler(SIGVTALRM, TimerTick, TimerBase, SysBase);
114 #else
115 TimerBase->tb_TimerIRQHandle = KrnAddIRQHandler(SIGALRM, TimerTick, TimerBase, SysBase);
116 #endif
117 if (!TimerBase->tb_TimerIRQHandle)
118 return FALSE;
120 /* Our defaults: 50 Hz VBlank and 4x timer rate. 1x gives very poor results. */
121 SysBase->VBlankFrequency = 50;
122 TimerBase->tb_Platform.tb_VBlankTicks = 4;
125 * Since we are software-driven, we can just ask the user which
126 * frequencies he wishes to use.
128 BootLoaderBase = OpenResource("bootloader.resource");
129 if (BootLoaderBase)
131 struct List *args = GetBootInfo(BL_Args);
133 if (args)
135 struct Node *node;
137 for (node = args->lh_Head; node->ln_Succ; node = node->ln_Succ)
139 if (strncasecmp(node->ln_Name, "vblank=", 7) == 0)
140 SysBase->VBlankFrequency = atoi(&node->ln_Name[7]);
141 else if (strncasecmp(node->ln_Name, "tickrate=", 9) == 0)
142 TimerBase->tb_Platform.tb_VBlankTicks = atoi(&node->ln_Name[9]);
147 /* Calculate effective EClock timer frequency. Set it also in ExecBase public field. */
148 TimerBase->tb_eclock_rate = SysBase->VBlankFrequency * TimerBase->tb_Platform.tb_VBlankTicks;
149 SysBase->ex_EClockFrequency = TimerBase->tb_eclock_rate;
150 D(bug("[Timer_Init] Timer frequency is %d\n", TimerBase->tb_eclock_rate));
152 /* Calculate timer period in us */
153 TimerBase->tb_Platform.tb_VBlankTime.tv_secs = 0;
154 TimerBase->tb_Platform.tb_VBlankTime.tv_micro = 1000000 / TimerBase->tb_eclock_rate;
156 /* Start up our system timer. */
157 interval.it_interval.tv_sec = interval.it_value.tv_sec = 0;
158 interval.it_interval.tv_usec = interval.it_value.tv_usec = TimerBase->tb_Platform.tb_VBlankTime.tv_micro;
160 HostLib_Lock();
162 #if DEBUG
163 ret = TimerBase->tb_Platform.setitimer(ITIMER_VIRTUAL, &interval, NULL);
164 #else
165 ret = TimerBase->tb_Platform.setitimer(ITIMER_REAL, &interval, NULL);
166 #endif
167 AROS_HOST_BARRIER
169 HostLib_Unlock();
171 D(bug("[Timer_Init] setitimer() returned %d\n", ret));
172 return !ret;
175 static int Timer_Expunge(struct TimerBase *TimerBase)
177 if (!HostLibBase)
178 return TRUE;
180 if (TimerBase->tb_TimerIRQHandle)
181 KrnRemIRQHandler(TimerBase->tb_TimerIRQHandle);
183 if (TimerBase->tb_Platform.libcHandle)
184 HostLib_Close(TimerBase->tb_Platform.libcHandle, NULL);
186 return TRUE;
189 ADD2INITLIB(Timer_Init, 0)
190 ADD2EXPUNGELIB(Timer_Expunge, 0)