92e4b7f2f87b1ee54b14861a87c7f2502297b136
[pcsx_rearmed.git] / libpcsxcore / cdrom.c
1 /***************************************************************************
2  *   Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team              *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
18  ***************************************************************************/
19
20 /* 
21 * Handles all CD-ROM registers and functions.
22 */
23
24 #include "cdrom.h"
25 #include "ppf.h"
26
27 cdrStruct cdr;
28
29 /* CD-ROM magic numbers */
30 #define CdlSync        0
31 #define CdlNop         1
32 #define CdlSetloc      2
33 #define CdlPlay        3
34 #define CdlForward     4
35 #define CdlBackward    5
36 #define CdlReadN       6
37 #define CdlStandby     7
38 #define CdlStop        8
39 #define CdlPause       9
40 #define CdlInit        10
41 #define CdlMute        11
42 #define CdlDemute      12
43 #define CdlSetfilter   13
44 #define CdlSetmode     14
45 #define CdlGetmode     15
46 #define CdlGetlocL     16
47 #define CdlGetlocP     17
48 #define CdlReadT       18
49 #define CdlGetTN       19
50 #define CdlGetTD       20
51 #define CdlSeekL       21
52 #define CdlSeekP       22
53 #define CdlSetclock    23
54 #define CdlGetclock    24
55 #define CdlTest        25
56 #define CdlID          26
57 #define CdlReadS       27
58 #define CdlReset       28
59 #define CdlReadToc     30
60
61 #define AUTOPAUSE      249
62 #define READ_ACK       250
63 #define READ           251
64 #define REPPLAY_ACK    252
65 #define REPPLAY        253
66 #define ASYNC          254
67 /* don't set 255, it's reserved */
68
69 char *CmdName[0x100]= {
70     "CdlSync",     "CdlNop",       "CdlSetloc",  "CdlPlay",
71     "CdlForward",  "CdlBackward",  "CdlReadN",   "CdlStandby",
72     "CdlStop",     "CdlPause",     "CdlInit",    "CdlMute",
73     "CdlDemute",   "CdlSetfilter", "CdlSetmode", "CdlGetmode",
74     "CdlGetlocL",  "CdlGetlocP",   "CdlReadT",   "CdlGetTN",
75     "CdlGetTD",    "CdlSeekL",     "CdlSeekP",   "CdlSetclock",
76     "CdlGetclock", "CdlTest",      "CdlID",      "CdlReadS",
77     "CdlReset",    NULL,           "CDlReadToc", NULL
78 };
79
80 unsigned char Test04[] = { 0 };
81 unsigned char Test05[] = { 0 };
82 unsigned char Test20[] = { 0x98, 0x06, 0x10, 0xC3 };
83 unsigned char Test22[] = { 0x66, 0x6F, 0x72, 0x20, 0x45, 0x75, 0x72, 0x6F };
84 unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 };
85
86 // 1x = 75 sectors per second
87 // PSXCLK = 1 sec in the ps
88 // so (PSXCLK / 75) = cdr read time (linuzappz)
89 #define cdReadTime (PSXCLK / 75)
90
91 static struct CdrStat stat;
92 static struct SubQ *subq;
93
94 #define CDR_INT(eCycle) { \
95         psxRegs.interrupt |= 0x4; \
96         psxRegs.intCycle[2 + 1] = eCycle; \
97         psxRegs.intCycle[2] = psxRegs.cycle; }
98
99 #define CDREAD_INT(eCycle) { \
100         psxRegs.interrupt |= 0x40000; \
101         psxRegs.intCycle[2 + 16 + 1] = eCycle; \
102         psxRegs.intCycle[2 + 16] = psxRegs.cycle; }
103
104 #define StartReading(type, eCycle) { \
105         cdr.Reading = type; \
106         cdr.FirstSector = 1; \
107         cdr.Readed = 0xff; \
108         AddIrqQueue(READ_ACK, eCycle); \
109 }
110
111 #define StopReading() { \
112         if (cdr.Reading) { \
113                 cdr.Reading = 0; \
114                 psxRegs.interrupt &= ~0x40000; \
115         } \
116         cdr.StatP &= ~0x20;\
117 }
118
119 #define StopCdda() { \
120         if (cdr.Play) { \
121                 if (!Config.Cdda) CDR_stop(); \
122                 cdr.StatP &= ~0x80; \
123                 cdr.Play = FALSE; \
124         } \
125 }
126
127 #define SetResultSize(size) { \
128     cdr.ResultP = 0; \
129         cdr.ResultC = size; \
130         cdr.ResultReady = 1; \
131 }
132
133 static void ReadTrack() {
134         cdr.Prev[0] = itob(cdr.SetSector[0]);
135         cdr.Prev[1] = itob(cdr.SetSector[1]);
136         cdr.Prev[2] = itob(cdr.SetSector[2]);
137
138 #ifdef CDR_LOG
139         CDR_LOG("ReadTrack() Log: KEY *** %x:%x:%x\n", cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]);
140 #endif
141         cdr.RErr = CDR_readTrack(cdr.Prev);
142 }
143
144 // cdr.Stat:
145 #define NoIntr          0
146 #define DataReady       1
147 #define Complete        2
148 #define Acknowledge     3
149 #define DataEnd         4
150 #define DiskError       5
151
152 void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
153         cdr.Irq = irq;
154         if (cdr.Stat) {
155                 cdr.eCycle = ecycle;
156         } else {
157                 CDR_INT(ecycle);
158         }
159 }
160
161 void cdrInterrupt() {
162         int i;
163         unsigned char Irq = cdr.Irq;
164
165         if (cdr.Stat) {
166                 CDR_INT(0x1000);
167                 return;
168         }
169
170         cdr.Irq = 0xff;
171         cdr.Ctrl &= ~0x80;
172
173         switch (Irq) {
174                 case CdlSync:
175                         SetResultSize(1);
176                         cdr.StatP |= 0x2;
177                         cdr.Result[0] = cdr.StatP;
178                         cdr.Stat = Acknowledge; 
179                         break;
180
181                 case CdlNop:
182                         SetResultSize(1);
183                         cdr.Result[0] = cdr.StatP;
184                         cdr.Stat = Acknowledge;
185                         i = stat.Status;
186                         if (CDR_getStatus(&stat) != -1) {
187                                 if (stat.Type == 0xff) cdr.Stat = DiskError;
188                                 if (stat.Status & 0x10) {
189                                         cdr.Stat = DiskError;
190                                         cdr.Result[0] |= 0x11;
191                                         cdr.Result[0] &= ~0x02;
192                                 }
193                                 else if (i & 0x10) {
194                                         cdr.StatP |= 0x2;
195                                         cdr.Result[0] |= 0x2;
196                                         CheckCdrom();
197                                 }
198                         }
199                         break;
200
201                 case CdlSetloc:
202                         cdr.CmdProcess = 0;
203                         SetResultSize(1);
204                         cdr.StatP |= 0x2;
205                         cdr.Result[0] = cdr.StatP;
206                         cdr.Stat = Acknowledge;
207                         break;
208
209                 case CdlPlay:
210                         cdr.CmdProcess = 0;
211                         SetResultSize(1);
212                         cdr.StatP |= 0x2;
213                         cdr.Result[0] = cdr.StatP;
214                         cdr.Stat = Acknowledge;
215                         cdr.StatP |= 0x80;
216 //                      if ((cdr.Mode & 0x5) == 0x5) AddIrqQueue(REPPLAY, cdReadTime);
217                         break;
218
219         case CdlForward:
220                         cdr.CmdProcess = 0;
221                         SetResultSize(1);
222                         cdr.StatP |= 0x2;
223                 cdr.Result[0] = cdr.StatP;
224                 cdr.Stat = Complete;
225                         break;
226
227         case CdlBackward:
228                         cdr.CmdProcess = 0;
229                         SetResultSize(1);
230                         cdr.StatP |= 0x2;
231                 cdr.Result[0] = cdr.StatP;
232                 cdr.Stat = Complete;
233                         break;
234
235         case CdlStandby:
236                         cdr.CmdProcess = 0;
237                         SetResultSize(1);
238                         cdr.StatP |= 0x2;
239                         cdr.Result[0] = cdr.StatP;
240                         cdr.Stat = Complete;
241                         break;
242
243                 case CdlStop:
244                         cdr.CmdProcess = 0;
245                         SetResultSize(1);
246                         cdr.StatP &= ~0x2;
247                         cdr.Result[0] = cdr.StatP;
248                         cdr.Stat = Complete;
249 //                      cdr.Stat = Acknowledge;
250
251                         // check case open/close -shalma
252                         i = stat.Status;
253                         if (CDR_getStatus(&stat) != -1) {
254                                 if (stat.Type == 0xff) cdr.Stat = DiskError;
255                                 if (stat.Status & 0x10) {
256                                         cdr.Stat = DiskError;
257                                         cdr.Result[0] |= 0x11;
258                                         cdr.Result[0] &= ~0x02;
259                                 }
260                                 else if (i & 0x10) {
261                                         cdr.StatP |= 0x2;
262                                         cdr.Result[0] |= 0x2;
263                                         CheckCdrom();
264                                 }
265                         }
266                         break;
267
268                 case CdlPause:
269                         SetResultSize(1);
270                         cdr.Result[0] = cdr.StatP;
271                 cdr.Stat = Acknowledge;
272                         AddIrqQueue(CdlPause + 0x20, 0x1000);
273                         cdr.Ctrl |= 0x80;
274                         break;
275
276                 case CdlPause + 0x20:
277                         SetResultSize(1);
278                 cdr.StatP &= ~0x20;
279                         cdr.StatP |= 0x2;
280                         cdr.Result[0] = cdr.StatP;
281                 cdr.Stat = Complete;
282                         break;
283
284         case CdlInit:
285                         SetResultSize(1);
286                 cdr.StatP = 0x2;
287                         cdr.Result[0] = cdr.StatP;
288                 cdr.Stat = Acknowledge;
289 //                      if (!cdr.Init) {
290                                 AddIrqQueue(CdlInit + 0x20, 0x1000);
291 //                      }
292                 break;
293
294                 case CdlInit + 0x20:
295                         SetResultSize(1);
296                         cdr.Result[0] = cdr.StatP;
297                 cdr.Stat = Complete;
298                         cdr.Init = 1;
299                         break;
300
301         case CdlMute:
302                         SetResultSize(1);
303                         cdr.StatP |= 0x2;
304                 cdr.Result[0] = cdr.StatP;
305                 cdr.Stat = Acknowledge;
306                         break;
307
308         case CdlDemute:
309                         SetResultSize(1);
310                         cdr.StatP |= 0x2;
311                 cdr.Result[0] = cdr.StatP;
312                 cdr.Stat = Acknowledge;
313                         break;
314
315         case CdlSetfilter:
316                         SetResultSize(1);
317                         cdr.StatP |= 0x2;
318                 cdr.Result[0] = cdr.StatP;
319                 cdr.Stat = Acknowledge; 
320                 break;
321
322                 case CdlSetmode:
323                         SetResultSize(1);
324                         cdr.StatP |= 0x2;
325                 cdr.Result[0] = cdr.StatP;
326                 cdr.Stat = Acknowledge;
327                 break;
328
329         case CdlGetmode:
330                         SetResultSize(6);
331                         cdr.StatP |= 0x2;
332                 cdr.Result[0] = cdr.StatP;
333                 cdr.Result[1] = cdr.Mode;
334                 cdr.Result[2] = cdr.File;
335                 cdr.Result[3] = cdr.Channel;
336                 cdr.Result[4] = 0;
337                 cdr.Result[5] = 0;
338                 cdr.Stat = Acknowledge;
339                 break;
340
341         case CdlGetlocL:
342                         SetResultSize(8);
343 //              for (i = 0; i < 8; i++)
344 //                              cdr.Result[i] = itob(cdr.Transfer[i]);
345                 for (i = 0; i < 8; i++)
346                                 cdr.Result[i] = cdr.Transfer[i];
347                 cdr.Stat = Acknowledge;
348                 break;
349
350                 case CdlGetlocP:
351                         SetResultSize(8);
352                         subq = (struct SubQ *)CDR_getBufferSub();
353
354                         if (subq != NULL) {
355                                 cdr.Result[0] = subq->TrackNumber;
356                                 cdr.Result[1] = subq->IndexNumber;
357                                 memcpy(cdr.Result + 2, subq->TrackRelativeAddress, 3);
358                                 memcpy(cdr.Result + 5, subq->AbsoluteAddress, 3);
359
360                                 // subQ integrity check
361                                 if (calcCrc((u8 *)subq + 12, 10) != (((u16)subq->CRC[0] << 8) | subq->CRC[1])) {
362                                         memset(cdr.Result + 2, 0, 3 + 3); // CRC wrong, wipe out time data
363                                 }
364                         } else {
365                                 cdr.Result[0] = 1;
366                                 cdr.Result[1] = 1;
367
368                                 cdr.Result[2] = btoi(cdr.Prev[0]);
369                                 cdr.Result[3] = btoi(cdr.Prev[1]) - 2;
370                                 cdr.Result[4] = cdr.Prev[2];
371
372                                 // m:s adjustment
373                                 if ((s8)cdr.Result[3] < 0) {
374                                         cdr.Result[3] += 60;
375                                         cdr.Result[2] -= 1;
376                                 }
377
378                                 cdr.Result[2] = itob(cdr.Result[2]);
379                                 cdr.Result[3] = itob(cdr.Result[3]);
380
381                                 memcpy(cdr.Result + 5, cdr.Prev, 3);
382                         }
383
384                         cdr.Stat = Acknowledge;
385                         break;
386
387         case CdlGetTN:
388                         cdr.CmdProcess = 0;
389                         SetResultSize(3);
390                         cdr.StatP |= 0x2;
391                 cdr.Result[0] = cdr.StatP;
392                 if (CDR_getTN(cdr.ResultTN) == -1) {
393                                 cdr.Stat = DiskError;
394                                 cdr.Result[0] |= 0x01;
395                 } else {
396                         cdr.Stat = Acknowledge;
397                     cdr.Result[1] = itob(cdr.ResultTN[0]);
398                     cdr.Result[2] = itob(cdr.ResultTN[1]);
399                 }
400                 break;
401
402         case CdlGetTD:
403                         cdr.CmdProcess = 0;
404                         cdr.Track = btoi(cdr.Param[0]);
405                         SetResultSize(4);
406                         cdr.StatP |= 0x2;
407                         if (CDR_getTD(cdr.Track, cdr.ResultTD) == -1) {
408                                 cdr.Stat = DiskError;
409                                 cdr.Result[0] |= 0x01;
410                         } else {
411                                 cdr.Stat = Acknowledge;
412                                 cdr.Result[0] = cdr.StatP;
413                                 cdr.Result[1] = itob(cdr.ResultTD[2]);
414                                 cdr.Result[2] = itob(cdr.ResultTD[1]);
415                                 cdr.Result[3] = itob(cdr.ResultTD[0]);
416                         }
417                         break;
418
419         case CdlSeekL:
420                         SetResultSize(1);
421                         cdr.StatP |= 0x2;
422                 cdr.Result[0] = cdr.StatP;
423                         cdr.StatP |= 0x40;
424                 cdr.Stat = Acknowledge;
425                         cdr.Seeked = TRUE;
426                         AddIrqQueue(CdlSeekL + 0x20, 0x1000);
427                         break;
428
429         case CdlSeekL + 0x20:
430                         SetResultSize(1);
431                         cdr.StatP |= 0x2;
432                         cdr.StatP &= ~0x40;
433                 cdr.Result[0] = cdr.StatP;
434                 cdr.Stat = Complete;
435                         break;
436
437         case CdlSeekP:
438                         SetResultSize(1);
439                         cdr.StatP |= 0x2;
440                 cdr.Result[0] = cdr.StatP;
441                         cdr.StatP |= 0x40;
442                 cdr.Stat = Acknowledge;
443                         AddIrqQueue(CdlSeekP + 0x20, 0x1000);
444                         break;
445
446         case CdlSeekP + 0x20:
447                         SetResultSize(1);
448                         cdr.StatP |= 0x2;
449                         cdr.StatP &= ~0x40;
450                 cdr.Result[0] = cdr.StatP;
451                 cdr.Stat = Complete;
452                         break;
453
454                 case CdlTest:
455                 cdr.Stat = Acknowledge;
456                 switch (cdr.Param[0]) {
457                     case 0x20: // System Controller ROM Version
458                                         SetResultSize(4);
459                                         memcpy(cdr.Result, Test20, 4);
460                                         break;
461                                 case 0x22:
462                                         SetResultSize(8);
463                                         memcpy(cdr.Result, Test22, 4);
464                                         break;
465                                 case 0x23: case 0x24:
466                                         SetResultSize(8);
467                                         memcpy(cdr.Result, Test23, 4);
468                                         break;
469                 }
470                         break;
471
472         case CdlID:
473                         SetResultSize(1);
474                         cdr.StatP |= 0x2;
475                 cdr.Result[0] = cdr.StatP;
476                 cdr.Stat = Acknowledge;
477                         AddIrqQueue(CdlID + 0x20, 0x1000);
478                         break;
479
480                 case CdlID + 0x20:
481                         SetResultSize(8);
482                 if (CDR_getStatus(&stat) == -1) {
483                         cdr.Result[0] = 0x00; // 0x08 and cdr.Result[1]|0x10 : audio cd, enters cd player
484                 cdr.Result[1] = 0x00; // 0x80 leads to the menu in the bios, else loads CD
485                 }
486                 else {
487                 if (stat.Type == 2) {
488                         cdr.Result[0] = 0x08;
489                     cdr.Result[1] = 0x10;
490                         }
491                         else {
492                     cdr.Result[0] = 0x00;
493                     cdr.Result[1] = 0x00;
494                         }
495                 }
496                         cdr.Result[1] |= 0x80;
497                         cdr.Result[2] = 0x00;
498                         cdr.Result[3] = 0x00;
499                         strncpy((char *)&cdr.Result[4], "PCSX", 4);
500                         cdr.Stat = Complete;
501                         break;
502
503                 case CdlReset:
504                         SetResultSize(1);
505                 cdr.StatP = 0x2;
506                         cdr.Result[0] = cdr.StatP;
507                 cdr.Stat = Acknowledge;
508                         break;
509
510         case CdlReadToc:
511                         SetResultSize(1);
512                         cdr.StatP |= 0x2;
513                 cdr.Result[0] = cdr.StatP;
514                 cdr.Stat = Acknowledge;
515                         AddIrqQueue(CdlReadToc + 0x20, 0x1000);
516                         break;
517
518         case CdlReadToc + 0x20:
519                         SetResultSize(1);
520                         cdr.StatP |= 0x2;
521                 cdr.Result[0] = cdr.StatP;
522                 cdr.Stat = Complete;
523                         break;
524
525                 case AUTOPAUSE:
526                         cdr.OCUP = 0;
527 /*                      SetResultSize(1);
528                         StopCdda();
529                         StopReading();
530                         cdr.OCUP = 0;
531                 cdr.StatP&=~0x20;
532                         cdr.StatP|= 0x2;
533                 cdr.Result[0] = cdr.StatP;
534                 cdr.Stat = DataEnd;
535 */                      AddIrqQueue(CdlPause, 0x800);
536                         break;
537
538                 case READ_ACK:
539                         if (!cdr.Reading) return;
540
541                         SetResultSize(1);
542                         cdr.StatP |= 0x2;
543                 cdr.Result[0] = cdr.StatP;
544                         if (!cdr.Seeked) {
545                                 cdr.Seeked = TRUE;
546                                 cdr.StatP |= 0x40;
547                         }
548                         cdr.StatP |= 0x20;
549                 cdr.Stat = Acknowledge;
550
551 //                      CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
552                         CDREAD_INT(0x80000);
553                         break;
554
555                 case REPPLAY_ACK:
556                         cdr.Stat = Acknowledge;
557                         cdr.Result[0] = cdr.StatP;
558                         SetResultSize(1);
559                         AddIrqQueue(REPPLAY, cdReadTime);
560                         break;
561
562                 case REPPLAY: 
563                         if ((cdr.Mode & 5) != 5) break;
564 /*                      if (CDR_getStatus(&stat) == -1) {
565                                 cdr.Result[0] = 0;
566                                 cdr.Result[1] = 0;
567                                 cdr.Result[2] = 0;
568                                 cdr.Result[3] = 0;
569                                 cdr.Result[4] = 0;
570                                 cdr.Result[5] = 0;
571                                 cdr.Result[6] = 0;
572                                 cdr.Result[7] = 0;
573                         } else memcpy(cdr.Result, &stat.Track, 8);
574                         cdr.Stat = 1;
575                         SetResultSize(8);
576                         AddIrqQueue(REPPLAY_ACK, cdReadTime);
577 */                      break;
578
579                 case 0xff:
580                         return;
581
582                 default:
583                         cdr.Stat = Complete;
584                         break;
585         }
586
587         if (cdr.Stat != NoIntr && cdr.Reg2 != 0x18) {
588                 psxHu32ref(0x1070) |= SWAP32((u32)0x4);
589         }
590
591 #ifdef CDR_LOG
592         CDR_LOG("cdrInterrupt() Log: CDR Interrupt IRQ %x\n", Irq);
593 #endif
594 }
595
596 void cdrReadInterrupt() {
597         u8 *buf;
598
599         if (!cdr.Reading)
600                 return;
601
602         if (cdr.Stat) {
603                 CDREAD_INT(0x1000);
604                 return;
605         }
606
607 #ifdef CDR_LOG
608         CDR_LOG("cdrReadInterrupt() Log: KEY END");
609 #endif
610
611     cdr.OCUP = 1;
612         SetResultSize(1);
613         cdr.StatP |= 0x22;
614         cdr.StatP &= ~0x40;
615     cdr.Result[0] = cdr.StatP;
616
617         ReadTrack();
618
619         buf = CDR_getBuffer();
620         if (buf == NULL)
621                 cdr.RErr = -1;
622
623         if (cdr.RErr == -1) {
624 #ifdef CDR_LOG
625                 fprintf(emuLog, "cdrReadInterrupt() Log: err\n");
626 #endif
627                 memset(cdr.Transfer, 0, DATA_SIZE);
628                 cdr.Stat = DiskError;
629                 cdr.Result[0] |= 0x01;
630                 CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
631                 return;
632         }
633
634         memcpy(cdr.Transfer, buf, DATA_SIZE);
635         CheckPPFCache(cdr.Transfer, cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]);
636
637     cdr.Stat = DataReady;
638
639 #ifdef CDR_LOG
640         fprintf(emuLog, "cdrReadInterrupt() Log: cdr.Transfer %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]);
641 #endif
642
643         if ((!cdr.Muted) && (cdr.Mode & 0x40) && (!Config.Xa) && (cdr.FirstSector != -1)) { // CD-XA
644                 if ((cdr.Transfer[4 + 2] & 0x4) &&
645                         ((cdr.Mode & 0x8) ? (cdr.Transfer[4 + 1] == cdr.Channel) : 1) &&
646                         (cdr.Transfer[4 + 0] == cdr.File)) {
647                         int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector);
648
649                         if (!ret) {
650                                 SPU_playADPCMchannel(&cdr.Xa);
651                                 cdr.FirstSector = 0;
652                         }
653                         else cdr.FirstSector = -1;
654                 }
655         }
656
657         cdr.SetSector[2]++;
658     if (cdr.SetSector[2] == 75) {
659         cdr.SetSector[2] = 0;
660         cdr.SetSector[1]++;
661         if (cdr.SetSector[1] == 60) {
662             cdr.SetSector[1] = 0;
663             cdr.SetSector[0]++;
664         }
665     }
666
667     cdr.Readed = 0;
668
669         if ((cdr.Transfer[4 + 2] & 0x80) && (cdr.Mode & 0x2)) { // EOF
670 #ifdef CDR_LOG
671                 CDR_LOG("cdrReadInterrupt() Log: Autopausing read\n");
672 #endif
673 //              AddIrqQueue(AUTOPAUSE, 0x1000);
674                 AddIrqQueue(CdlPause, 0x1000);
675         }
676         else {
677                 CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
678         }
679         psxHu32ref(0x1070) |= SWAP32((u32)0x4);
680 }
681
682 /*
683 cdrRead0:
684         bit 0 - 0 REG1 command send / 1 REG1 data read
685         bit 1 - 0 data transfer finish / 1 data transfer ready/in progress
686         bit 2 - unknown
687         bit 3 - unknown
688         bit 4 - unknown
689         bit 5 - 1 result ready
690         bit 6 - 1 dma ready
691         bit 7 - 1 command being processed
692 */
693
694 unsigned char cdrRead0(void) {
695         if (cdr.ResultReady)
696                 cdr.Ctrl |= 0x20;
697         else
698                 cdr.Ctrl &= ~0x20;
699
700         if (cdr.OCUP)
701                 cdr.Ctrl |= 0x40;
702 //  else
703 //              cdr.Ctrl &= ~0x40;
704
705         // What means the 0x10 and the 0x08 bits? I only saw it used by the bios
706         cdr.Ctrl |= 0x18;
707
708 #ifdef CDR_LOG
709         CDR_LOG("cdrRead0() Log: CD0 Read: %x\n", cdr.Ctrl);
710 #endif
711
712         return psxHu8(0x1800) = cdr.Ctrl;
713 }
714
715 /*
716 cdrWrite0:
717         0 - to send a command / 1 - to get the result
718 */
719
720 void cdrWrite0(unsigned char rt) {
721 #ifdef CDR_LOG
722         CDR_LOG("cdrWrite0() Log: CD0 write: %x\n", rt);
723 #endif
724         cdr.Ctrl = rt | (cdr.Ctrl & ~0x3);
725
726     if (rt == 0) {
727                 cdr.ParamP = 0;
728                 cdr.ParamC = 0;
729                 cdr.ResultReady = 0;
730         }
731 }
732
733 unsigned char cdrRead1(void) {
734     if (cdr.ResultReady) { // && cdr.Ctrl & 0x1) {
735                 psxHu8(0x1801) = cdr.Result[cdr.ResultP++];
736                 if (cdr.ResultP == cdr.ResultC)
737                         cdr.ResultReady = 0;
738         } else {
739                 psxHu8(0x1801) = 0;
740         }
741 #ifdef CDR_LOG
742         CDR_LOG("cdrRead1() Log: CD1 Read: %x\n", psxHu8(0x1801));
743 #endif
744         return psxHu8(0x1801);
745 }
746
747 void cdrWrite1(unsigned char rt) {
748         int i;
749
750 #ifdef CDR_LOG
751         CDR_LOG("cdrWrite1() Log: CD1 write: %x (%s)\n", rt, CmdName[rt]);
752 #endif
753 //      psxHu8(0x1801) = rt;
754     cdr.Cmd = rt;
755         cdr.OCUP = 0;
756
757 #ifdef CDRCMD_DEBUG
758         SysPrintf("cdrWrite1() Log: CD1 write: %x (%s)", rt, CmdName[rt]);
759         if (cdr.ParamC) {
760                 SysPrintf(" Param[%d] = {", cdr.ParamC);
761                 for (i = 0; i < cdr.ParamC; i++)
762                         SysPrintf(" %x,", cdr.Param[i]);
763                 SysPrintf("}\n");
764         } else {
765                 SysPrintf("\n");
766         }
767 #endif
768
769         if (cdr.Ctrl & 0x1) return;
770
771     switch (cdr.Cmd) {
772         case CdlSync:
773                         cdr.Ctrl |= 0x80;
774                 cdr.Stat = NoIntr; 
775                 AddIrqQueue(cdr.Cmd, 0x1000);
776                 break;
777
778         case CdlNop:
779                         cdr.Ctrl |= 0x80;
780                 cdr.Stat = NoIntr; 
781                 AddIrqQueue(cdr.Cmd, 0x1000);
782                 break;
783
784         case CdlSetloc:
785                         StopReading();
786                         cdr.Seeked = FALSE;
787                 for (i = 0; i < 3; i++)
788                                 cdr.SetSector[i] = btoi(cdr.Param[i]);
789                 cdr.SetSector[3] = 0;
790 /*              if ((cdr.SetSector[0] | cdr.SetSector[1] | cdr.SetSector[2]) == 0) {
791                                 *(u32 *)cdr.SetSector = *(u32 *)cdr.SetSectorSeek;
792                         }*/
793                         cdr.Ctrl |= 0x80;
794                 cdr.Stat = NoIntr;
795                 AddIrqQueue(cdr.Cmd, 0x1000);
796                 break;
797
798         case CdlPlay:
799                 if (!cdr.SetSector[0] & !cdr.SetSector[1] & !cdr.SetSector[2]) {
800                 if (CDR_getTN(cdr.ResultTN) != -1) {
801                         if (cdr.CurTrack > cdr.ResultTN[1])
802                                                 cdr.CurTrack = cdr.ResultTN[1];
803                     if (CDR_getTD((unsigned char)(cdr.CurTrack), cdr.ResultTD) != -1) {
804                                 int tmp = cdr.ResultTD[2];
805                         cdr.ResultTD[2] = cdr.ResultTD[0];
806                                                 cdr.ResultTD[0] = tmp;
807                             if (!Config.Cdda) CDR_play(cdr.ResultTD);
808                                         }
809                 }
810                         } else if (!Config.Cdda) {
811                                 CDR_play(cdr.SetSector);
812                         }
813                 cdr.Play = TRUE;
814                         cdr.Ctrl |= 0x80;
815                 cdr.Stat = NoIntr; 
816                 AddIrqQueue(cdr.Cmd, 0x1000);
817                 break;
818
819         case CdlForward:
820                 if (cdr.CurTrack < 0xaa)
821                                 cdr.CurTrack++;
822                         cdr.Ctrl |= 0x80;
823                 cdr.Stat = NoIntr; 
824                 AddIrqQueue(cdr.Cmd, 0x1000);
825                 break;
826
827         case CdlBackward:
828                 if (cdr.CurTrack > 1)
829                                 cdr.CurTrack--;
830                         cdr.Ctrl |= 0x80;
831                 cdr.Stat = NoIntr; 
832                 AddIrqQueue(cdr.Cmd, 0x1000);
833                 break;
834
835         case CdlReadN:
836                         cdr.Irq = 0;
837                         StopReading();
838                         cdr.Ctrl|= 0x80;
839                 cdr.Stat = NoIntr; 
840                         StartReading(1, 0x1000);
841                 break;
842
843         case CdlStandby:
844                         StopCdda();
845                         StopReading();
846                         cdr.Ctrl |= 0x80;
847                 cdr.Stat = NoIntr;
848                 AddIrqQueue(cdr.Cmd, 0x1000);
849                 break;
850
851         case CdlStop:
852                         StopCdda();
853                         StopReading();
854                         cdr.Ctrl |= 0x80;
855                 cdr.Stat = NoIntr;
856                 AddIrqQueue(cdr.Cmd, 0x1000);
857                 break;
858
859         case CdlPause:
860                         StopCdda();
861                         StopReading();
862                         cdr.Ctrl |= 0x80;
863                 cdr.Stat = NoIntr;
864                 AddIrqQueue(cdr.Cmd, 0x80000);
865                 break;
866
867                 case CdlReset:
868         case CdlInit:
869                         StopCdda();
870                         StopReading();
871                         cdr.Ctrl |= 0x80;
872                 cdr.Stat = NoIntr; 
873                 AddIrqQueue(cdr.Cmd, 0x1000);
874                 break;
875
876         case CdlMute:
877                 cdr.Muted = TRUE;
878                         cdr.Ctrl |= 0x80;
879                 cdr.Stat = NoIntr; 
880                 AddIrqQueue(cdr.Cmd, 0x1000);
881                 break;
882
883         case CdlDemute:
884                 cdr.Muted = FALSE;
885                         cdr.Ctrl |= 0x80;
886                 cdr.Stat = NoIntr; 
887                 AddIrqQueue(cdr.Cmd, 0x1000);
888                 break;
889
890         case CdlSetfilter:
891                 cdr.File = cdr.Param[0];
892                 cdr.Channel = cdr.Param[1];
893                         cdr.Ctrl |= 0x80;
894                 cdr.Stat = NoIntr; 
895                 AddIrqQueue(cdr.Cmd, 0x1000);
896                 break;
897
898         case CdlSetmode:
899 #ifdef CDR_LOG
900                         CDR_LOG("cdrWrite1() Log: Setmode %x\n", cdr.Param[0]);
901 #endif 
902                 cdr.Mode = cdr.Param[0];
903                         cdr.Ctrl |= 0x80;
904                 cdr.Stat = NoIntr; 
905                 AddIrqQueue(cdr.Cmd, 0x1000);
906                 break;
907
908         case CdlGetmode:
909                         cdr.Ctrl |= 0x80;
910                 cdr.Stat = NoIntr; 
911                 AddIrqQueue(cdr.Cmd, 0x1000);
912                 break;
913
914         case CdlGetlocL:
915                         cdr.Ctrl |= 0x80;
916                 cdr.Stat = NoIntr; 
917                 AddIrqQueue(cdr.Cmd, 0x1000);
918                 break;
919
920         case CdlGetlocP:
921                         cdr.Ctrl |= 0x80;
922                 cdr.Stat = NoIntr; 
923                         AddIrqQueue(cdr.Cmd, 0x1000);
924                 break;
925
926         case CdlGetTN:
927                         cdr.Ctrl |= 0x80;
928                 cdr.Stat = NoIntr; 
929                 AddIrqQueue(cdr.Cmd, 0x1000);
930                 break;
931
932         case CdlGetTD:
933                         cdr.Ctrl |= 0x80;
934                 cdr.Stat = NoIntr; 
935                 AddIrqQueue(cdr.Cmd, 0x1000);
936                 break;
937
938         case CdlSeekL:
939 //                      ((u32 *)cdr.SetSectorSeek)[0] = ((u32 *)cdr.SetSector)[0];
940                         cdr.Ctrl |= 0x80;
941                 cdr.Stat = NoIntr; 
942                 AddIrqQueue(cdr.Cmd, 0x1000);
943                 break;
944
945         case CdlSeekP:
946 //              ((u32 *)cdr.SetSectorSeek)[0] = ((u32 *)cdr.SetSector)[0];
947                         cdr.Ctrl |= 0x80;
948                 cdr.Stat = NoIntr; 
949                 AddIrqQueue(cdr.Cmd, 0x1000);
950                 break;
951
952         case CdlTest:
953                         cdr.Ctrl |= 0x80;
954                 cdr.Stat = NoIntr; 
955                 AddIrqQueue(cdr.Cmd, 0x1000);
956                 break;
957
958         case CdlID:
959                         cdr.Ctrl |= 0x80;
960                 cdr.Stat = NoIntr; 
961                 AddIrqQueue(cdr.Cmd, 0x1000);
962                 break;
963
964         case CdlReadS:
965                         cdr.Irq = 0;
966                         StopReading();
967                         cdr.Ctrl |= 0x80;
968                 cdr.Stat = NoIntr; 
969                         StartReading(2, 0x1000);
970                 break;
971
972         case CdlReadToc:
973                         cdr.Ctrl |= 0x80;
974                 cdr.Stat = NoIntr; 
975                 AddIrqQueue(cdr.Cmd, 0x1000);
976                 break;
977
978         default:
979 #ifdef CDR_LOG
980                         CDR_LOG("cdrWrite1() Log: Unknown command: %x\n", cdr.Cmd);
981 #endif
982                         return;
983     }
984         if (cdr.Stat != NoIntr) {
985                 psxHu32ref(0x1070) |= SWAP32((u32)0x4);
986         }
987 }
988
989 unsigned char cdrRead2(void) {
990         unsigned char ret;
991
992         if (cdr.Readed == 0) {
993                 ret = 0;
994         } else {
995                 ret = *cdr.pTransfer++;
996         }
997
998 #ifdef CDR_LOG
999         CDR_LOG("cdrRead2() Log: CD2 Read: %x\n", ret);
1000 #endif
1001         return ret;
1002 }
1003
1004 void cdrWrite2(unsigned char rt) {
1005 #ifdef CDR_LOG
1006         CDR_LOG("cdrWrite2() Log: CD2 write: %x\n", rt);
1007 #endif
1008     if (cdr.Ctrl & 0x1) {
1009                 switch (rt) {
1010                         case 0x07:
1011                         cdr.ParamP = 0;
1012                                 cdr.ParamC = 0;
1013                                 cdr.ResultReady = 1; //0;
1014                                 cdr.Ctrl &= ~3; //cdr.Ctrl = 0;
1015                                 break;
1016
1017                         default:
1018                                 cdr.Reg2 = rt;
1019                                 break;
1020                 }
1021     } else if (!(cdr.Ctrl & 0x1) && cdr.ParamP < 8) {
1022                 cdr.Param[cdr.ParamP++] = rt;
1023                 cdr.ParamC++;
1024         }
1025 }
1026
1027 unsigned char cdrRead3(void) {
1028         if (cdr.Stat) {
1029                 if (cdr.Ctrl & 0x1)
1030                         psxHu8(0x1803) = cdr.Stat | 0xE0;
1031                 else
1032                         psxHu8(0x1803) = 0xff;
1033         } else {
1034                 psxHu8(0x1803) = 0;
1035         }
1036 #ifdef CDR_LOG
1037         CDR_LOG("cdrRead3() Log: CD3 Read: %x\n", psxHu8(0x1803));
1038 #endif
1039         return psxHu8(0x1803);
1040 }
1041
1042 void cdrWrite3(unsigned char rt) {
1043 #ifdef CDR_LOG
1044         CDR_LOG("cdrWrite3() Log: CD3 write: %x\n", rt);
1045 #endif
1046     if (rt == 0x07 && cdr.Ctrl & 0x1) {
1047                 cdr.Stat = 0;
1048
1049                 if (cdr.Irq == 0xff) {
1050                         cdr.Irq = 0;
1051                         return;
1052                 }
1053                 if (cdr.Irq)
1054                         CDR_INT(cdr.eCycle);
1055                 if (cdr.Reading && !cdr.ResultReady) 
1056             CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
1057
1058                 return;
1059         }
1060         if (rt == 0x80 && !(cdr.Ctrl & 0x1) && cdr.Readed == 0) {
1061                 cdr.Readed = 1;
1062                 cdr.pTransfer = cdr.Transfer;
1063
1064                 switch (cdr.Mode & 0x30) {
1065                         case 0x10:
1066                         case 0x00:
1067                                 cdr.pTransfer += 12;
1068                                 break;
1069                         default:
1070                                 break;
1071                 }
1072         }
1073 }
1074
1075 void psxDma3(u32 madr, u32 bcr, u32 chcr) {
1076         u32 cdsize;
1077         u8 *ptr;
1078
1079 #ifdef CDR_LOG
1080         CDR_LOG("psxDma3() Log: *** DMA 3 *** %x addr = %x size = %x\n", chcr, madr, bcr);
1081 #endif
1082
1083         switch (chcr) {
1084                 case 0x11000000:
1085                 case 0x11400100:
1086                         if (cdr.Readed == 0) {
1087 #ifdef CDR_LOG
1088                                 CDR_LOG("psxDma3() Log: *** DMA 3 *** NOT READY\n");
1089 #endif
1090                                 break;
1091                         }
1092
1093                         cdsize = (bcr & 0xffff) * 4;
1094
1095                         ptr = (u8 *)PSXM(madr);
1096                         if (ptr == NULL) {
1097 #ifdef CPU_LOG
1098                                 CDR_LOG("psxDma3() Log: *** DMA 3 *** NULL Pointer!\n");
1099 #endif
1100                                 break;
1101                         }
1102                         memcpy(ptr, cdr.pTransfer, cdsize);
1103                         psxCpu->Clear(madr, cdsize / 4);
1104                         cdr.pTransfer += cdsize;
1105                         break;
1106                 default:
1107 #ifdef CDR_LOG
1108                         CDR_LOG("psxDma3() Log: Unknown cddma %x\n", chcr);
1109 #endif
1110                         break;
1111         }
1112
1113         HW_DMA3_CHCR &= SWAP32(~0x01000000);
1114         DMA_INTERRUPT(3);
1115 }
1116
1117 void cdrReset() {
1118         memset(&cdr, 0, sizeof(cdr));
1119         cdr.CurTrack = 1;
1120         cdr.File = 1;
1121         cdr.Channel = 1;
1122 }
1123
1124 int cdrFreeze(gzFile f, int Mode) {
1125         uintptr_t tmp;
1126
1127         gzfreeze(&cdr, sizeof(cdr));
1128
1129         if (Mode == 1)
1130                 tmp = cdr.pTransfer - cdr.Transfer;
1131
1132         gzfreeze(&tmp, sizeof(tmp));
1133
1134         if (Mode == 0)
1135                 cdr.pTransfer = cdr.Transfer + tmp;
1136
1137         return 0;
1138 }