PS2SDK
PS2 Homebrew Libraries
atapicmd.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 "acata_internal.h"
12 
13 #include "atahw.h"
14 
15 static int atapi_dma_xfer(acDmaT dma, int intr, acDmaOp op);
16 static void atapi_dma_done(acDmaT dma);
17 static void atapi_dma_error(acDmaT dma, int intr, acDmaState state, int result);
18 static int atapi_ops_command(struct ac_ata_h *atah, int cmdpri, int pri);
19 static void atapi_ops_done(struct ac_ata_h *atah, int result);
20 static int atapi_ops_error(struct ac_ata_h *atah, int ret);
21 
22 static acDmaOpsData ops_8_0 = {&atapi_dma_xfer, &atapi_dma_done, &atapi_dma_error};
23 static struct ac_ata_ops ops_48 = {&atapi_ops_command, &atapi_ops_done, &atapi_ops_error};
24 
25 static int atapi_dma_xfer(acDmaT dma, int intr, acDmaOp op)
26 {
27  struct atapi_dma *dmatmp;
28  int thid;
29 
30  dmatmp = (struct atapi_dma *)dma;
31  if ( dmatmp->ad_state == 31 )
32  {
33  dmatmp->ad_result = dmatmp->ad_atapi->ap_h.a_size;
34  return op(dma, (void *)0xB6000000, dmatmp->ad_atapi->ap_h.a_buf, dmatmp->ad_atapi->ap_h.a_size);
35  }
36  thid = dmatmp->ad_thid;
37  dmatmp->ad_state = 3;
38  if ( intr )
39  iWakeupThread(thid);
40  else
41  WakeupThread(thid);
42  return 0;
43 }
44 
45 static void atapi_dma_done(acDmaT dma)
46 {
47  struct atapi_dma *dmatmp;
48  int thid;
49 
50  dmatmp = (struct atapi_dma *)dma;
51  thid = dmatmp->ad_thid;
52  dmatmp->ad_state = 127;
53  if ( thid )
54  iWakeupThread(thid);
55 }
56 
57 static void atapi_dma_error(acDmaT dma, int intr, acDmaState state, int result)
58 {
59  struct atapi_dma *dmatmp;
60  int thid;
61 
62  dmatmp = (struct atapi_dma *)dma;
63  thid = dmatmp->ad_thid;
64  dmatmp->ad_state = 1023;
65  dmatmp->ad_result = result;
66  if ( thid )
67  {
68  if ( intr )
69  iWakeupThread(thid);
70  else
71  WakeupThread(thid);
72  }
73  Kprintf("acata:P:dma_error: state=%d ret=%d\n", state, result);
74 }
75 
76 static int atapi_packet_send(acAtaReg atareg, acAtapiPacketData *pkt, int flag)
77 {
78  int count;
79  int tmout;
80  int v6;
81 
82  (void)atareg;
83  count = 6;
84  *((volatile acUint16 *)0xB6050000) = 0;
85  *((volatile acUint16 *)0xB6040000) = 64;
86  *((volatile acUint16 *)0xB6060000) = flag & 0x10;
87  *((volatile acUint16 *)0xB6160000) = (flag & 2) ^ 2;
88  *((volatile acUint16 *)0xB6010000) = flag & 1;
89  *((volatile acUint16 *)0xB6070000) = 160; // ATA_STAT_BUSY|ATA_STAT_READY?
90  tmout = 999;
91  v6 = 1000;
92  // cppcheck-suppress knownConditionTrueFalse
93  while ( (*((volatile acUint16 *)0xB6070000) & ATA_STAT_BUSY) != 0 )
94  {
95  if ( tmout < 0 )
96  {
97  printf("acata:P:wait: TIMEDOUT\n");
98  v6 = -116;
99  break;
100  }
101  --tmout;
102  v6 = tmout + 1;
103  }
104  if ( v6 < 0 )
105  {
106  printf("acata:P:packet_send: TIMEDOUT\n");
107  return -116;
108  }
109  // cppcheck-suppress knownConditionTrueFalse
110  while ( (*((volatile acUint16 *)0xB6070000) & ATA_STAT_DRQ) != 0 )
111  {
112  --count;
113  if ( count < 0 )
114  break;
115  *((volatile acUint16 *)0xB6000000) = pkt->u_h[0];
116  pkt = (acAtapiPacketData *)((char *)pkt + 2);
117  }
118  return 0;
119 }
120 
121 static int atapi_pio_read(acAtaReg atareg, acUint16 *buf, int count, int flag)
122 {
123  char v6;
124  int rest;
125  int sr;
126  int xlen;
127  int sr_v5;
128  int drop_v10;
129 
130  (void)atareg;
131  v6 = flag;
132  rest = count;
133  sr = flag & 2;
134  while ( 1 )
135  {
136  int xlen_v6;
137  int drop;
138  int xlen_v8;
139  int sr_v9;
140 
141  if ( !sr )
142  {
143  sr_v5 = *((volatile acUint16 *)0xB6070000);
144  while ( (sr_v5 & ATA_STAT_BUSY) != 0 )
145  {
146  xlen = *((volatile acUint16 *)0xB6070000);
147  sr_v5 = xlen & 0xFF;
148  }
149  }
150  else
151  {
152  xlen = *((volatile acUint16 *)0xB6160000);
153  sr_v5 = xlen & 0xFF;
154  while ( (sr_v5 & 0x80) != 0 )
155  {
156  sr_v5 = -116;
157  if ( SleepThread() != 0 )
158  break;
159  sr_v5 = *((volatile acUint16 *)0xB6160000);
160  }
161  }
162  if ( sr_v5 < 0 )
163  return sr_v5;
164  if ( (sr_v5 & 8) == 0 )
165  break;
166  xlen_v6 = (*((volatile acUint16 *)0xB6050000) << 8) + *((volatile acUint16 *)0xB6040000);
167  drop = xlen_v6 - rest;
168  if ( rest >= xlen_v6 )
169  drop = 0;
170  else
171  xlen_v6 = rest;
172  rest -= xlen_v6;
173  xlen_v8 = (xlen_v6 + 1) / 2 - 1;
174  while ( xlen_v8 >= 0 )
175  {
176  --xlen_v8;
177  *buf++ = *((volatile acUint16 *)0xB6000000);
178  }
179  sr_v9 = drop + 1;
180  for ( drop_v10 = sr_v9 / 2 - 1; drop_v10 >= 0; --drop_v10 )
181  ;
182  sr = v6 & 2;
183  if ( (*((volatile acUint16 *)0xB6070000) & ATA_STAT_BUSY) == 0 )
184  {
185  break;
186  }
187  }
188  return count - rest;
189 }
190 
191 static int atapi_ops_command(struct ac_ata_h *atah, int cmdpri, int pri)
192 {
193  int flag;
194  int ret_v5;
195  int v28;
196  struct atapi_dma dma_data;
197  acAtapiT atapi;
198 
199  atapi = (acAtapiT)atah;
200  flag = atah->a_flag;
201  if ( (flag & 1) == 0 )
202  {
203  ret_v5 = 0;
204  }
205  else
206  {
207  acDmaT dma;
208  int v8;
209  int ret;
210 
211  dma = acDmaSetup(&dma_data.ad_dma, &ops_8_0, 4, 64, flag & 4);
212  dma_data.ad_result = 0;
213  // cppcheck-suppress unreadVariable
214  dma_data.ad_thid = GetThreadId();
215  // cppcheck-suppress unreadVariable
216  dma_data.ad_atapi = atapi;
217  dma_data.ad_state = 0;
218  v8 = acDmaRequest(dma);
219  ret = v8;
220  if ( v8 < 0 )
221  {
222  printf("acata:P:dma_wait: error %d\n", v8);
223  ret_v5 = ret;
224  }
225  else
226  {
227  while ( 1 )
228  {
229  int flg;
230 
231  flg = 0;
232  ret_v5 = dma_data.ad_state;
233  if ( ret_v5 )
234  {
235  if ( (int)ret_v5 > 0 )
236  {
237  ret_v5 = 0;
238  break;
239  }
240  flg = 1;
241  }
242  if ( flg == 0 && SleepThread() )
243  flg = 1;
244  if ( flg != 0 )
245  {
246  printf("acata:P:dma_wait: TIMEDOUT %d\n", ret_v5);
247  acDmaCancel(&dma_data.ad_dma, -116);
248  if ( ret_v5 >= 0 )
249  {
250  ret_v5 = -116;
251  }
252  break;
253  }
254  }
255  }
256  }
257  if ( ret_v5 < 0 )
258  return ret_v5;
259  ChangeThreadPriority(TH_SELF, cmdpri);
260  ret_v5 = atapi_packet_send((acAtaReg)0xB6000000, &atapi->ap_packet, flag);
261  if ( ret_v5 >= 0 )
262  {
263  int v12;
264  if ( atah->a_state < 0x1FFu )
265  {
266  atah->a_state = 31;
267  v12 = 0;
268  }
269  else
270  {
271  v12 = -116;
272  }
273  ret_v5 = -116;
274  if ( v12 >= 0 )
275  {
276  acUint16 *a_buf;
277 
278  a_buf = (acUint16 *)atah->a_buf;
279  if ( !a_buf )
280  {
281  ret_v5 = 0;
282  }
283  else if ( (flag & 1) != 0 )
284  {
285  dma_data.ad_state = 31;
286  ret_v5 = acDmaRequest(&dma_data.ad_dma);
287  }
288  else
289  {
290  int size;
291  acUint16 *v15;
292 
293  size = atah->a_size;
294  v15 = (acUint16 *)atah->a_buf;
295  if ( (flag & 4) == 0 )
296  {
297  ret_v5 = atapi_pio_read((acAtaReg)0xB6000000, a_buf, atah->a_size, flag);
298  }
299  else
300  {
301  signed int a_size;
302  int sr;
303 
304  a_size = atah->a_size;
305  sr = flag & 2;
306  while ( 1 )
307  {
308  int xlen;
309  int sr_v14;
310  int xlen_v15;
311  int drop;
312  int xlen_v17;
313  int sr_v18;
314  int drop_v20;
315 
316  if ( sr )
317  {
318  xlen = *((volatile acUint16 *)0xB6160000);
319  sr_v14 = xlen & 0xFF;
320  while ( (sr_v14 & 0x80) != 0 )
321  {
322  sr_v14 = -116;
323  if ( SleepThread() != 0 )
324  break;
325  sr_v14 = *((volatile acUint16 *)0xB6160000);
326  }
327  }
328  else
329  {
330  sr_v14 = *((volatile acUint16 *)0xB6070000);
331  while ( (sr_v14 & ATA_STAT_BUSY) != 0 )
332  {
333  xlen = *((volatile acUint16 *)0xB6070000);
334  sr_v14 = xlen & 0xFF;
335  }
336  }
337  ret_v5 = sr_v14;
338  if ( sr_v14 < 0 )
339  break;
340  if ( (sr_v14 & 8) == 0 )
341  {
342  ret_v5 = size - a_size;
343  break;
344  }
345  xlen_v15 = (*((volatile acUint16 *)0xB6050000) << 8) + *((volatile acUint16 *)0xB6040000);
346  drop = xlen_v15 - a_size;
347  if ( a_size >= xlen_v15 )
348  drop = 0;
349  else
350  xlen_v15 = a_size;
351  a_size -= xlen_v15;
352  xlen_v17 = (xlen_v15 + 1) / 2 - 1;
353  for ( sr_v18 = drop + 1; xlen_v17 >= 0; sr_v18 = drop + 1 )
354  {
355  *((volatile acUint16 *)0xB6000000) = *v15;
356  v15++;
357  --xlen_v17;
358  }
359  for ( drop_v20 = sr_v18 / 2 - 1; drop_v20 >= 0; --drop_v20 )
360  *((volatile acUint16 *)0xB6000000) = 0;
361  sr = flag & 2;
362  if ( (*((volatile acUint16 *)0xB6070000) & ATA_STAT_BUSY) == 0 )
363  {
364  ret_v5 = size - a_size;
365  break;
366  }
367  }
368  }
369  }
370  }
371  }
372  ChangeThreadPriority(TH_SELF, pri);
373  if ( ret_v5 < 0 )
374  return ret_v5;
375  if ( atah->a_state < 0x1FFu )
376  {
377  atah->a_state = 63;
378  v28 = 0;
379  }
380  else
381  {
382  v28 = -116;
383  }
384  if ( v28 < 0 )
385  return -116;
386  if ( (flag & 1) == 0 )
387  {
388  int v32;
389 
390  v32 = 0;
391  if ( (flag & 2) != 0 )
392  {
393  while ( (*((volatile acUint16 *)0xB6160000) & (ATA_STAT_BUSY|ATA_STAT_ERR)) == ATA_STAT_BUSY )
394  {
395  if ( SleepThread() )
396  {
397  v32 = -116;
398  break;
399  }
400  }
401  }
402  else
403  {
404  int tmout;
405 
406  tmout = 99999;
407  while ( (*((volatile acUint16 *)0xB6070000) & (ATA_STAT_BUSY|ATA_STAT_ERR)) == ATA_STAT_BUSY )
408  {
409  if ( tmout < 0 )
410  {
411  v32 = -116;
412  break;
413  }
414  --tmout;
415  }
416  }
417  if ( v32 < 0 )
418  {
419  printf("acata:C:io_done: TIMEDOUT\n");
420  ret_v5 = -116;
421  }
422  }
423  else
424  {
425  signed int ret_v23;
426  acInt32 ad_result;
427 
428  ret_v23 = 63;
429  while ( 1 )
430  {
431  int v30;
432 
433  v30 = *((volatile acUint16 *)0xB6160000) & 1;
434  if ( v30 || ret_v23 >= 511 )
435  {
436  printf(
437  "acata:P:dma_iowait: TIMEDOUT %04x:%02x:%02x\n",
438  ret_v23,
439  *((volatile acUint16 *)0xB6160000),
440  *((volatile acUint16 *)0xB6010000));
441  if ( ret_v23 < 1023 )
442  acDmaCancel(&dma_data.ad_dma, -116);
443  ad_result = 0;
444  if ( !v30 )
445  ad_result = -116;
446  break;
447  }
448  ret_v23 = dma_data.ad_state;
449  if ( (*((volatile acUint16 *)0xB6160000) & 0x80) == 0 && (int)dma_data.ad_state >= 64 )
450  {
451  ad_result = dma_data.ad_result;
452  break;
453  }
454  if ( SleepThread() )
455  {
456  ret_v23 = 511;
457  if ( dma_data.ad_state == 31 )
458  ret_v23 = 1023;
459  }
460  }
461  ret_v5 = ad_result;
462  }
463  if ( ret_v5 < 0 )
464  return ret_v5;
465  if ( (*((volatile acUint16 *)0xB6070000) & ATA_STAT_ERR) != 0 )
466  return -((*((volatile acUint16 *)0xB6070000) << 8) + *((volatile acUint16 *)0xB6010000));
467  if ( atah->a_state >= 0x1FFu )
468  {
469  return -116;
470  }
471  atah->a_state = 127;
472  return ret_v5;
473 }
474 
475 static void atapi_ops_done(struct ac_ata_h *atah, int result)
476 {
477  acAtapiDone ap_done;
478  acAtapiT atapi;
479 
480  atapi = (acAtapiT)atah;
481  ap_done = atapi->ap_done;
482  if ( ap_done )
483  ap_done(atapi, atah->a_arg, result);
484 }
485 
486 static int atapi_ops_error(struct ac_ata_h *atah, int ret)
487 {
488  int flag;
489  int v3;
490  struct atapi_sense sense;
491  union
492  {
493  struct
494  {
495  acUint8 opcode;
496  acUint8 lun;
497  // cppcheck-suppress unusedStructMember
498  acUint8 padding[2];
499  acUint8 len;
500  // cppcheck-suppress unusedStructMember
501  acUint8 padding2[7];
502  };
503  acAtapiPacketData pkt;
504  } u;
505  acAtapiT atapi;
506 
507  atapi = (acAtapiT)atah;
508  if ( (*((volatile acUint16 *)0xB6070000) & ATA_STAT_ERR) == 0 )
509  return ret;
510  memset(&sense, 0, sizeof(sense));
511  memset(&u, 0, sizeof(u));
512  flag = atah->a_flag;
513  u.opcode = 0x03;
514  u.len = 0x12;
515  u.lun = atapi->ap_packet.u_b[1];
516  *((volatile acUint16 *)0xB6160000) = (flag & 2) ^ 2;
517  *((volatile acUint16 *)0xB6010000) = 0;
518  v3 = atapi_packet_send((acAtaReg)0xB6000000, &u.pkt, flag);
519  if ( v3 < 0 )
520  {
521  ret = v3;
522  }
523  else
524  {
525  int v4;
526  int v5;
527 
528  v4 = atapi_pio_read((acAtaReg)0xB6000000, (acUint16 *)&sense, sizeof(sense), flag);
529  v5 = v4;
530  if ( v4 > 0 )
531  {
532  int v6;
533 
534  v6 = 0;
535  if ( (flag & 2) != 0 )
536  {
537  while ( (*((volatile acUint16 *)0xB6160000) & 0x81) == ATA_STAT_BUSY )
538  {
539  if ( SleepThread() )
540  {
541  v6 = -116;
542  break;
543  }
544  }
545  }
546  else
547  {
548  int tmout;
549 
550  tmout = 99999;
551  while ( (*((volatile acUint16 *)0xB6070000) & 0x81) == ATA_STAT_BUSY )
552  {
553  if ( tmout < 0 )
554  {
555  v6 = -116;
556  break;
557  }
558  --tmout;
559  }
560  }
561  if ( v6 < 0 )
562  {
563  printf("acata:C:io_done: TIMEDOUT\n");
564  v6 = -116;
565  }
566  v3 = v5;
567  if ( v6 < 0 )
568  v3 = -116;
569  ret = v3;
570  }
571  else
572  {
573  ret = v4;
574  if ( !v4 )
575  {
576  v3 = -5;
577  ret = v3;
578  }
579  }
580  }
581  if ( ret > 0 )
582  return -((sense.s_key << 16) | (sense.s_asc << 8) | sense.s_ascq);
583  if ( !ret )
584  return -5;
585  return ret;
586 }
587 
588 acAtapiT acAtapiSetup(acAtapiData *atapi, acAtapiDone done, void *arg, unsigned int tmout)
589 {
590  if ( atapi )
591  {
592  atapi->ap_h.a_ops = &ops_48;
593  atapi->ap_h.a_arg = arg;
594  atapi->ap_h.a_tmout = tmout;
595  atapi->ap_h.a_state = 0;
596  atapi->ap_h.a_flag = 0;
597  atapi->ap_done = done;
598  }
599  return atapi;
600 }
601 
602 int acAtapiRequest(acAtapiT atapi, int flag, acAtapiPacketData *pkt, void *buf, int size)
603 {
604  flag = flag | 8;
605  if ( !atapi || !pkt )
606  {
607  return -22;
608  }
609  atapi->ap_h.a_flag = flag;
610  atapi->ap_packet.u_w[0] = pkt->u_w[0];
611  atapi->ap_packet.u_w[1] = pkt->u_w[1];
612  atapi->ap_packet.u_w[2] = pkt->u_w[2];
613  atapi->ap_h.a_buf = buf;
614  atapi->ap_h.a_size = size;
615  return ata_request(&atapi->ap_h, WakeupThread);
616 }
617 
618 int acAtapiRequestI(acAtapiT atapi, int flag, acAtapiPacketData *pkt, void *buf, int size)
619 {
620  flag = flag | 8;
621  if ( !atapi || !pkt )
622  {
623  return -22;
624  }
625  atapi->ap_h.a_flag = flag;
626  atapi->ap_packet.u_w[0] = pkt->u_w[0];
627  atapi->ap_packet.u_w[1] = pkt->u_w[1];
628  atapi->ap_packet.u_w[2] = pkt->u_w[2];
629  atapi->ap_h.a_buf = buf;
630  atapi->ap_h.a_size = size;
631  return ata_request(&atapi->ap_h, iWakeupThread);
632 }
633 
634 int acAtapiStatus(acAtapiT atapi)
635 {
636  int state;
637 
638  if ( atapi == 0 )
639  {
640  return -22;
641  }
642  state = atapi->ap_h.a_state;
643  if ( (unsigned int)(state - 1) >= 0x7E )
644  {
645  return 0;
646  }
647  if ( state != 1 )
648  return 2;
649  return 1;
650 }
ac_dma
Definition: accore.h:61
ac_atapi_pkt
Definition: acata.h:57
TH_SELF
#define TH_SELF
Definition: kernel.h:68
ac_ata_ops
Definition: acata.h:35
count
u32 count
start sector of fragmented bd/file
Definition: usbhdfsd-common.h:3
atapi_dma
Definition: acata_internal.h:37
ac_atapi
Definition: acata.h:67
ac_dma_ops
Definition: accore.h:41
atahw.h
ac_ata_h
Definition: acata.h:23
atapi_sense
Definition: acata_internal.h:46