PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
sifcmd.c
Go to the documentation of this file.
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# (C)2001, Gustavo Scotti (gustavo@scotti.com)
7# (c) 2003 Marcus R. Brown (mrbrown@0xd6.org)
8# Licenced under Academic Free License version 2.0
9# Review ps2sdk README & LICENSE files for further details.
10*/
11
19#include <tamtypes.h>
20#include <kernel.h>
21#include <sifcmd.h>
22
23#define CMD_PACKET_MAX 128
24#define CMD_PACKET_DATA_MAX 112
25#define SYS_CMD_HANDLER_MAX 32
26
27/* EE DMAC registers. */
28#define DMAC_COMM_STAT 0x1000e010
29#define DMAC_SIF0_CHCR 0x1000c000
30#define CHCR_STR 0x100
31#define STAT_SIF0 0x20
32
40{
42 void *pktbuf;
43 void *unused;
45 void *iopbuf;
46 SifCmdHandlerData_t *sys_cmd_handlers;
47 u32 nr_sys_handlers;
48 SifCmdHandlerData_t *usr_cmd_handlers;
49 u32 nr_usr_handlers;
50 int *sregs;
51};
52
53extern int _iop_reboot_count;
54extern struct cmd_data _sif_cmd_data;
55int _SifCmdIntHandler(int channel);
56
57#ifdef F_sif_cmd_send
58static unsigned int _SifSendCmd(int cid, int mode, void *pkt, int pktsize, void *src,
59 void *dest, int size)
60{
61 SifDmaTransfer_t dmat[2];
62 SifCmdHeader_t *header;
63 int count = 0;
64
65 pktsize &= 0xff;
66
67 if (pktsize > CMD_PACKET_DATA_MAX)
68 return 0;
69
70 header = (SifCmdHeader_t *)pkt;
71 header->cid = cid;
72 header->psize = pktsize;
73 header->dest = NULL;
74
75 if (size > 0) {
76 header->dsize = size;
77 header->dest = dest;
78
79 if (mode & SIF_CMD_M_WBDC) /* if mode is & 4, flush reference cache */
80 SifWriteBackDCache(src, size);
81
82 dmat[count].src = src;
83 dmat[count].dest = dest;
84 dmat[count].size = size;
85 dmat[count].attr = 0;
86 count++;
87 }
88
89 dmat[count].src = pkt;
90 dmat[count].dest = _sif_cmd_data.iopbuf;
91 dmat[count].size = pktsize;
92 dmat[count].attr = SIF_DMA_ERT | SIF_DMA_INT_O;
93 count++;
94
95 SifWriteBackDCache(pkt, pktsize);
96
97 if (mode & SIF_CMD_M_INTR) /* INTERRUPT DMA TRANSFER */
98 return iSifSetDma(dmat, count);
99 else
100 return SifSetDma(dmat, count);
101}
102
103unsigned int
104SifSendCmd(int command, void *send_data, int send_len,
105 void *extra_from, void *extra_dest, int extra_len)
106{
107 return _SifSendCmd(command, 0, send_data, send_len,
108 extra_from, extra_dest, extra_len);
109}
110
111unsigned int
112iSifSendCmd(int command, void *send_data, int send_len,
113 void *extra_from, void *extra_dest, int extra_len)
114{
115 return _SifSendCmd(command, SIF_CMD_M_INTR, send_data, send_len,
116 extra_from, extra_dest, extra_len);
117}
118#endif
119
120#ifdef F__sif_cmd_int_handler
121int _SifCmdIntHandler(int channel)
122{
123 u128 packet[8];
124 u128 *pktbuf;
125 struct cmd_data *cmd_data = &_sif_cmd_data;
126 SifCmdHeader_t *header;
127 SifCmdHandlerData_t *cmd_handlers;
128 int size, pktquads, id, i = 0;
129
130 (void)channel;
131
132 EI();
133
134 header = (SifCmdHeader_t *)cmd_data->pktbuf;
135
136 if (!(size = header->psize))
137 goto out;
138
139 pktquads = (size + 30) >> 4;
140 header->psize = 0;
141 if (pktquads) {
142 pktbuf = (u128 *)cmd_data->pktbuf;
143 while (pktquads--) {
144 packet[i] = pktbuf[i];
145 i++;
146 }
147 }
148
149 iSifSetDChain();
150
151 header = (SifCmdHeader_t *)packet;
152 /* Get the command handler id and determine which handler list to
153 dispatch from. */
154 id = header->cid & ~SIF_CMD_ID_SYSTEM;
155
156 if (header->cid & SIF_CMD_ID_SYSTEM) {
157 if ((u32)id < cmd_data->nr_sys_handlers)
158 cmd_handlers = cmd_data->sys_cmd_handlers;
159 else
160 goto out;
161 } else {
162 if ((u32)id < cmd_data->nr_usr_handlers)
163 cmd_handlers = cmd_data->usr_cmd_handlers;
164 else
165 goto out;
166 }
167
168 if (cmd_handlers[id].handler)
169 cmd_handlers[id].handler(packet, cmd_handlers[id].harg);
170
171out:
172 ExitHandler();
173 return 0;
174}
175#endif
176
177#ifdef F_sif_cmd_main
178static u8 pktbuf[CMD_PACKET_MAX] __attribute__((aligned(64)));
179/* Define this so that in the unlikely case another SIF implementation decides
180 to use it, it won't crash. Otherwise unused. */
181static u8 sif_unused[64] __attribute__((aligned(64)));
182
183static SifCmdHandlerData_t sys_cmd_handlers[SYS_CMD_HANDLER_MAX];
184static int sregs[32];
185
186struct cmd_data _sif_cmd_data;
187static int init = 0;
188static int sif0_id = -1;
189
190struct ca_pkt
191{
192 SifCmdHeader_t header;
193 void *buf;
194};
195
196static void change_addr(void *packet, void *harg)
197{
198 struct cmd_data *cmd_data = (struct cmd_data *)harg;
199 struct ca_pkt *pkt = (struct ca_pkt *)packet;
200
201 cmd_data->iopbuf = pkt->buf;
202}
203
204struct sr_pkt
205{
206 SifCmdHeader_t header;
207 u32 sreg;
208 int val;
209};
210
211static void set_sreg(void *packet, void *harg)
212{
213 struct cmd_data *cmd_data = (struct cmd_data *)harg;
214 struct sr_pkt *pkt = (struct sr_pkt *)packet;
215
216 cmd_data->sregs[pkt->sreg] = pkt->val;
217}
218
219void SifInitCmd(void)
220{
221 static struct ca_pkt packet __attribute((aligned(64)));
222 int i;
223 static int _rb_count = 0;
224 if (_rb_count != _iop_reboot_count) {
225 _rb_count = _iop_reboot_count;
226 if (sif0_id >= 0) {
227 DisableDmac(DMAC_SIF0);
228 RemoveDmacHandler(DMAC_SIF0, sif0_id);
229 }
230 init = 0;
231 }
232
233 if (init)
234 return;
235
236 DI();
237
238 _sif_cmd_data.pktbuf = UNCACHED_SEG(pktbuf);
239 _sif_cmd_data.unused = UNCACHED_SEG(sif_unused);
240 _sif_cmd_data.sys_cmd_handlers = sys_cmd_handlers;
241 _sif_cmd_data.nr_sys_handlers = SYS_CMD_HANDLER_MAX;
242 _sif_cmd_data.usr_cmd_handlers = NULL;
243 _sif_cmd_data.nr_usr_handlers = 0;
244 _sif_cmd_data.sregs = sregs;
245
246 for (i = 0; i < SYS_CMD_HANDLER_MAX; i++) {
247 _sif_cmd_data.sys_cmd_handlers[i].handler = NULL;
248 _sif_cmd_data.sys_cmd_handlers[i].harg = NULL;
249 }
250
251 for (i = 0; i < 32; i++)
252 _sif_cmd_data.sregs[i] = 0;
253
254 _sif_cmd_data.sys_cmd_handlers[0].handler = change_addr;
255 _sif_cmd_data.sys_cmd_handlers[0].harg = &_sif_cmd_data;
256 _sif_cmd_data.sys_cmd_handlers[1].handler = set_sreg;
257 _sif_cmd_data.sys_cmd_handlers[1].harg = &_sif_cmd_data;
258
259 EI();
260 FlushCache(0);
261
262 if (_lw(DMAC_COMM_STAT) & STAT_SIF0)
263 _sw(STAT_SIF0, DMAC_COMM_STAT);
264
265 // If SIF0 (IOP -> EE) is not enabled, enable it.
266 if (!(_lw(DMAC_SIF0_CHCR) & CHCR_STR))
267 SifSetDChain();
268
269 sif0_id = AddDmacHandler(DMAC_SIF0, &_SifCmdIntHandler, 0);
270 EnableDmac(DMAC_SIF0);
271
272 init = 1;
273
274 _sif_cmd_data.iopbuf = (void *)SifGetReg(SIF_SYSREG_SUBADDR);
275 if (_sif_cmd_data.iopbuf) {
276 /* IOP SIF CMD is already initialized, so give it our new
277 receive address. */
278 packet.buf = _sif_cmd_data.pktbuf;
279 SifSendCmd(SIF_CMD_CHANGE_SADDR, &packet, sizeof packet, NULL, NULL, 0);
280 } else {
281 /* Sync with the IOP side's SIFCMD implementation. */
282 while (!(SifGetReg(SIF_REG_SMFLAG) & SIF_STAT_CMDINIT))
283 ;
284
285 _sif_cmd_data.iopbuf = (void *)SifGetReg(SIF_REG_SUBADDR);
286 SifSetReg(SIF_SYSREG_SUBADDR, (u32)_sif_cmd_data.iopbuf);
287 /* See the note above about struct cmd_data, and the use of
288 this register. */
289 SifSetReg(SIF_SYSREG_MAINADDR, (u32)&_sif_cmd_data);
290 packet.header.opt = 0; // SIFCMD initialization on the IOP (opt = 0)
291 packet.buf = _sif_cmd_data.pktbuf;
292 SifSendCmd(SIF_CMD_INIT_CMD, &packet, sizeof packet, NULL, NULL, 0);
293 }
294}
295
296void SifExitCmd(void)
297{
298 DisableDmac(DMAC_SIF0);
299 RemoveDmacHandler(DMAC_SIF0, sif0_id);
300 init = 0;
301}
302#endif
303
304#ifdef F_sif_cmd_client
305SifCmdHandlerData_t *SifSetCmdBuffer(SifCmdHandlerData_t *db, int size)
306{
308
309 old = _sif_cmd_data.usr_cmd_handlers;
310 _sif_cmd_data.usr_cmd_handlers = db;
311 _sif_cmd_data.nr_usr_handlers = size;
312
313 return old;
314}
315
316void SifAddCmdHandler(int pos, SifCmdHandler_t handler, void *harg)
317{
318 SifCmdHandlerData_t *cmd_handlers;
319 u32 id = pos & ~SIF_CMD_ID_SYSTEM;
320
321 cmd_handlers = (pos & SIF_CMD_ID_SYSTEM) ? _sif_cmd_data.sys_cmd_handlers : _sif_cmd_data.usr_cmd_handlers;
322
323 cmd_handlers[id].handler = handler;
324 cmd_handlers[id].harg = harg;
325}
326#endif
327
328#ifdef F_sif_cmd_remove_cmdhandler
329void SifRemoveCmdHandler(int pos)
330{
331 u32 id = pos & ~SIF_CMD_ID_SYSTEM;
332
333 if (pos & SIF_CMD_ID_SYSTEM)
334 _sif_cmd_data.sys_cmd_handlers[id].handler = NULL;
335 else
336 _sif_cmd_data.usr_cmd_handlers[id].handler = NULL;
337}
338#endif
339
340#ifdef F_sif_sreg_get
341int SifGetSreg(int sreg)
342{
343 return _sif_cmd_data.sregs[sreg];
344}
345#endif
#define SIF_CMD_ID_SYSTEM
Definition sifcmd.h:37
#define SIF_CMD_M_INTR
Definition sifcmd.h:102
#define SIF_CMD_M_WBDC
Definition sifcmd.h:104
void * iopbuf
Definition sifcmd.c:45
void * pktbuf
Definition sifcmd.c:42
void * dest
Definition sifcmd.h:29
#define SIF_STAT_CMDINIT
Definition sifdma.h:48
@ SIF_REG_SUBADDR
Definition sifdma.h:32
@ SIF_REG_SMFLAG
Definition sifdma.h:36
u32 count
start sector of fragmented bd/file