sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
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
15
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
34alarm_struct_t g_AlarmBuf[ALARM_COUNT] __attribute__((aligned(16)));
35alarm_struct_t *g_pFreeAlarm = NULL;
36
37__attribute__((weak)) void ForTimer_InitAlarm(void)
38{
39 g_pFreeAlarm = &g_AlarmBuf[0];
40 for (u32 i = 0; i < (ALARM_COUNT - 1); i += 1)
41 {
42 g_AlarmBuf[i].alarm_next = &g_AlarmBuf[i + 1];
43 }
44 g_AlarmBuf[ALARM_COUNT - 1].alarm_next = NULL;
45}
46
47static inline alarm_struct_t *ForTimer_AllocAlarm(void)
48{
49 alarm_struct_t *alarm_current;
50 alarm_current = g_pFreeAlarm;
51 if (alarm_current != NULL)
52 {
53 g_pFreeAlarm = alarm_current->alarm_next;
54 }
55 return alarm_current;
56}
57
58static inline void ForTimer_FreeAlarm(alarm_struct_t *alarm_current)
59{
60 alarm_current->alarm_next = g_pFreeAlarm;
61 alarm_current->timer_counter_id = 0;
62 g_pFreeAlarm = alarm_current;
63}
64
65u64 AlarmHandler(s32 alarm_id, u64 scheduled_time, u64 actual_time, void *arg, void *last_pc)
66{
67 u64 result;
68 alarm_struct_t *alarm_current;
69
70 alarm_current = (alarm_struct_t *)arg;
71 result = alarm_current->callback_handler(
72 PTR_TO_ALARM_ID(alarm_current, alarm_id),
73 scheduled_time,
74 actual_time,
75 alarm_current->callback_handler_arg, last_pc);
76 if (result == 0)
77 {
78 ForTimer_FreeAlarm(alarm_current);
79 return -1;
80 }
81 return result;
82}
83
84s32 iSetTimerAlarm(u64 clock_cycles, timer_alarm_handler_t callback_handler, void *arg)
85{
86 s32 timer_counter_id;
87 alarm_struct_t *alarm_current;
88
89 if (callback_handler == NULL)
90 {
91 return 0x80000016; // EINVAL
92 }
93 alarm_current = ForTimer_AllocAlarm();
94 if (alarm_current == NULL)
95 {
96 return 0x80008005; // ETIMER
97 }
98 timer_counter_id = iAllocTimerCounter();
99 if (timer_counter_id < 0)
100 {
101 ForTimer_FreeAlarm(alarm_current);
102 return timer_counter_id;
103 }
104 alarm_current->timer_counter_id = timer_counter_id;
105 alarm_current->callback_handler = callback_handler;
106 alarm_current->callback_handler_arg = arg;
107 iSetTimerHandler(timer_counter_id, clock_cycles, AlarmHandler, alarm_current);
108 iStartTimerCounter(timer_counter_id);
109 return PTR_TO_ALARM_ID(alarm_current, timer_counter_id);
110}
111
120s32 SetTimerAlarm(u64 clock_cycles, timer_alarm_handler_t callback_handler, void *arg)
121{
122 u32 oldintr;
123 s32 ret;
124
125 oldintr = DIntr();
126 ret = iSetTimerAlarm(clock_cycles, callback_handler, arg);
127 if (oldintr != 0)
128 {
129 EIntr();
130 }
131 return ret;
132}
133
134s32 iReleaseTimerAlarm(s32 id)
135{
136 alarm_struct_t *alarm_current;
137 s32 ret;
138
139 alarm_current = ALARM_ID_TO_PTR(id);
140 if (!ALARM_ID_IS_VALID(id))
141 {
142 return 0x80008002; // EID
143 }
144 ret = iFreeTimerCounter(alarm_current->timer_counter_id);
145 if (ret == 0)
146 {
147 ForTimer_FreeAlarm(alarm_current);
148 }
149 return ret;
150}
151
152s32 ReleaseTimerAlarm(s32 id)
153{
154 alarm_struct_t *alarm_current;
155 u32 oldintr;
156
157 alarm_current = ALARM_ID_TO_PTR(id);
158 oldintr = DIntr();
159 if (!ALARM_ID_IS_VALID(id))
160 {
161 if (oldintr != 0)
162 {
163 EIntr();
164 }
165 return 0x80008002; // EID
166 }
167 FreeTimerCounter(alarm_current->timer_counter_id);
168 // Note: the result of FreeTimerCounter is not checked, so can be called within own timer handler
169 ForTimer_FreeAlarm(alarm_current);
170 if (oldintr != 0)
171 {
172 EIntr();
173 }
174 return 0;
175}
s32 SetTimerAlarm(u64 clock_cycles, timer_alarm_handler_t callback_handler, void *arg)