PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
timer_alarm.c
Go to the documentation of this file.
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
16#include <kernel.h>
17#include <timer.h>
18#include <timer_alarm.h>
19
20typedef struct alarm_struct_
21{
22 struct alarm_struct_ *alarm_next;
23 vs32 timer_counter_id;
24 timer_alarm_handler_t callback_handler;
25 void *callback_handler_arg;
26} alarm_struct_t __attribute__((aligned(16)));
27
28#define PTR_TO_ALARM_ID(ptr_, cid_) ((s32)((((uiptr)(ptr_)) << 4) | ((cid_) & 0xFE) | 1))
29#define ALARM_ID_TO_PTR(id_) ((alarm_struct_t *)((((uiptr)(id_)) >> 8) << 4))
30#define ALARM_ID_IS_VALID(id_) ((ALARM_ID_TO_PTR(id_) != NULL) && ((siptr)(id_) >= 0) && ((((((uiptr)id_) & 0xFF) == (((ALARM_ID_TO_PTR(id_))->timer_counter_id) & 0xFF)))))
31
32#define ALARM_COUNT 64
33
34#ifdef F_alarm_data
35alarm_struct_t g_AlarmBuf[ALARM_COUNT] __attribute__((aligned(16)));
36alarm_struct_t *g_pFreeAlarm = NULL;
37#else
38extern alarm_struct_t g_AlarmBuf[ALARM_COUNT] __attribute__((aligned(16)));
39extern alarm_struct_t *g_pFreeAlarm;
40#endif
41
42#ifdef F_ForTimer_InitAlarm
43__attribute__((weak)) void ForTimer_InitAlarm(void)
44{
45 g_pFreeAlarm = &g_AlarmBuf[0];
46 for (u32 i = 0; i < (ALARM_COUNT - 1); i += 1)
47 {
48 g_AlarmBuf[i].alarm_next = &g_AlarmBuf[i + 1];
49 }
50 g_AlarmBuf[ALARM_COUNT - 1].alarm_next = NULL;
51}
52#endif
53
54static inline alarm_struct_t *ForTimer_AllocAlarm(void)
55{
56 alarm_struct_t *alarm_current;
57 alarm_current = g_pFreeAlarm;
58 if (alarm_current != NULL)
59 {
60 g_pFreeAlarm = alarm_current->alarm_next;
61 }
62 return alarm_current;
63}
64
65static inline void ForTimer_FreeAlarm(alarm_struct_t *alarm_current)
66{
67 alarm_current->alarm_next = g_pFreeAlarm;
68 alarm_current->timer_counter_id = 0;
69 g_pFreeAlarm = alarm_current;
70}
71
72#ifdef F_AlarmHandler
73u64 AlarmHandler(s32 alarm_id, u64 scheduled_time, u64 actual_time, void *arg, void *last_pc)
74{
75 u64 result;
76 alarm_struct_t *alarm_current;
77
78 alarm_current = (alarm_struct_t *)arg;
79 result = alarm_current->callback_handler(
80 PTR_TO_ALARM_ID(alarm_current, alarm_id),
81 scheduled_time,
82 actual_time,
83 alarm_current->callback_handler_arg, last_pc);
84 if (result == 0)
85 {
86 ForTimer_FreeAlarm(alarm_current);
87 return -1;
88 }
89 return result;
90}
91#endif
92
93#ifdef F_iSetTimerAlarm
94s32 iSetTimerAlarm(u64 clock_cycles, timer_alarm_handler_t callback_handler, void *arg)
95{
96 s32 timer_counter_id;
97 alarm_struct_t *alarm_current;
98
99 if (callback_handler == NULL)
100 {
101 return 0x80000016; // EINVAL
102 }
103 alarm_current = ForTimer_AllocAlarm();
104 if (alarm_current == NULL)
105 {
106 return 0x80008005; // ETIMER
107 }
108 timer_counter_id = iAllocTimerCounter();
109 if (timer_counter_id < 0)
110 {
111 ForTimer_FreeAlarm(alarm_current);
112 return timer_counter_id;
113 }
114 alarm_current->timer_counter_id = timer_counter_id;
115 alarm_current->callback_handler = callback_handler;
116 alarm_current->callback_handler_arg = arg;
117 iSetTimerHandler(timer_counter_id, clock_cycles, AlarmHandler, alarm_current);
118 iStartTimerCounter(timer_counter_id);
119 return PTR_TO_ALARM_ID(alarm_current, timer_counter_id);
120}
121#endif
122
123#ifdef F_SetTimerAlarm
132s32 SetTimerAlarm(u64 clock_cycles, timer_alarm_handler_t callback_handler, void *arg)
133{
134 u32 oldintr;
135 s32 ret;
136
137 oldintr = DIntr();
138 ret = iSetTimerAlarm(clock_cycles, callback_handler, arg);
139 if (oldintr != 0)
140 {
141 EIntr();
142 }
143 return ret;
144}
145#endif
146
147#ifdef F_iReleaseTimerAlarm
148s32 iReleaseTimerAlarm(s32 id)
149{
150 alarm_struct_t *alarm_current;
151 s32 ret;
152
153 alarm_current = ALARM_ID_TO_PTR(id);
154 if (!ALARM_ID_IS_VALID(id))
155 {
156 return 0x80008002; // EID
157 }
158 ret = iFreeTimerCounter(alarm_current->timer_counter_id);
159 if (ret == 0)
160 {
161 ForTimer_FreeAlarm(alarm_current);
162 }
163 return ret;
164}
165#endif
166
167#ifdef F_ReleaseTimerAlarm
168s32 ReleaseTimerAlarm(s32 id)
169{
170 alarm_struct_t *alarm_current;
171 u32 oldintr;
172
173 alarm_current = ALARM_ID_TO_PTR(id);
174 oldintr = DIntr();
175 if (!ALARM_ID_IS_VALID(id))
176 {
177 if (oldintr != 0)
178 {
179 EIntr();
180 }
181 return 0x80008002; // EID
182 }
183 FreeTimerCounter(alarm_current->timer_counter_id);
184 // Note: the result of FreeTimerCounter is not checked, so can be called within own timer handler
185 ForTimer_FreeAlarm(alarm_current);
186 if (oldintr != 0)
187 {
188 EIntr();
189 }
190 return 0;
191}
192#endif