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