sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
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
18
19#include <tamtypes.h>
20#include <kernel.h>
21#include <sifcmd.h>
22#include <iopcontrol.h>
23
24#define CMD_PACKET_MAX 128
25#define CMD_PACKET_DATA_MAX 112
26#define SYS_CMD_HANDLER_MAX 32
27
28/* EE DMAC registers. */
29#define DMAC_COMM_STAT 0x1000e010
30#define DMAC_SIF0_CHCR 0x1000c000
31#define CHCR_STR 0x100
32#define STAT_SIF0 0x20
33
41{
43 void *pktbuf;
44 void *unused;
46 void *iopbuf;
47 SifCmdSysHandlerData_t *sys_cmd_handlers;
48 u32 nr_sys_handlers;
49 SifCmdHandlerData_t *usr_cmd_handlers;
50 u32 nr_usr_handlers;
51 int *sregs;
52} __attribute__((aligned(64)));
53
54extern struct cmd_data _sif_cmd_data;
55extern unsigned int _SifSendCmd(int cid, int mode, void *pkt, int pktsize, void *src,
56 void *dest, int size);
57extern int _SifCmdIntHandler(int channel);
58
59unsigned int _SifSendCmd(int cid, int mode, void *pkt, int pktsize, void *src,
60 void *dest, int size)
61{
62 SifDmaTransfer_t dmat[2];
63 SifCmdHeader_t *header;
64 int count = 0;
65
66 pktsize &= 0xff;
67
68 if (pktsize > CMD_PACKET_DATA_MAX)
69 return 0;
70
71 header = (SifCmdHeader_t *)pkt;
72 header->cid = cid;
73 header->psize = pktsize;
74 header->dest = NULL;
75
76 if (size > 0) {
77 header->dsize = size;
78 header->dest = dest;
79
80 if (mode & SIF_CMD_M_WBDC) /* if mode is & 4, flush reference cache */
81 sceSifWriteBackDCache(src, size);
82
83 dmat[count].src = src;
84 dmat[count].dest = dest;
85 dmat[count].size = size;
86 dmat[count].attr = 0;
87 count++;
88 }
89
90 dmat[count].src = pkt;
91 dmat[count].dest = _sif_cmd_data.iopbuf;
92 dmat[count].size = pktsize;
93 dmat[count].attr = SIF_DMA_ERT | SIF_DMA_INT_O;
94 count++;
95
96 sceSifWriteBackDCache(pkt, pktsize);
97
98 if (mode & SIF_CMD_M_INTR) /* INTERRUPT DMA TRANSFER */
99 return isceSifSetDma(dmat, count);
100 else
101 return sceSifSetDma(dmat, count);
102}
103
104unsigned int sceSifSendCmd(int cid, void *packet, int packet_size, void *src_extra,
105 void *dest_extra, int size_extra)
106{
107 return _SifSendCmd(cid, 0, packet, packet_size,
108 src_extra, dest_extra, size_extra);
109}
110
111unsigned int isceSifSendCmd(int cid, void *packet, int packet_size, void *src_extra,
112 void *dest_extra, int size_extra)
113{
114 return _SifSendCmd(cid, SIF_CMD_M_INTR, packet, packet_size,
115 src_extra, dest_extra, size_extra);
116}
117
118int _SifCmdIntHandler(int channel)
119{
120 u128 packet[8];
121 u128 *pktbuf;
122 struct cmd_data *cmd_data = &_sif_cmd_data;
123 SifCmdHeader_t *header;
124 int size, pktquads, id, i = 0;
125
126 (void)channel;
127
128 EI();
129
130 header = (SifCmdHeader_t *)cmd_data->pktbuf;
131
132 if (!(size = header->psize))
133 goto out;
134
135 pktquads = (size + 30) >> 4;
136 header->psize = 0;
137 if (pktquads) {
138 pktbuf = (u128 *)cmd_data->pktbuf;
139 while (pktquads--) {
140 packet[i] = pktbuf[i];
141 i++;
142 }
143 }
144
145 isceSifSetDChain();
146
147 header = (SifCmdHeader_t *)packet;
148 /* Get the command handler id and determine which handler list to
149 dispatch from. */
150 id = header->cid & ~SIF_CMD_ID_SYSTEM;
151
152 if (header->cid & SIF_CMD_ID_SYSTEM) {
153 if ((u32)id < cmd_data->nr_sys_handlers)
154 if (cmd_data->sys_cmd_handlers[id].handler)
155 cmd_data->sys_cmd_handlers[id].handler(packet, cmd_data->sys_cmd_handlers[id].harg);
156 } else {
157 if ((u32)id < cmd_data->nr_usr_handlers)
158 if (cmd_data->usr_cmd_handlers[id].handler)
159 cmd_data->usr_cmd_handlers[id].handler(packet, cmd_data->usr_cmd_handlers[id].harg);
160 }
161
162out:
163 ExitHandler();
164 return 0;
165}
166
167static u8 pktbuf[CMD_PACKET_MAX] __attribute__((aligned(64)));
168/* Define this so that in the unlikely case another SIF implementation decides
169 to use it, it won't crash. Otherwise unused. */
170static u8 sif_unused[64] __attribute__((aligned(64)));
171
172static SifCmdSysHandlerData_t sys_cmd_handlers[SYS_CMD_HANDLER_MAX];
173static int sregs[32];
174
175struct cmd_data _sif_cmd_data;
176static int sif0_id;
177
178struct ca_pkt
179{
180 SifCmdHeader_t header;
181 void *buf;
182};
183
184static void change_addr(void *packet, void *harg)
185{
186 struct cmd_data *cmd_data = (struct cmd_data *)harg;
187 struct ca_pkt *pkt = (struct ca_pkt *)packet;
188
189 cmd_data->iopbuf = pkt->buf;
190}
191
192struct sr_pkt
193{
194 SifCmdHeader_t header;
195 u32 sreg;
196 int val;
197};
198
199static void set_sreg(void *packet, void *harg)
200{
201 struct cmd_data *cmd_data = (struct cmd_data *)harg;
202 struct sr_pkt *pkt = (struct sr_pkt *)packet;
203
204 cmd_data->sregs[pkt->sreg] = pkt->val;
205}
206
207void sceSifInitCmd(void)
208{
209 static struct ca_pkt packet __attribute((aligned(64)));
210 int i;
211 if (HasIopRebootedSinceLastCall())
212 sceSifExitCmd();
213
214 if (sif0_id > 0)
215 return;
216
217 DI();
218
219 _sif_cmd_data.pktbuf = UNCACHED_SEG(pktbuf);
220 _sif_cmd_data.unused = UNCACHED_SEG(sif_unused);
221 _sif_cmd_data.sys_cmd_handlers = sys_cmd_handlers;
222 _sif_cmd_data.nr_sys_handlers = SYS_CMD_HANDLER_MAX;
223 _sif_cmd_data.usr_cmd_handlers = NULL;
224 _sif_cmd_data.nr_usr_handlers = 0;
225 _sif_cmd_data.sregs = sregs;
226
227 for (i = 0; i < SYS_CMD_HANDLER_MAX; i++) {
228 _sif_cmd_data.sys_cmd_handlers[i].handler = NULL;
229 _sif_cmd_data.sys_cmd_handlers[i].harg = NULL;
230 }
231
232 for (i = 0; i < 32; i++)
233 _sif_cmd_data.sregs[i] = 0;
234
235 _sif_cmd_data.sys_cmd_handlers[0].handler = change_addr;
236 _sif_cmd_data.sys_cmd_handlers[0].harg = &_sif_cmd_data;
237 _sif_cmd_data.sys_cmd_handlers[1].handler = set_sreg;
238 _sif_cmd_data.sys_cmd_handlers[1].harg = &_sif_cmd_data;
239
240 EI();
241 FlushCache(0);
242
243 if (_lw(DMAC_COMM_STAT) & STAT_SIF0)
244 _sw(STAT_SIF0, DMAC_COMM_STAT);
245
246 // If SIF0 (IOP -> EE) is not enabled, enable it.
247 if (!(_lw(DMAC_SIF0_CHCR) & CHCR_STR))
248 sceSifSetDChain();
249
250 sif0_id = AddDmacHandler(DMAC_SIF0, &_SifCmdIntHandler, 0);
251 EnableDmac(DMAC_SIF0);
252
253
254 _sif_cmd_data.iopbuf = (void *)sceSifGetReg(SIF_SYSREG_SUBADDR);
255 if (_sif_cmd_data.iopbuf) {
256 /* IOP SIF CMD is already initialized, so give it our new
257 receive address. */
258 packet.buf = _sif_cmd_data.pktbuf;
259 sceSifSendCmd(SIF_CMD_CHANGE_SADDR, &packet, sizeof packet, NULL, NULL, 0);
260 } else {
261 /* Sync with the IOP side's SIFCMD implementation. */
262 while (!(sceSifGetReg(SIF_REG_SMFLAG) & SIF_STAT_CMDINIT))
263 ;
264
265 _sif_cmd_data.iopbuf = (void *)sceSifGetReg(SIF_REG_SUBADDR);
266 sceSifSetReg(SIF_SYSREG_SUBADDR, (u32)_sif_cmd_data.iopbuf);
267 /* See the note above about struct cmd_data, and the use of
268 this register. */
269 sceSifSetReg(SIF_SYSREG_MAINADDR, (u32)&_sif_cmd_data);
270 packet.header.opt = 0; // SIFCMD initialization on the IOP (opt = 0)
271 packet.buf = _sif_cmd_data.pktbuf;
272 sceSifSendCmd(SIF_CMD_INIT_CMD, &packet, sizeof packet, NULL, NULL, 0);
273 }
274}
275
276void sceSifExitCmd(void)
277{
278 if (sif0_id > 0) {
279 DisableDmac(DMAC_SIF0);
280 RemoveDmacHandler(DMAC_SIF0, sif0_id);
281 sif0_id = 0;
282 }
283}
284
285void sceSifSetCmdBuffer(SifCmdHandlerData_t *db, int size)
286{
287 _sif_cmd_data.usr_cmd_handlers = db;
288 _sif_cmd_data.nr_usr_handlers = size;
289}
290
291void sceSifSetSysCmdBuffer(SifCmdSysHandlerData_t *db, int size)
292{
293 _sif_cmd_data.sys_cmd_handlers = db;
294 _sif_cmd_data.nr_sys_handlers = size;
295}
296
297void sceSifAddCmdHandler(int cid, SifCmdHandler_t handler, void *harg)
298{
299 u32 id = cid & ~SIF_CMD_ID_SYSTEM;
300
301 if (cid & SIF_CMD_ID_SYSTEM)
302 {
303 _sif_cmd_data.sys_cmd_handlers[id].handler = handler;
304 _sif_cmd_data.sys_cmd_handlers[id].harg = harg;
305 }
306 else
307 {
308 _sif_cmd_data.usr_cmd_handlers[id].handler = handler;
309 _sif_cmd_data.usr_cmd_handlers[id].harg = harg;
310 }
311}
312
313void sceSifRemoveCmdHandler(int cid)
314{
315 u32 id = cid & ~SIF_CMD_ID_SYSTEM;
316
317 if (cid & SIF_CMD_ID_SYSTEM)
318 _sif_cmd_data.sys_cmd_handlers[id].handler = NULL;
319 else
320 _sif_cmd_data.usr_cmd_handlers[id].handler = NULL;
321}
322
323unsigned int sceSifGetSreg(int sreg)
324{
325 return _sif_cmd_data.sregs[sreg];
326}
327
328void sceSifSetSreg(int sreg, unsigned int value)
329{
330 _sif_cmd_data.sregs[sreg] = value;
331}
void * pktbuf
Definition sifcmd.c:1
struct t_SifCmdHeader SifCmdHeader_t
#define SIF_CMD_ID_SYSTEM
#define SIF_CMD_M_INTR
#define SIF_CMD_M_WBDC
#define SIF_STAT_CMDINIT
Definition sifdma.h:49
@ SIF_REG_SUBADDR
Definition sifdma.h:33
@ SIF_REG_SMFLAG
Definition sifdma.h:37
void * iopbuf
Definition sifcmd.c:46
void * pktbuf
Definition sifcmd.c:43
u32 count
start sector of fragmented bd/file