PS2SDK
PS2 Homebrew Libraries
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 
20 typedef 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
35 alarm_struct_t g_AlarmBuf[ALARM_COUNT] __attribute__((aligned(16)));
36 alarm_struct_t *g_pFreeAlarm = NULL;
37 #else
38 extern alarm_struct_t g_AlarmBuf[ALARM_COUNT] __attribute__((aligned(16)));
39 extern 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 
54 static 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 
65 static 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
73 u64 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
94 s32 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
124 
132 s32 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
148 s32 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
168 s32 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
kernel.h
timer.h
alarm_struct_
Definition: timer_alarm.c:20
__attribute__
Definition: gif_registers.h:38