PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
vblank.c
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
11#include "vblank.h"
12#include "irx_imports.h"
13#include "kerr.h"
14
15extern struct irx_export_table _exp_vblank;
16
17#ifdef _IOP
18IRX_ID("Vblank_service", 1, 1);
19#endif
20// Based on the module from SCE SDK 1.3.4.
21
22static vblank_internals_t vblank_internals;
23
24static int irq_vblank_interrupt_handler(vblank_internals_t *vbi);
25static int irq_evblank_interrupt_handler(vblank_internals_t *vbi);
26static int vblank_handler_base_beginning(vblank_internals_t *vbi);
27static int vblank_handler_base_end(vblank_internals_t *vbi);
28static void linked_list_set_self(vblank_ll_t *ll);
29static int linked_list_next_is_self(const vblank_ll_t *ll);
30static void linked_list_remove(vblank_ll_t *ll);
31static void linked_list_add_after(vblank_ll_t *ll1, vblank_ll_t *ll2);
32
33int _start(int ac, char **av)
34{
35 unsigned int i;
36 iop_event_t evfp;
37 int state;
38
39 (void)ac;
40 (void)av;
41
42 CpuSuspendIntr(&state);
43 if ( RegisterLibraryEntries(&_exp_vblank) )
44 {
45 CpuResumeIntr(state);
46 return 1;
47 }
48
49 memset(&vblank_internals, 0, sizeof(vblank_internals));
50 linked_list_set_self(&vblank_internals.list_00);
51 linked_list_set_self(&vblank_internals.list_11);
52 linked_list_set_self(&vblank_internals.list_free);
53 for ( i = 0; i < (sizeof(vblank_internals.list_items) / sizeof(vblank_internals.list_items[0])); i += 1 )
54 {
55 linked_list_add_after(&vblank_internals.list_free, &(vblank_internals.list_items[i].ll));
56 }
57 evfp.bits = 0;
58 evfp.attr = EA_MULTI;
59 evfp.option = 0;
60 vblank_internals.ef = CreateEventFlag(&evfp);
61 RegisterVblankHandler(0, 128, (int (*)(void *))vblank_handler_base_beginning, &vblank_internals);
62 RegisterVblankHandler(1, 128, (int (*)(void *))vblank_handler_base_end, &vblank_internals);
63 RegisterIntrHandler(IOP_IRQ_VBLANK, 1, (int (*)(void *))irq_vblank_interrupt_handler, &vblank_internals);
64 RegisterIntrHandler(IOP_IRQ_EVBLANK, 1, (int (*)(void *))irq_evblank_interrupt_handler, &vblank_internals);
65 EnableIntr(IOP_IRQ_VBLANK);
66 EnableIntr(IOP_IRQ_EVBLANK);
67 CpuResumeIntr(state);
68 return 0;
69}
70
71vblank_internals_t *GetVblankInternalData(void)
72{
73 return &vblank_internals;
74}
75
76int RegisterVblankHandler(int startend, int priority, int (*handler)(void *), void *arg)
77{
78 const vblank_ll_t *list;
79 vblank_ll_t *item;
80 vblank_item_t *item_new;
81 int state;
82
83 if ( QueryIntrContext() != 0 )
84 {
85 return KE_ILLEGAL_CONTEXT;
86 }
87 CpuSuspendIntr(&state);
88 if ( linked_list_next_is_self(&vblank_internals.list_free) )
89 {
90 CpuResumeIntr(state);
91 return KE_NO_MEMORY;
92 }
93 list = &vblank_internals.list_11;
94 if ( !startend )
95 list = &vblank_internals.list_00;
96 item = list->next;
97 if ( list->next != list )
98 {
99 do
100 {
101 const vblank_item_t *item_vblank;
102
103 item_vblank = (vblank_item_t *)item;
104 if ( item_vblank->callback == handler )
105 {
106 CpuResumeIntr(state);
107 return KE_FOUND_HANDLER;
108 }
109 item = item->next;
110 } while ( item != list );
111 item = list->next;
112 }
113 for ( ; item != list; item = item->next )
114 {
115 const vblank_item_t *item_vblank;
116
117 item_vblank = (vblank_item_t *)item;
118 if ( priority < item_vblank->priority )
119 break;
120 }
121 item_new = (vblank_item_t *)vblank_internals.list_free.next;
122 linked_list_remove(vblank_internals.list_free.next);
123 item_new->callback = handler;
124 item_new->userdata = arg;
125 item_new->priority = priority;
126 linked_list_add_after(item, &item_new->ll);
127 CpuResumeIntr(state);
128 return 0;
129}
130
131// cppcheck-suppress constParameterPointer
132int ReleaseVblankHandler(int startend, int (*handler)(void *))
133{
134 const vblank_ll_t *list;
135 vblank_ll_t *item;
136 int state;
137
138 if ( QueryIntrContext() != 0 )
139 {
140 return KE_ILLEGAL_CONTEXT;
141 }
142 CpuSuspendIntr(&state);
143 list = &vblank_internals.list_11;
144 if ( !startend )
145 list = &vblank_internals.list_00;
146 item = list->next;
147 if ( list->next == list )
148 {
149 CpuResumeIntr(state);
150 return KE_NOTFOUND_HANDLER;
151 }
152 {
153 const vblank_item_t *item_vblank;
154
155 item_vblank = (vblank_item_t *)item;
156 while ( item_vblank->callback != handler )
157 {
158 item = item->next;
159 item_vblank = (vblank_item_t *)item;
160 if ( item == list )
161 {
162 CpuResumeIntr(state);
163 return KE_NOTFOUND_HANDLER;
164 }
165 }
166 }
167 linked_list_remove(item);
168 linked_list_add_after(&vblank_internals.list_free, item);
169 CpuResumeIntr(state);
170 return 0;
171}
172
173static int irq_vblank_interrupt_handler(vblank_internals_t *vbi)
174{
175 int item_count;
176 vblank_ll_t *item;
177 vblank_ll_t *item_tmp;
178
179 item_count = vbi->item_count;
180 if ( !item_count )
181 {
182 iSetEventFlag(GetSystemStatusFlag(), 0x200);
183 item_count = vbi->item_count;
184 }
185 item = vbi->list_00.next;
186 vbi->item_count = item_count + 1;
187 if ( item != &vbi->list_00 )
188 {
189 do
190 {
191 vblank_item_t *item_vblank;
192
193 item_vblank = (vblank_item_t *)item;
194 item_tmp = item->next;
195 if ( item_vblank->callback(item_vblank->userdata) == 0 )
196 {
197 linked_list_remove(item);
198 linked_list_add_after(&vbi->list_free, item);
199 }
200 item = item_tmp;
201 } while ( item_tmp != &vbi->list_00 );
202 }
203 return 1;
204}
205
206static int irq_evblank_interrupt_handler(vblank_internals_t *vbi)
207{
208 vblank_ll_t *item;
209 const vblank_ll_t *list_tail;
210 vblank_ll_t *item_tmp;
211
212 item = vbi->list_11.next;
213 list_tail = &vbi->list_11;
214 if ( item != list_tail )
215 {
216 do
217 {
218 vblank_item_t *item_vblank;
219
220 item_vblank = (vblank_item_t *)item;
221 item_tmp = item->next;
222 if ( item_vblank->callback(item_vblank->userdata) == 0 )
223 {
224 linked_list_remove(item);
225 linked_list_add_after(&vbi->list_free, item);
226 }
227 item = item_tmp;
228 } while ( item_tmp != list_tail );
229 }
230 return 1;
231}
232
233#define EF_VBLANK_START 1
234#define EF_VBLANK_END 4
235#define EF_VBLANK 2
236#define EF_NON_VBLANK 8
237
238static int vblank_handler_base_beginning(vblank_internals_t *vbi)
239{
240 iSetEventFlag(vbi->ef, EF_VBLANK_START);
241 iSetEventFlag(vbi->ef, EF_VBLANK);
242 iClearEventFlag(vbi->ef, ~(9));
243 return 1;
244}
245
246static int vblank_handler_base_end(vblank_internals_t *vbi)
247{
248 iSetEventFlag(vbi->ef, EF_VBLANK_END);
249 iSetEventFlag(vbi->ef, EF_NON_VBLANK);
250 iClearEventFlag(vbi->ef, ~(6));
251 return 1;
252}
253
254void WaitVblankStart()
255{
256 WaitEventFlag(vblank_internals.ef, EF_VBLANK_START, WEF_OR, NULL);
257}
258
259void WaitVblankEnd()
260{
261 WaitEventFlag(vblank_internals.ef, EF_VBLANK_END, WEF_OR, NULL);
262}
263
264void WaitVblank()
265{
266 WaitEventFlag(vblank_internals.ef, EF_VBLANK, WEF_OR, NULL);
267}
268
269void WaitNonVblank()
270{
271 WaitEventFlag(vblank_internals.ef, EF_NON_VBLANK, WEF_OR, NULL);
272}
273
274static void linked_list_set_self(vblank_ll_t *ll)
275{
276 ll->next = ll;
277 ll->prev = ll;
278}
279
280static int linked_list_next_is_self(const vblank_ll_t *ll)
281{
282 return ll->next == ll;
283}
284
285static void linked_list_remove(vblank_ll_t *ll)
286{
287 ll->next->prev = ll->prev;
288 ll->prev->next = ll->next;
289}
290
291#if 0
292// This function is unused
293static int linked_list_is_circular(vblank_ll_t *ll)
294{
295 return ll->prev == ll->next;
296}
297#endif
298
299static void linked_list_add_after(vblank_ll_t *ll1, vblank_ll_t *ll2)
300{
301 ll2->next = ll1;
302 ll2->prev = ll1->prev;
303 ll1->prev = ll2;
304 ll2->prev->next = ll2;
305}
int CpuResumeIntr(int state)
Definition intrman.c:227
int RegisterIntrHandler(int irq, int mode, int(*handler)(void *), void *arg)
Definition intrman.c:125
int QueryIntrContext(void)
int CpuSuspendIntr(int *state)
Definition intrman.c:205
int EnableIntr(int irq)
Definition intrman.c:346
#define EA_MULTI
Definition thevent.h:35