PS2SDK
PS2 Homebrew Libraries
dma.c
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright ps2dev - http://www.ps2dev.org
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
9 */
10 
11 #include "accore_internal.h"
12 
13 static struct dma_softc Dmac;
14 
15 static int dma_cancel(struct dma_softc *dmac, acDmaT dma, int intr, int result)
16 {
17  int d_state;
18  acQueueT q_next;
19  acQueueT q_prev;
20  acSpl state;
21 
22  (void)dmac;
23  CpuSuspendIntr(&state);
24  d_state = dma->d_state;
25  if ( d_state )
26  {
27  if ( (unsigned int)d_state <= 3u )
28  {
29  if ( d_state == 3 )
30  {
31  dmac_disable(8u);
32  }
33  q_next = dma->d_chain.q_next;
34  q_prev = dma->d_chain.q_prev;
35  q_prev->q_next = q_next;
36  q_next->q_prev = q_prev;
37  }
38  else
39  {
40  d_state = -13;
41  }
42  }
43  else
44  {
45  d_state = -13;
46  }
47  CpuResumeIntr(state);
48  if ( d_state >= 0 )
49  {
50  acDmaOpsT ops;
51 
52  ops = dma->d_ops;
53  dma->d_state = 0;
54  ops->do_error(dma, intr, (acDmaState)d_state, result);
55  }
56  return d_state;
57 }
58 
59 static int dma_xfer(acDmaT dma, void *ioptr, void *buf, int count)
60 {
61  int slice;
62  int ret;
63  int slice_v2;
64  int ret_v3;
65  int state;
66 
67  slice = dma->d_slice;
68  if ( count >= 4 << slice )
69  {
70  ret = count >> (slice + 2);
71  slice_v2 = 1 << slice;
72  }
73  else
74  {
75  ret = count >> 2;
76  slice_v2 = 1;
77  }
78  CpuSuspendIntr(&state);
79  if ( dma == (acDmaT)Dmac.requestq.q_next && dma->d_state == 2 )
80  {
81  if ( ret > 0 )
82  {
83  int attr;
84  unsigned int v12;
85  int v13;
86  int v14;
87 
88  attr = dma->d_attr;
89  v12 = GetAcIoDelayReg() & 0x80FFDFFF;
90  v13 = 0x62000000;
91  if ( ioptr == (void *)0xB6000000 )
92  v13 = 0x24000000;
93  SetAcIoDelayReg(v12 | v13);
94  dmac_ch_set_dpcr(8u, (unsigned int)attr >> 5);
95  dmac_enable(8u);
96  v14 = dmac_request(8u, buf, slice_v2, ret, attr & 1);
97  if ( v14 == 1 )
98  {
99  *((volatile acUint32 *)0x1F801410) = ((unsigned int)ioptr & 0x3FFFFFF) | 0x14000000;
100  Dmac.status = 2;
101  dma->d_state = 3;
102  dmac_transfer(8u);
103  ret_v3 = 1;
104  }
105  else
106  {
107  Dmac.status = 1;
108  ret_v3 = -5;
109  }
110  }
111  else
112  {
113  ret_v3 = -22;
114  }
115  }
116  else
117  {
118  ret_v3 = -13;
119  }
120  CpuResumeIntr(state);
121  return ret_v3;
122 }
123 
124 static int dma_request(struct dma_softc *dmac, acDmaT dma, int intr)
125 {
126  acDmaState d_state;
127  acDmaOpsT ops;
128  int ret;
129  acSpl state;
130 
131  CpuSuspendIntr(&state);
132  if ( dma )
133  {
134  d_state = dma->d_state;
135  }
136  else
137  {
138  acDmaT q_next;
139 
140  q_next = (acDmaT)dmac->requestq.q_next;
141  d_state = AC_DMA_STATE_READY;
142  if ( dmac == (struct dma_softc *)q_next )
143  {
144  d_state = AC_DMA_STATE_FREE;
145  }
146  else
147  {
148  dma = (acDmaT)dmac->requestq.q_next;
149  q_next->d_state = 2;
150  }
151  }
152  ret = 0;
153  if ( dma )
154  {
155  int flg;
156  flg = 0;
157  ops = dma->d_ops;
158  if ( d_state == AC_DMA_STATE_QUEUE )
159  {
160  flg = 1;
161  }
162  else
163  {
164  if ( d_state )
165  {
166  if ( d_state != AC_DMA_STATE_READY )
167  {
168  ret = -13;
169  if ( d_state == AC_DMA_STATE_XFER )
170  {
171  ret = 0;
172  flg = 1;
173  }
174  }
175  }
176  else
177  {
178  acQueueT v10;
179  acDmaT state_v5;
180  unsigned int v12;
181 
182  v10 = dmac->requestq.q_next;
183  state_v5 = (acDmaT)dmac->requestq.q_prev;
184  dma->d_chain.q_next = &dmac->requestq;
185  v12 = (unsigned int)dmac ^ (unsigned int)v10;
186  ret = v12 == 0;
187  flg = v12 != 0;
188  dma->d_chain.q_prev = (acQueueT)state_v5;
189  state_v5->d_chain.q_next = &dma->d_chain;
190  dmac->requestq.q_prev = &dma->d_chain;
191  }
192  if ( ret < 0 )
193  {
194  flg = 0;
195  }
196  }
197  if ( !flg )
198  {
199  ret = -13;
200  if ( dma == (acDmaT)dmac->requestq.q_next )
201  {
202  if ( !ops->do_xfer )
203  {
204  ret = -14;
205  }
206  else
207  {
208  dma->d_state = 2;
209  CpuResumeIntr(state);
210  ret = ops->do_xfer(dma, intr, dma_xfer);
211  CpuSuspendIntr(&state);
212  if ( dma->d_state == 3 )
213  {
214  ret = 0;
215  }
216  }
217  }
218  flg = 1;
219  }
220  if ( ret < 0 )
221  {
222  flg = 0;
223  }
224  if ( flg )
225  {
226  acUint8 v13;
227 
228  v13 = dma->d_state + ret;
229  ret = dma->d_state;
230  dma->d_state = v13;
231  }
232  }
233  CpuResumeIntr(state);
234  if ( ret < 0 )
235  {
236  dma_cancel(dmac, dma, intr, ret);
237  }
238  return ret;
239 }
240 
241 int acDmaRequest(acDmaT dma)
242 {
243  int ret;
244 
245  ret = dma_request(&Dmac, dma, 0);
246  if ( ret < 0 )
247  {
248  while ( dma_request(&Dmac, 0, 0) < 0 )
249  ;
250  }
251  return ret;
252 }
253 
254 int acDmaRequestI(acDmaT dma)
255 {
256  int ret;
257 
258  ret = dma_request(&Dmac, dma, 1);
259  if ( ret < 0 )
260  {
261  while ( dma_request(&Dmac, 0, 1) < 0 )
262  ;
263  }
264  return ret;
265 }
266 
267 int acDmaCancel(acDmaT dma, int result)
268 {
269  int ret;
270 
271  ret = dma_cancel(&Dmac, dma, 0, result);
272  if ( ret >= 0 )
273  {
274  while ( dma_request(&Dmac, 0, 0) < 0 )
275  ;
276  }
277  return ret;
278 }
279 
280 int acDmaCancelI(acDmaT dma, int result)
281 {
282  int ret;
283 
284  ret = dma_cancel(&Dmac, dma, 1, result);
285  if ( ret >= 0 )
286  {
287  while ( dma_request(&Dmac, 0, 1) < 0 )
288  ;
289  }
290  return ret;
291 }
292 
293 static int dma_intr(void *arg)
294 {
295  acDmaData *q_next;
296  acQueueData *v3;
297  acQueueT q_prev;
298  struct dma_softc *argt;
299 
300  argt = (struct dma_softc *)arg;
301  if ( argt )
302  {
303  dmac_disable(8u);
304  q_next = (acDmaData *)argt->requestq.q_next;
305  if ( argt != (struct dma_softc *)q_next )
306  {
307  acDmaOpsT ops;
308  acDmaState state;
309 
310  v3 = q_next->d_chain.q_next;
311  q_prev = q_next->d_chain.q_prev;
312  ops = q_next->d_ops;
313  state = q_next->d_state;
314  q_prev->q_next = v3;
315  v3->q_prev = q_prev;
316  q_next->d_state = 0;
317  if ( state == AC_DMA_STATE_XFER )
318  ops->do_done(q_next);
319  else
320  ops->do_error(q_next, 1, state, -13);
321  }
322  while ( dma_request(&Dmac, 0, 1) < 0 )
323  ;
324  }
325  return 1;
326 }
327 
328 acDmaT acDmaSetup(acDmaData *dma, acDmaOpsData *ops, int priority, int slice, int output)
329 {
330  if ( dma )
331  {
332  acUint32 x;
333  unsigned int v6;
334 
335  dma->d_ops = ops;
336  dma->d_attr = (32 * priority) | (output != 0);
337  x = slice / 4;
338  v6 = 0;
339  if ( x > 1 )
340  {
341  v6 = 1;
342  while ( ((unsigned int)1 << v6) < x )
343  {
344  v6 = v6 + 1;
345  }
346  v6 = v6 - 1;
347  }
348  dma->d_slice = v6;
349  dma->d_state = 0;
350  }
351  return dma;
352 }
353 
354 int acDmaModuleStart(int argc, char **argv)
355 {
356  int ret;
357  char *msg;
358 
359  (void)argc;
360  (void)argv;
361  if ( Dmac.status )
362  {
363  return -16;
364  }
365  Dmac.requestq.q_prev = (acQueueT)&Dmac;
366  Dmac.requestq.q_next = (acQueueT)&Dmac;
367  ret = RegisterIntrHandler(41, 1, dma_intr, &Dmac);
368  if ( !ret || ret == -104 )
369  {
370  ret = EnableIntr(41);
371  if ( !ret )
372  {
373  dmac_disable(8u);
374  Dmac.status = 1;
375  return 0;
376  }
377  ReleaseIntrHandler(41);
378  msg = "dma_intr_enable";
379  }
380  else
381  {
382  msg = "dma_intr_register";
383  }
384  printf("accore:dma_init:%s: error %d\n", msg, ret);
385  return -6;
386 }
387 
388 int acDmaModuleStop()
389 {
390  int dummy;
391 
392  if ( Dmac.status )
393  {
394  DisableIntr(41, &dummy);
395  ReleaseIntrHandler(41);
396  Dmac.status = 0;
397  }
398  return 0;
399 }
400 
401 int acDmaModuleRestart(int argc, char **argv)
402 {
403  (void)argc;
404  (void)argv;
405  return -88;
406 }
407 
408 int acDmaModuleStatus()
409 {
410  return Dmac.status;
411 }
RegisterIntrHandler
int RegisterIntrHandler(int irq, int mode, int(*handler)(void *arg), void *arg)
Definition: intrman.c:115
ac_dma
Definition: accore.h:61
ReleaseIntrHandler
int ReleaseIntrHandler(int irq)
Definition: intrman.c:157
ac_queue
Definition: accore.h:52
DisableIntr
int DisableIntr(int irq, int *res)
Definition: intrman.c:385
CpuSuspendIntr
int CpuSuspendIntr(int *state)
Definition: intrman.c:195
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
EnableIntr
int EnableIntr(int irq)
Definition: intrman.c:336
CpuResumeIntr
int CpuResumeIntr(int state)
Definition: intrman.c:217
ac_dma_ops
Definition: accore.h:41
dma_softc
Definition: accore_internal.h:19