PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
ps2_sbus.c
1/*
2
3Common PS2 SBUS interrupt management API for both EE and IOP.
4
5This file contains all common code for both EE and IOP SBUS interrupt management.
6
7See also iop_sbus.c and ee_sbus.c for platform-specific glue functions.
8
9*/
10
11#include <tamtypes.h>
12#include <ps2_reg_defs.h>
13#include "ps2_sbus.h"
14#include "sbus_priv.h"
15
16// 32 local SBUS interrupt handlers.
17SBUS_IrqHandler _sbus_irq_handlers[32];
18
19static u32 _get_reg(u32 *reg)
20{
21 u32 v1, v2;
22
23 v2 = *(vu32 *)(reg);
24 do {
25 v1 = v2;
26
27#ifdef _EE
28 // EE needs 20 NOPs!
29 __asm__ volatile("nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n");
30#endif
31
32 v2 = *(vu32 *)reg;
33 } while (v1 != v2);
34
35 return (v1);
36}
37
38static void _set_reg(u32 *reg, u32 val)
39{
40 *(vu32 *)(reg) = val;
41 _get_reg(reg);
42}
43
44// API call
45u32 SBUS_get_reg(int reg_no) { return (_get_reg((u32 *)R_LOCAL_SBUS(reg_no))); }
46
47// API call
48void SBUS_set_reg(int reg_no, u32 val) { _set_reg((u32 *)R_LOCAL_SBUS(reg_no), val); }
49
50// Interrupt handler for local SBUS interrupts
51int __local_sbus_irq_handler(void)
52{
53 u32 flag;
54 int irq;
55
56 flag = SBUS_get_reg(PS2_SBUS_RL_FLAG);
57
58 // loop through each bit of RL_FLAG calling the handler of any bit which is set.
59 for (irq = 31; ((flag != 0) && (irq >= 0)); irq--) {
60 if (flag & (1 << irq)) {
61 if (_sbus_irq_handlers[irq].func) {
62 _sbus_irq_handlers[irq].func(irq, _sbus_irq_handlers[irq].param);
63 }
64
65 SBUS_set_reg(PS2_SBUS_RL_FLAG, (1 << irq));
66
67 flag ^= (1 << irq);
68 }
69 }
70
71 return (1);
72}
73
74// API call
75void *SBUS_set_irq_handler(int irq, SBUS_IrqHandlerFunc func, void *param)
76{
77 void *rv = NULL;
78
79 if (irq < 32) {
80 int oldi;
81 M_SuspendIntr(&oldi);
82 rv = _sbus_irq_handlers[irq].func;
83 _sbus_irq_handlers[irq].func = func;
84 _sbus_irq_handlers[irq].param = param;
85 M_ResumeIntr(oldi);
86 }
87
88 // return pointer to old handler
89 return (rv);
90}
91
92// API call
93int SBUS_rem_irq_handler(int irq)
94{
95
96 if (irq < 32) {
97 int oldi;
98 M_SuspendIntr(&oldi);
99 _sbus_irq_handlers[irq].func = NULL;
100 _sbus_irq_handlers[irq].param = NULL;
101 M_ResumeIntr(oldi);
102 return (0);
103 }
104
105 return (-1);
106}
107
108static int __sbus_init = 0;
109
110int SBUS_init(void)
111{
112 int i;
113 int old_irq_state;
114 int old_intr_state;
115
116 if (__sbus_init) {
117 return (-1);
118 }
119
120 M_SuspendIntr(&old_intr_state);
121
122 M_DisableIrq(PS2_IRQ_SBUS, &old_irq_state);
123
124 M_ReleaseIrqHandler(PS2_IRQ_SBUS);
125
126 for (i = 0; i < 32; i++) {
127 _sbus_irq_handlers[i].func = NULL;
128 _sbus_irq_handlers[i].param = NULL;
129 }
130
131 M_RegisterIrqHandler(PS2_IRQ_SBUS, (void *)__local_sbus_irq_handler, NULL);
132
133 M_EnableIrq(PS2_IRQ_SBUS);
134
135 M_ResumeIntr(old_intr_state);
136
137 __sbus_init = 1;
138
139 return (0);
140}
141
142int SBUS_deinit(void)
143{
144 int old_irq_state;
145 int old_intr_state;
146
147 if (!__sbus_init) {
148 return (-1);
149 }
150
151 M_SuspendIntr(&old_intr_state);
152
153 M_DisableIrq(PS2_IRQ_SBUS, &old_irq_state);
154 M_ReleaseIrqHandler(PS2_IRQ_SBUS);
155
156 M_ResumeIntr(old_intr_state);
157
158 __sbus_init = 0;
159
160 return (0);
161}