PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
alarm.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Licenced under Academic Free License version 2.0
7# Review ps2sdk README & LICENSE files for further details.
8*/
9
10#include "tamtypes.h"
11#include "timer.h"
12#include "ee_regs.h"
13#include "kernel.h"
14
15#include "internal.h"
16
17#define USER_MODE_DISPATCHER 0x00082000 // Call the replacement dispatcher (the original dispatcher function is located at 0x00081fe0).
18
19#define INTC_TIM3 12
20#define T3_COUNT_W ((vu32 *)0xB0001800)
21#define T3_MODE_W ((vu32 *)0xB0001810)
22#define T3_COMP_W ((vu32 *)0xB0001820)
23
24static int AlarmCount = 0;
25static u64 AlarmStatus = 0;
26
27struct alarm
28{
29 u16 target; // 0x00
30 u16 time; // 0x02
31 int id; // 0x04
32 void *callback; // 0x08
33 void *common; // 0x0c
34 void *gp; // 0x10
35};
36
37static struct alarm alarms[MAX_ALARMS];
38
39// Function prototypes
40static u32 CalculateTimeDiff(u32 t1, u32 t2);
41static int InsertAlarm(u32 now, u32 target);
42static s32 SetAlarmInternal(u16 time, void (*callback)(s32 dispatch_id, u16 time, void *common), void *common);
43static void SetupTIM3(u16 ticks);
44
45static u32 CalculateTimeDiff(u32 t1, u32 t2)
46{
47 return (t2 < t1 ? (0x10000 | t2) : t2);
48}
49
50static int InsertAlarm(u32 now, u32 target)
51{
52 int pos, i;
53
54 pos = 0;
55 for (pos = 0; pos < AlarmCount; pos++) {
56 if (target < CalculateTimeDiff(now, alarms[pos].time)) { // Spot found. If it is not at the end of the list, move back the list.
57 for (i = AlarmCount - 1; i >= pos; i--)
58 alarms[i + 1] = alarms[i];
59
60 break;
61 }
62 }
63
64 return pos;
65}
66
67static s32 SetAlarmInternal(u16 time, void (*callback)(s32 dispatch_id, u16 time, void *common), void *common)
68{
69 void *gp;
70 u32 target, now;
71 struct alarm *alarm;
72 int i, alarmID, pos;
73
74 now = *T3_COUNT_W;
75 target = now + time;
76
77 if (AlarmCount >= MAX_ALARMS)
78 return -1;
79
80 alarmID = -1;
81 for (i = 0; i < MAX_ALARMS; i++) {
82 if (((AlarmStatus >> i) & 1) == 0) {
83 AlarmStatus |= (1 << i);
84 alarmID = i;
85 break;
86 }
87 }
88
89 if (alarmID < 0)
90 return alarmID;
91
92 gp = GetGP();
93 pos = InsertAlarm(now, target);
94 alarm = &alarms[pos];
95 alarm->time = time;
96 alarm->target = (u16)target;
97 alarm->id = alarmID;
98 alarm->gp = gp;
99 alarm->callback = callback;
100 alarm->common = common;
101 AlarmCount++;
102 SetupTIM3(alarms[0].target);
103
104 return alarm->id;
105}
106
107s32 ReleaseAlarm(s32 id)
108{
109 u16 time;
110 s32 result;
111 int i, j;
112
113 result = -1;
114 for (i = 0; i < AlarmCount; i++) {
115 if (alarms[i].id == id) {
116 if (alarms[i].target == *T3_COMP_W) {
117 if (*R_EE_I_STAT & (1 << INTC_TIM3)) // Cannot release alarm that has already triggered.
118 return -1;
119 }
120
121 time = alarms[i].time;
122 // Move forward list.
123 for (j = i; j < AlarmCount - 1; j++)
124 alarms[j] = alarms[j + 1];
125
126 --AlarmCount;
127 AlarmStatus &= ~(1 << id);
128
129 if (i == 0) // If the first alarm was released, update timer comparator.
130 SetupTIM3(alarms[0].target);
131
132 if (AlarmCount == 0) // Stop timer if there are no alarms left.
133 *T3_MODE_W = Tn_MODE(3, 0, 0, 0, 0, 1, 0, 0, 0, 0);
134
135 result = (CalculateTimeDiff(time, *T3_COUNT_W) - time);
136 }
137 }
138
139 EE_SYNC();
140 return result;
141}
142
143s32 SetAlarm(u16 time, void (*callback)(s32 dispatch_id, u16 time, void *common), void *common)
144{
145 s32 result;
146
147 result = SetAlarmInternal(time, callback, common);
148 EE_SYNC();
149
150 return result;
151}
152
153static void SetupTIM3(u16 ticks)
154{
155 *T3_COMP_W = ticks;
156 EE_SYNC();
157 *T3_MODE_W = Tn_MODE(3, 0, 0, 0, 0, 1, 1, 0, 1, 0);
158}
159
160// INTC 12 (TIM3) handler
161void Intc12Handler(void)
162{
163 struct alarm alarm;
164 int i;
165
166 for (i = 0; i < AlarmCount; i++) { // Attempt to find another alarm request that has a different target. Update TIM3's comparator.
167 if (alarms[i].target != alarms[0].target) {
168 SetupTIM3(alarms[i].target);
169 break;
170 }
171 }
172
173 do {
174 void *gp;
175
176 alarm = alarms[0];
177 AlarmCount--;
178 for (i = 0; i < AlarmCount; i++)
179 alarms[i] = alarms[i + 1];
180
181 gp = ChangeGP(alarm.gp);
182 AlarmStatus &= ~(1 << alarm.id);
183 InvokeUserModeCallback((void *)USER_MODE_DISPATCHER, alarm.callback, alarm.id, alarm.target, alarm.common);
184 SetGP(gp);
185
186 if (AlarmCount <= 0)
187 break;
188 } while (alarms[0].target == alarm.target);
189
190 if (AlarmCount <= 0) // If there are no further alarms, disable CMPE.
191 *T3_MODE_W = Tn_MODE(3, 0, 0, 0, 0, 1, 0, 0, 1, 0);
192 else
193 SetupTIM3(alarms[0].target);
194
195 ExitHandler();
196}
#define R_EE_I_STAT
Definition ee_regs.h:462
Definition alarm.c:28