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 #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 
40 struct cmd_data
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 
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 sif0_id = -1;
186 
187 struct ca_pkt
188 {
189  SifCmdHeader_t header;
190  void *buf;
191 };
192 
193 static void change_addr(void *packet, void *harg)
194 {
195  struct cmd_data *cmd_data = (struct cmd_data *)harg;
196  struct ca_pkt *pkt = (struct ca_pkt *)packet;
197 
198  cmd_data->iopbuf = pkt->buf;
199 }
200 
201 struct sr_pkt
202 {
203  SifCmdHeader_t header;
204  u32 sreg;
205  int val;
206 };
207 
208 static void set_sreg(void *packet, void *harg)
209 {
210  struct cmd_data *cmd_data = (struct cmd_data *)harg;
211  struct sr_pkt *pkt = (struct sr_pkt *)packet;
212 
213  cmd_data->sregs[pkt->sreg] = pkt->val;
214 }
215 
216 void sceSifInitCmd(void)
217 {
218  static struct ca_pkt packet __attribute((aligned(64)));
219  int i;
221  sceSifExitCmd();
222 
223  if (sif0_id >= 0)
224  return;
225 
226  DI();
227 
228  _sif_cmd_data.pktbuf = UNCACHED_SEG(pktbuf);
229  _sif_cmd_data.unused = UNCACHED_SEG(sif_unused);
230  _sif_cmd_data.sys_cmd_handlers = sys_cmd_handlers;
231  _sif_cmd_data.nr_sys_handlers = SYS_CMD_HANDLER_MAX;
232  _sif_cmd_data.usr_cmd_handlers = NULL;
233  _sif_cmd_data.nr_usr_handlers = 0;
234  _sif_cmd_data.sregs = sregs;
235 
236  for (i = 0; i < SYS_CMD_HANDLER_MAX; i++) {
237  _sif_cmd_data.sys_cmd_handlers[i].handler = NULL;
238  _sif_cmd_data.sys_cmd_handlers[i].harg = NULL;
239  }
240 
241  for (i = 0; i < 32; i++)
242  _sif_cmd_data.sregs[i] = 0;
243 
244  _sif_cmd_data.sys_cmd_handlers[0].handler = change_addr;
245  _sif_cmd_data.sys_cmd_handlers[0].harg = &_sif_cmd_data;
246  _sif_cmd_data.sys_cmd_handlers[1].handler = set_sreg;
247  _sif_cmd_data.sys_cmd_handlers[1].harg = &_sif_cmd_data;
248 
249  EI();
250  FlushCache(0);
251 
252  if (_lw(DMAC_COMM_STAT) & STAT_SIF0)
253  _sw(STAT_SIF0, DMAC_COMM_STAT);
254 
255  // If SIF0 (IOP -> EE) is not enabled, enable it.
256  if (!(_lw(DMAC_SIF0_CHCR) & CHCR_STR))
257  sceSifSetDChain();
258 
259  sif0_id = AddDmacHandler(DMAC_SIF0, &_SifCmdIntHandler, 0);
260  EnableDmac(DMAC_SIF0);
261 
262 
263  _sif_cmd_data.iopbuf = (void *)sceSifGetReg(SIF_SYSREG_SUBADDR);
264  if (_sif_cmd_data.iopbuf) {
265  /* IOP SIF CMD is already initialized, so give it our new
266  receive address. */
267  packet.buf = _sif_cmd_data.pktbuf;
268  sceSifSendCmd(SIF_CMD_CHANGE_SADDR, &packet, sizeof packet, NULL, NULL, 0);
269  } else {
270  /* Sync with the IOP side's SIFCMD implementation. */
271  while (!(sceSifGetReg(SIF_REG_SMFLAG) & SIF_STAT_CMDINIT))
272  ;
273 
274  _sif_cmd_data.iopbuf = (void *)sceSifGetReg(SIF_REG_SUBADDR);
275  sceSifSetReg(SIF_SYSREG_SUBADDR, (u32)_sif_cmd_data.iopbuf);
276  /* See the note above about struct cmd_data, and the use of
277  this register. */
278  sceSifSetReg(SIF_SYSREG_MAINADDR, (u32)&_sif_cmd_data);
279  packet.header.opt = 0; // SIFCMD initialization on the IOP (opt = 0)
280  packet.buf = _sif_cmd_data.pktbuf;
281  sceSifSendCmd(SIF_CMD_INIT_CMD, &packet, sizeof packet, NULL, NULL, 0);
282  }
283 }
284 
285 void sceSifExitCmd(void)
286 {
287  if (sif0_id >= 0) {
288  DisableDmac(DMAC_SIF0);
289  RemoveDmacHandler(DMAC_SIF0, sif0_id);
290  sif0_id = -1;
291  }
292 }
293 #endif
294 
295 #ifdef F_sceSifSetCmdBuffer
296 void sceSifSetCmdBuffer(SifCmdHandlerData_t *db, int size)
297 {
298  _sif_cmd_data.usr_cmd_handlers = db;
299  _sif_cmd_data.nr_usr_handlers = size;
300 }
301 #endif
302 
303 #ifdef F_sceSifSetSysCmdBuffer
304 void sceSifSetSysCmdBuffer(SifCmdSysHandlerData_t *db, int size)
305 {
306  _sif_cmd_data.sys_cmd_handlers = db;
307  _sif_cmd_data.nr_sys_handlers = size;
308 }
309 #endif
310 
311 #ifdef F_sceSifAddCmdHandler
312 void sceSifAddCmdHandler(int cid, SifCmdHandler_t handler, void *harg)
313 {
314  u32 id = cid & ~SIF_CMD_ID_SYSTEM;
315 
316  if (cid & SIF_CMD_ID_SYSTEM)
317  {
318  _sif_cmd_data.sys_cmd_handlers[id].handler = handler;
319  _sif_cmd_data.sys_cmd_handlers[id].harg = harg;
320  }
321  else
322  {
323  _sif_cmd_data.usr_cmd_handlers[id].handler = handler;
324  _sif_cmd_data.usr_cmd_handlers[id].harg = harg;
325  }
326 }
327 #endif
328 
329 #ifdef F_sceSifRemoveCmdHandler
330 void sceSifRemoveCmdHandler(int cid)
331 {
332  u32 id = cid & ~SIF_CMD_ID_SYSTEM;
333 
334  if (cid & SIF_CMD_ID_SYSTEM)
335  _sif_cmd_data.sys_cmd_handlers[id].handler = NULL;
336  else
337  _sif_cmd_data.usr_cmd_handlers[id].handler = NULL;
338 }
339 #endif
340 
341 #ifdef F_sceSifGetSreg
342 unsigned int sceSifGetSreg(int sreg)
343 {
344  return _sif_cmd_data.sregs[sreg];
345 }
346 #endif
347 
348 #ifdef F_sceSifSetSreg
349 void sceSifSetSreg(int sreg, unsigned int value)
350 {
351  _sif_cmd_data.sregs[sreg] = value;
352 }
353 #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
iopcontrol.h
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:46
tamtypes.h
HasIopRebootedSinceLastCall
static int HasIopRebootedSinceLastCall(void)
Definition: iopcontrol.h:47
cmd_data
Definition: sifcmd.c:40
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:43
__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