f7cd7b5e520cf628f980db8c0505a7a6c0f48867
[picodrive.git] / pico / cd / cd_sys.c
1 /***********************************************************\r
2  *                                                         *\r
3  * This source file was taken from the Gens project        *\r
4  * Written by Stéphane Dallongeville                       *\r
5  * Copyright (c) 2002 by Stéphane Dallongeville            *\r
6  * Modified/adapted for PicoDrive by notaz, 2007           *\r
7  *                                                         *\r
8  ***********************************************************/\r
9 \r
10 #include <stdio.h>\r
11 \r
12 #include "../pico_int.h"\r
13 #include "cd_sys.h"\r
14 #include "cd_file.h"\r
15 \r
16 #define DEBUG_CD\r
17 \r
18 #define TRAY_OPEN       0x0500          // TRAY OPEN CDD status\r
19 #define NOCD            0x0000          // CD removed CDD status\r
20 #define STOPPED         0x0900          // STOPPED CDD status (happen after stop or close tray command)\r
21 #define READY           0x0400          // READY CDD status (also used for seeking)\r
22 #define FAST_FOW        0x0300          // FAST FORWARD track CDD status\r
23 #define FAST_REV        0x10300         // FAST REVERSE track CDD status\r
24 #define PLAYING         0x0100          // PLAYING audio track CDD status\r
25 \r
26 //#undef cdprintf\r
27 //#define cdprintf(x, ...) elprintf(EL_STATUS, x, ##__VA_ARGS__)\r
28 \r
29 #define CDC_Update_Header()\r
30 \r
31 static int CD_Present = 0;\r
32 \r
33 \r
34 #define CHECK_TRAY_OPEN                         \\r
35 if (Pico_mcd->scd.Status_CDD == TRAY_OPEN)      \\r
36 {                                                                       \\r
37         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;        \\r
38                                                                         \\r
39         Pico_mcd->cdd.Minute = 0;                                       \\r
40         Pico_mcd->cdd.Seconde = 0;                              \\r
41         Pico_mcd->cdd.Frame = 0;                                        \\r
42         Pico_mcd->cdd.Ext = 0;                                  \\r
43                                                                         \\r
44         Pico_mcd->scd.CDD_Complete = 1;                         \\r
45                                                                         \\r
46         return 2;                                               \\r
47 }\r
48 \r
49 \r
50 #define CHECK_CD_PRESENT                        \\r
51 if (!CD_Present)                                        \\r
52 {                                                                       \\r
53         Pico_mcd->scd.Status_CDD = NOCD;                        \\r
54         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;        \\r
55                                                                         \\r
56         Pico_mcd->cdd.Minute = 0;                                       \\r
57         Pico_mcd->cdd.Seconde = 0;                              \\r
58         Pico_mcd->cdd.Frame = 0;                                        \\r
59         Pico_mcd->cdd.Ext = 0;                                  \\r
60                                                                         \\r
61         Pico_mcd->scd.CDD_Complete = 1;                         \\r
62                                                                         \\r
63         return 3;                                               \\r
64 }\r
65 \r
66 \r
67 static int MSF_to_LBA(_msf *MSF)\r
68 {\r
69         return (MSF->M * 60 * 75) + (MSF->S * 75) + MSF->F - 150;\r
70 }\r
71 \r
72 \r
73 PICO_INTERNAL void LBA_to_MSF(int lba, _msf *MSF)\r
74 {\r
75         if (lba < -150) lba = 0;\r
76         else lba += 150;\r
77         MSF->M = lba / (60 * 75);\r
78         MSF->S = (lba / 75) % 60;\r
79         MSF->F = lba % 75;\r
80 }\r
81 \r
82 \r
83 static unsigned int MSF_to_Track(_msf *MSF)\r
84 {\r
85         int i, Start, Cur;\r
86 \r
87         Start = (MSF->M << 16) + (MSF->S << 8) + MSF->F;\r
88 \r
89         for(i = 1; i <= (Pico_mcd->TOC.Last_Track + 1); i++)\r
90         {\r
91                 Cur = Pico_mcd->TOC.Tracks[i - 1].MSF.M << 16;\r
92                 Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.S << 8;\r
93                 Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.F;\r
94 \r
95                 if (Cur > Start) break;\r
96         }\r
97 \r
98         --i;\r
99 \r
100         if (i > Pico_mcd->TOC.Last_Track) return 100;\r
101         else if (i < 1) i = 1;\r
102 \r
103         return (unsigned) i;\r
104 }\r
105 \r
106 \r
107 static unsigned int LBA_to_Track(int lba)\r
108 {\r
109         _msf MSF;\r
110 \r
111         LBA_to_MSF(lba, &MSF);\r
112         return MSF_to_Track(&MSF);\r
113 }\r
114 \r
115 \r
116 static void Track_to_MSF(int track, _msf *MSF)\r
117 {\r
118         if (track < 1) track = 1;\r
119         else if (track > Pico_mcd->TOC.Last_Track) track = Pico_mcd->TOC.Last_Track;\r
120 \r
121         MSF->M = Pico_mcd->TOC.Tracks[track - 1].MSF.M;\r
122         MSF->S = Pico_mcd->TOC.Tracks[track - 1].MSF.S;\r
123         MSF->F = Pico_mcd->TOC.Tracks[track - 1].MSF.F;\r
124 }\r
125 \r
126 \r
127 PICO_INTERNAL int Track_to_LBA(int track)\r
128 {\r
129         _msf MSF;\r
130 \r
131         Track_to_MSF(track, &MSF);\r
132         return MSF_to_LBA(&MSF);\r
133 }\r
134 \r
135 \r
136 PICO_INTERNAL void Check_CD_Command(void)\r
137 {\r
138         cdprintf("CHECK CD COMMAND");\r
139 \r
140         // Check CDC\r
141         if (Pico_mcd->scd.Status_CDC & 1)                       // CDC is reading data ...\r
142         {\r
143                 cdprintf("Got a read command");\r
144 \r
145                 // DATA ?\r
146                 if (Pico_mcd->scd.Cur_Track == 1) {\r
147                      Pico_mcd->s68k_regs[0x36] |=  0x01;\r
148 \r
149                   if (Pico_mcd->scd.File_Add_Delay == 0)\r
150                   {\r
151                         unsigned char header[4];\r
152                         _msf MSF;\r
153 \r
154                         LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
155 \r
156                         header[0] = INT_TO_BCDB(MSF.M);\r
157                         header[1] = INT_TO_BCDB(MSF.S);\r
158                         header[2] = INT_TO_BCDB(MSF.F);\r
159                         header[3] = 0x01;\r
160 \r
161                         //FILE_Read_One_LBA_CDC();\r
162                         Pico_mcd->scd.Cur_LBA +=\r
163                           cdc_decoder_update(header);\r
164                   }\r
165                   else Pico_mcd->scd.File_Add_Delay--;\r
166                 }\r
167                 else {\r
168                         Pico_mcd->s68k_regs[0x36] &= ~0x01;                     // AUDIO\r
169                         unsigned char header[4] = { 0, };\r
170                         cdc_decoder_update(header);\r
171                 }\r
172         }\r
173 \r
174         // Check CDD\r
175         if (Pico_mcd->scd.CDD_Complete)\r
176         {\r
177                 Pico_mcd->scd.CDD_Complete = 0;\r
178 \r
179                 CDD_Export_Status();\r
180         }\r
181 \r
182         if (Pico_mcd->scd.Status_CDD == FAST_FOW)\r
183         {\r
184                 Pico_mcd->scd.Cur_LBA += 10;\r
185                 CDC_Update_Header();\r
186 \r
187         }\r
188         else if (Pico_mcd->scd.Status_CDD == FAST_REV)\r
189         {\r
190                 Pico_mcd->scd.Cur_LBA -= 10;\r
191                 if (Pico_mcd->scd.Cur_LBA < -150) Pico_mcd->scd.Cur_LBA = -150;\r
192                 CDC_Update_Header();\r
193         }\r
194 }\r
195 \r
196 \r
197 PICO_INTERNAL int Init_CD_Driver(void)\r
198 {\r
199         return 0;\r
200 }\r
201 \r
202 \r
203 PICO_INTERNAL void End_CD_Driver(void)\r
204 {\r
205         Unload_ISO();\r
206 }\r
207 \r
208 \r
209 PICO_INTERNAL void Reset_CD(void)\r
210 {\r
211         Pico_mcd->scd.Cur_Track = 0;\r
212         Pico_mcd->scd.Cur_LBA = -150;\r
213         Pico_mcd->scd.Status_CDC &= ~1;\r
214         if (Pico_mcd->scd.Status_CDD != TRAY_OPEN)\r
215                 Pico_mcd->scd.Status_CDD = CD_Present ? READY : NOCD;\r
216         Pico_mcd->scd.CDD_Complete = 0;\r
217         Pico_mcd->scd.File_Add_Delay = 0;\r
218 }\r
219 \r
220 \r
221 int Insert_CD(const char *cdimg_name, int type)\r
222 {\r
223         int ret = 1;\r
224 \r
225         CD_Present = 0;\r
226 \r
227         if (cdimg_name != NULL && type != CIT_NOT_CD)\r
228         {\r
229                 ret = Load_CD_Image(cdimg_name, type);\r
230                 if (ret == 0) {\r
231                         CD_Present = 1;\r
232 \r
233                         if (Pico_mcd->scd.Status_CDD == TRAY_OPEN)\r
234                         {\r
235                                 if (Pico_mcd->bios[0x122 ^ 1] == '2')\r
236                                         Close_Tray_CDD_cC();\r
237                                 // else bios will issue it\r
238                         }\r
239                         else\r
240                         {\r
241                                 Pico_mcd->scd.Status_CDD = READY;\r
242                         }\r
243                 }\r
244         }\r
245 \r
246         if (Pico_mcd->scd.Status_CDD != TRAY_OPEN && !CD_Present)\r
247                 Pico_mcd->scd.Status_CDD = NOCD;\r
248 \r
249         return ret;\r
250 }\r
251 \r
252 \r
253 int Stop_CD(void)\r
254 {\r
255         int ret = CD_Present;\r
256 \r
257         Unload_ISO();\r
258         CD_Present = 0;\r
259 \r
260         return ret;\r
261 }\r
262 \r
263 \r
264 /*\r
265 PICO_INTERNAL void Change_CD(void)\r
266 {\r
267         if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) Close_Tray_CDD_cC();\r
268         else Open_Tray_CDD_cD();\r
269 }\r
270 */\r
271 \r
272 PICO_INTERNAL int Get_Status_CDD_c0(void)\r
273 {\r
274         cdprintf("Status command : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
275 \r
276         // Clear immediat status\r
277         if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0200)\r
278                 Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
279         else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0700)\r
280                 Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
281         else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0E00)\r
282                 Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
283 \r
284         Pico_mcd->scd.CDD_Complete = 1;\r
285 \r
286         return 0;\r
287 }\r
288 \r
289 \r
290 PICO_INTERNAL int Stop_CDD_c1(void)\r
291 {\r
292         CHECK_TRAY_OPEN\r
293 \r
294         Pico_mcd->scd.Status_CDC &= ~1;                         // Stop CDC read\r
295 \r
296         if (CD_Present) Pico_mcd->scd.Status_CDD = STOPPED;\r
297         else Pico_mcd->scd.Status_CDD = NOCD;\r
298         Pico_mcd->cdd.Status = 0x0000;\r
299 \r
300         Pico_mcd->s68k_regs[0x36] |= 0x01;                      // Data bit set because stopped\r
301 \r
302         Pico_mcd->cdd.Minute = 0;\r
303         Pico_mcd->cdd.Seconde = 0;\r
304         Pico_mcd->cdd.Frame = 0;\r
305         Pico_mcd->cdd.Ext = 0;\r
306 \r
307         Pico_mcd->scd.CDD_Complete = 1;\r
308 \r
309         return 0;\r
310 }\r
311 \r
312 \r
313 PICO_INTERNAL int Get_Pos_CDD_c20(void)\r
314 {\r
315         _msf MSF;\r
316 \r
317         cdprintf("command 200 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
318 \r
319         CHECK_TRAY_OPEN\r
320 \r
321         Pico_mcd->cdd.Status &= 0xFF;\r
322         if (!CD_Present)\r
323         {\r
324                 Pico_mcd->scd.Status_CDD = NOCD;\r
325                 Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
326         }\r
327 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
328         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
329 \r
330         cdprintf("Status CDD = %.4X  Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);\r
331 \r
332         LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
333 \r
334         Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);\r
335         Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);\r
336         Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);\r
337         Pico_mcd->cdd.Ext = 0;\r
338 \r
339         Pico_mcd->scd.CDD_Complete = 1;\r
340 \r
341         return 0;\r
342 }\r
343 \r
344 \r
345 PICO_INTERNAL int Get_Track_Pos_CDD_c21(void)\r
346 {\r
347         int elapsed_time;\r
348         _msf MSF;\r
349 \r
350         cdprintf("command 201 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
351 \r
352         CHECK_TRAY_OPEN\r
353 \r
354         Pico_mcd->cdd.Status &= 0xFF;\r
355         if (!CD_Present)\r
356         {\r
357                 Pico_mcd->scd.Status_CDD = NOCD;\r
358                 Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
359         }\r
360 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
361         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
362 \r
363         elapsed_time = Pico_mcd->scd.Cur_LBA - Track_to_LBA(LBA_to_Track(Pico_mcd->scd.Cur_LBA));\r
364         LBA_to_MSF(elapsed_time - 150, &MSF);\r
365 \r
366         cdprintf("   elapsed = %d", elapsed_time);\r
367 \r
368         Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);\r
369         Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);\r
370         Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);\r
371         Pico_mcd->cdd.Ext = 0;\r
372 \r
373         Pico_mcd->scd.CDD_Complete = 1;\r
374 \r
375         return 0;\r
376 }\r
377 \r
378 \r
379 PICO_INTERNAL int Get_Current_Track_CDD_c22(void)\r
380 {\r
381         cdprintf("Status CDD = %.4X  Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);\r
382 \r
383         CHECK_TRAY_OPEN\r
384 \r
385         Pico_mcd->cdd.Status &= 0xFF;\r
386         if (!CD_Present)\r
387         {\r
388                 Pico_mcd->scd.Status_CDD = NOCD;\r
389                 Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
390         }\r
391 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
392         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
393 \r
394         Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);\r
395 \r
396         if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
397         else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
398         Pico_mcd->cdd.Seconde = 0;\r
399         Pico_mcd->cdd.Frame = 0;\r
400         Pico_mcd->cdd.Ext = 0;\r
401 \r
402         Pico_mcd->scd.CDD_Complete = 1;\r
403 \r
404         return 0;\r
405 }\r
406 \r
407 \r
408 PICO_INTERNAL int Get_Total_Lenght_CDD_c23(void)\r
409 {\r
410         CHECK_TRAY_OPEN\r
411 \r
412         Pico_mcd->cdd.Status &= 0xFF;\r
413         if (!CD_Present)\r
414         {\r
415                 Pico_mcd->scd.Status_CDD = NOCD;\r
416                 Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
417         }\r
418 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
419         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
420 \r
421         Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.M);\r
422         Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.S);\r
423         Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.F);\r
424         Pico_mcd->cdd.Ext = 0;\r
425 \r
426         Pico_mcd->scd.CDD_Complete = 1;\r
427 \r
428         return 0;\r
429 }\r
430 \r
431 \r
432 PICO_INTERNAL int Get_First_Last_Track_CDD_c24(void)\r
433 {\r
434         CHECK_TRAY_OPEN\r
435 \r
436         Pico_mcd->cdd.Status &= 0xFF;\r
437         if (!CD_Present)\r
438         {\r
439                 Pico_mcd->scd.Status_CDD = NOCD;\r
440         }\r
441 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
442         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
443 \r
444         Pico_mcd->cdd.Minute = INT_TO_BCDW(1);\r
445         Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Last_Track);\r
446         Pico_mcd->cdd.Frame = 0;\r
447         Pico_mcd->cdd.Ext = 0;\r
448 \r
449         Pico_mcd->scd.CDD_Complete = 1;\r
450 \r
451         return 0;\r
452 }\r
453 \r
454 \r
455 PICO_INTERNAL int Get_Track_Adr_CDD_c25(void)\r
456 {\r
457         int track_number;\r
458 \r
459         CHECK_TRAY_OPEN\r
460 \r
461         // track number in TC4 & TC5\r
462 \r
463         track_number = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
464 \r
465         Pico_mcd->cdd.Status &= 0xFF;\r
466         if (!CD_Present)\r
467         {\r
468                 Pico_mcd->scd.Status_CDD = NOCD;\r
469                 Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
470         }\r
471 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
472         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
473 \r
474         if (track_number > Pico_mcd->TOC.Last_Track) track_number = Pico_mcd->TOC.Last_Track;\r
475         else if (track_number < 1) track_number = 1;\r
476 \r
477         Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.M);\r
478         Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.S);\r
479         Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.F);\r
480         Pico_mcd->cdd.Ext = track_number % 10;\r
481 \r
482         if (track_number == 1) Pico_mcd->cdd.Frame |= 0x0800; // data track\r
483 \r
484         Pico_mcd->scd.CDD_Complete = 1;\r
485         return 0;\r
486 }\r
487 \r
488 \r
489 PICO_INTERNAL int Play_CDD_c3(void)\r
490 {\r
491         _msf MSF;\r
492         int delay, new_lba;\r
493 \r
494         CHECK_TRAY_OPEN\r
495         CHECK_CD_PRESENT\r
496 \r
497         // MSF of the track to play in TC buffer\r
498 \r
499         MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);\r
500         MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
501         MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);\r
502 \r
503         Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);\r
504 \r
505         new_lba = MSF_to_LBA(&MSF);\r
506         delay = new_lba - Pico_mcd->scd.Cur_LBA;\r
507         if (delay < 0) delay = -delay;\r
508         delay >>= 12;\r
509 \r
510         if (Pico_mcd->scd.Cur_LBA > 0 && delay < 13)\r
511                 // based on genplus GX\r
512                 delay = 13;\r
513 \r
514         Pico_mcd->scd.Cur_LBA = new_lba;\r
515         CDC_Update_Header();\r
516 \r
517         cdprintf("Read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);\r
518 \r
519         if (Pico_mcd->scd.Status_CDD != PLAYING) delay += 20;\r
520 \r
521         Pico_mcd->scd.Status_CDD = PLAYING;\r
522         Pico_mcd->cdd.Status = 0x0102;\r
523 //      Pico_mcd->cdd.Status = COMM_OK;\r
524 \r
525         if (Pico_mcd->scd.File_Add_Delay == 0) Pico_mcd->scd.File_Add_Delay = delay;\r
526 \r
527         if (Pico_mcd->scd.Cur_Track == 1)\r
528         {\r
529                 Pico_mcd->s68k_regs[0x36] |=  0x01;                             // DATA\r
530         }\r
531         else\r
532         {\r
533                 Pico_mcd->s68k_regs[0x36] &= ~0x01;                             // AUDIO\r
534                 cdda_start_play();\r
535         }\r
536 \r
537         if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
538         else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
539         Pico_mcd->cdd.Seconde = 0;\r
540         Pico_mcd->cdd.Frame = 0;\r
541         Pico_mcd->cdd.Ext = 0;\r
542 \r
543         Pico_mcd->scd.Status_CDC |= 1;                  // Read data with CDC\r
544 \r
545         Pico_mcd->scd.CDD_Complete = 1;\r
546         return 0;\r
547 }\r
548 \r
549 \r
550 PICO_INTERNAL int Seek_CDD_c4(void)\r
551 {\r
552         _msf MSF;\r
553 \r
554         CHECK_TRAY_OPEN\r
555         CHECK_CD_PRESENT\r
556 \r
557         // MSF to seek in TC buffer\r
558 \r
559         MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);\r
560         MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
561         MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);\r
562 \r
563         Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);\r
564         Pico_mcd->scd.Cur_LBA = MSF_to_LBA(&MSF);\r
565         CDC_Update_Header();\r
566 \r
567         Pico_mcd->scd.Status_CDC &= ~1;                         // Stop CDC read\r
568 \r
569         Pico_mcd->scd.Status_CDD = READY;\r
570         Pico_mcd->cdd.Status = 0x0200;\r
571 \r
572         // DATA ?\r
573         if (Pico_mcd->scd.Cur_Track == 1)\r
574              Pico_mcd->s68k_regs[0x36] |=  0x01;\r
575         else Pico_mcd->s68k_regs[0x36] &= ~0x01;                // AUDIO\r
576 \r
577         Pico_mcd->cdd.Minute = 0;\r
578         Pico_mcd->cdd.Seconde = 0;\r
579         Pico_mcd->cdd.Frame = 0;\r
580         Pico_mcd->cdd.Ext = 0;\r
581 \r
582         Pico_mcd->scd.CDD_Complete = 1;\r
583 \r
584         return 0;\r
585 }\r
586 \r
587 \r
588 PICO_INTERNAL int Pause_CDD_c6(void)\r
589 {\r
590         CHECK_TRAY_OPEN\r
591         CHECK_CD_PRESENT\r
592 \r
593         Pico_mcd->scd.Status_CDC &= ~1;                 // Stop CDC read to start a new one if raw data\r
594 \r
595         Pico_mcd->scd.Status_CDD = READY;\r
596         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
597 \r
598         Pico_mcd->s68k_regs[0x36] |= 0x01;              // Data bit set because stopped\r
599 \r
600         Pico_mcd->cdd.Minute = 0;\r
601         Pico_mcd->cdd.Seconde = 0;\r
602         Pico_mcd->cdd.Frame = 0;\r
603         Pico_mcd->cdd.Ext = 0;\r
604 \r
605         Pico_mcd->scd.CDD_Complete = 1;\r
606 \r
607         return 0;\r
608 }\r
609 \r
610 \r
611 PICO_INTERNAL int Resume_CDD_c7(void)\r
612 {\r
613         CHECK_TRAY_OPEN\r
614         CHECK_CD_PRESENT\r
615 \r
616         Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);\r
617 \r
618 #ifdef DEBUG_CD\r
619         {\r
620                 _msf MSF;\r
621                 LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
622                 cdprintf("Resume read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);\r
623         }\r
624 #endif\r
625 \r
626         Pico_mcd->scd.Status_CDD = PLAYING;\r
627         Pico_mcd->cdd.Status = 0x0102;\r
628 \r
629         if (Pico_mcd->scd.Cur_Track == 1)\r
630         {\r
631                 Pico_mcd->s68k_regs[0x36] |=  0x01;                             // DATA\r
632         }\r
633         else\r
634         {\r
635                 Pico_mcd->s68k_regs[0x36] &= ~0x01;                             // AUDIO\r
636                 cdda_start_play();\r
637         }\r
638 \r
639         if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
640         else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
641         Pico_mcd->cdd.Seconde = 0;\r
642         Pico_mcd->cdd.Frame = 0;\r
643         Pico_mcd->cdd.Ext = 0;\r
644 \r
645         Pico_mcd->scd.Status_CDC |= 1;                  // Read data with CDC\r
646 \r
647         Pico_mcd->scd.CDD_Complete = 1;\r
648         return 0;\r
649 }\r
650 \r
651 \r
652 PICO_INTERNAL int Fast_Foward_CDD_c8(void)\r
653 {\r
654         CHECK_TRAY_OPEN\r
655         CHECK_CD_PRESENT\r
656 \r
657         Pico_mcd->scd.Status_CDC &= ~1;                         // Stop CDC read\r
658 \r
659         Pico_mcd->scd.Status_CDD = FAST_FOW;\r
660         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;\r
661 \r
662         Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
663         Pico_mcd->cdd.Seconde = 0;\r
664         Pico_mcd->cdd.Frame = 0;\r
665         Pico_mcd->cdd.Ext = 0;\r
666 \r
667         Pico_mcd->scd.CDD_Complete = 1;\r
668 \r
669         return 0;\r
670 }\r
671 \r
672 \r
673 PICO_INTERNAL int Fast_Rewind_CDD_c9(void)\r
674 {\r
675         CHECK_TRAY_OPEN\r
676         CHECK_CD_PRESENT\r
677 \r
678         Pico_mcd->scd.Status_CDC &= ~1;                         // Stop CDC read\r
679 \r
680         Pico_mcd->scd.Status_CDD = FAST_REV;\r
681         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;\r
682 \r
683         Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
684         Pico_mcd->cdd.Seconde = 0;\r
685         Pico_mcd->cdd.Frame = 0;\r
686         Pico_mcd->cdd.Ext = 0;\r
687 \r
688         Pico_mcd->scd.CDD_Complete = 1;\r
689 \r
690         return 0;\r
691 }\r
692 \r
693 \r
694 PICO_INTERNAL int Close_Tray_CDD_cC(void)\r
695 {\r
696         Pico_mcd->scd.Status_CDC &= ~1;                 // Stop CDC read\r
697 \r
698         elprintf(EL_STATUS, "tray close\n");\r
699 \r
700         if (PicoMCDcloseTray != NULL)\r
701                 PicoMCDcloseTray();\r
702 \r
703         Pico_mcd->scd.Status_CDD = CD_Present ? STOPPED : NOCD;\r
704         Pico_mcd->cdd.Status = 0x0000;\r
705 \r
706         Pico_mcd->cdd.Minute = 0;\r
707         Pico_mcd->cdd.Seconde = 0;\r
708         Pico_mcd->cdd.Frame = 0;\r
709         Pico_mcd->cdd.Ext = 0;\r
710 \r
711         Pico_mcd->scd.CDD_Complete = 1;\r
712 \r
713         return 0;\r
714 }\r
715 \r
716 \r
717 PICO_INTERNAL int Open_Tray_CDD_cD(void)\r
718 {\r
719         CHECK_TRAY_OPEN\r
720 \r
721         Pico_mcd->scd.Status_CDC &= ~1;                 // Stop CDC read\r
722 \r
723         elprintf(EL_STATUS, "tray open\n");\r
724 \r
725         Unload_ISO();\r
726         CD_Present = 0;\r
727 \r
728         if (PicoMCDopenTray != NULL)\r
729                 PicoMCDopenTray();\r
730 \r
731         Pico_mcd->scd.Status_CDD = TRAY_OPEN;\r
732         Pico_mcd->cdd.Status = 0x0E00;\r
733 \r
734         Pico_mcd->cdd.Minute = 0;\r
735         Pico_mcd->cdd.Seconde = 0;\r
736         Pico_mcd->cdd.Frame = 0;\r
737         Pico_mcd->cdd.Ext = 0;\r
738 \r
739         Pico_mcd->scd.CDD_Complete = 1;\r
740 \r
741         return 0;\r
742 }\r
743 \r
744 \r
745 PICO_INTERNAL int CDD_cA(void)\r
746 {\r
747         CHECK_TRAY_OPEN\r
748         CHECK_CD_PRESENT\r
749 \r
750         Pico_mcd->scd.Status_CDC &= ~1;\r
751 \r
752         Pico_mcd->scd.Status_CDD = READY;\r
753         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
754 \r
755         Pico_mcd->cdd.Minute = 0;\r
756         Pico_mcd->cdd.Seconde = INT_TO_BCDW(1);\r
757         Pico_mcd->cdd.Frame = INT_TO_BCDW(1);\r
758         Pico_mcd->cdd.Ext = 0;\r
759 \r
760         Pico_mcd->scd.CDD_Complete = 1;\r
761 \r
762         return 0;\r
763 }\r
764 \r
765 \r
766 PICO_INTERNAL int CDD_Def(void)\r
767 {\r
768         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
769 \r
770         Pico_mcd->cdd.Minute = 0;\r
771         Pico_mcd->cdd.Seconde = 0;\r
772         Pico_mcd->cdd.Frame = 0;\r
773         Pico_mcd->cdd.Ext = 0;\r
774 \r
775         return 0;\r
776 }\r
777 \r
778 \r
779 static int bswapwrite(int a, unsigned short d)\r
780 {\r
781         *(unsigned short *)(Pico_mcd->s68k_regs + a) = (d>>8)|(d<<8);\r
782         return d + (d >> 8);\r
783 }\r
784 \r
785 PICO_INTERNAL void CDD_Export_Status(void)\r
786 {\r
787         unsigned int csum;\r
788 \r
789         csum  = bswapwrite( 0x38+0, Pico_mcd->cdd.Status);\r
790         csum += bswapwrite( 0x38+2, Pico_mcd->cdd.Minute);\r
791         csum += bswapwrite( 0x38+4, Pico_mcd->cdd.Seconde);\r
792         csum += bswapwrite( 0x38+6, Pico_mcd->cdd.Frame);\r
793         Pico_mcd->s68k_regs[0x38+8] = Pico_mcd->cdd.Ext;\r
794         csum += Pico_mcd->cdd.Ext;\r
795         Pico_mcd->s68k_regs[0x38+9] = ~csum & 0xf;\r
796 \r
797         Pico_mcd->s68k_regs[0x37] &= 3; // CDD.Control\r
798 \r
799         if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4)\r
800         {\r
801                 elprintf(EL_INTS, "cdd export irq 4");\r
802                 SekInterruptS68k(4);\r
803         }\r
804 \r
805 //      cdprintf("CDD exported status\n");\r
806         cdprintf("out:  Status=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X  Checksum=%.4X",\r
807                 (Pico_mcd->s68k_regs[0x38+0] << 8) | Pico_mcd->s68k_regs[0x38+1],\r
808                 (Pico_mcd->s68k_regs[0x38+2] << 8) | Pico_mcd->s68k_regs[0x38+3],\r
809                 (Pico_mcd->s68k_regs[0x38+4] << 8) | Pico_mcd->s68k_regs[0x38+5],\r
810                 (Pico_mcd->s68k_regs[0x38+6] << 8) | Pico_mcd->s68k_regs[0x38+7],\r
811                 (Pico_mcd->s68k_regs[0x38+8] << 8) | Pico_mcd->s68k_regs[0x38+9]);\r
812 }\r
813 \r
814 \r
815 PICO_INTERNAL void CDD_Import_Command(void)\r
816 {\r
817 //      cdprintf("CDD importing command\n");\r
818         cdprintf("in:  Command=%.4X, Minute=%.4X, Second=%.4X, Frame=%.4X  Checksum=%.4X",\r
819                 (Pico_mcd->s68k_regs[0x38+10+0] << 8) | Pico_mcd->s68k_regs[0x38+10+1],\r
820                 (Pico_mcd->s68k_regs[0x38+10+2] << 8) | Pico_mcd->s68k_regs[0x38+10+3],\r
821                 (Pico_mcd->s68k_regs[0x38+10+4] << 8) | Pico_mcd->s68k_regs[0x38+10+5],\r
822                 (Pico_mcd->s68k_regs[0x38+10+6] << 8) | Pico_mcd->s68k_regs[0x38+10+7],\r
823                 (Pico_mcd->s68k_regs[0x38+10+8] << 8) | Pico_mcd->s68k_regs[0x38+10+9]);\r
824 \r
825         switch (Pico_mcd->s68k_regs[0x38+10+0])\r
826         {\r
827                 case 0x0:       // STATUS (?)\r
828                         Get_Status_CDD_c0();\r
829                         break;\r
830 \r
831                 case 0x1:       // STOP ALL (?)\r
832                         Stop_CDD_c1();\r
833                         break;\r
834 \r
835                 case 0x2:       // GET TOC INFORMATIONS\r
836                         switch(Pico_mcd->s68k_regs[0x38+10+3])\r
837                         {\r
838                                 case 0x0:       // get current position (MSF format)\r
839                                         Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00);\r
840                                         Get_Pos_CDD_c20();\r
841                                         break;\r
842 \r
843                                 case 0x1:       // get elapsed time of current track played/scanned (relative MSF format)\r
844                                         Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 1;\r
845                                         Get_Track_Pos_CDD_c21();\r
846                                         break;\r
847 \r
848                                 case 0x2:       // get current track in RS2-RS3\r
849                                         Pico_mcd->cdd.Status =  (Pico_mcd->cdd.Status & 0xFF00) | 2;\r
850                                         Get_Current_Track_CDD_c22();\r
851                                         break;\r
852 \r
853                                 case 0x3:       // get total length (MSF format)\r
854                                         Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 3;\r
855                                         Get_Total_Lenght_CDD_c23();\r
856                                         break;\r
857 \r
858                                 case 0x4:       // first & last track number\r
859                                         Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 4;\r
860                                         Get_First_Last_Track_CDD_c24();\r
861                                         break;\r
862 \r
863                                 case 0x5:       // get track addresse (MSF format)\r
864                                         Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 5;\r
865                                         Get_Track_Adr_CDD_c25();\r
866                                         break;\r
867 \r
868                                 default :       // invalid, then we return status\r
869                                         Pico_mcd->cdd.Status = (Pico_mcd->cdd.Status & 0xFF00) | 0xF;\r
870                                         Get_Status_CDD_c0();\r
871                                         break;\r
872                         }\r
873                         break;\r
874 \r
875                 case 0x3:       // READ\r
876                         Play_CDD_c3();\r
877                         break;\r
878 \r
879                 case 0x4:       // SEEK\r
880                         Seek_CDD_c4();\r
881                         break;\r
882 \r
883                 case 0x6:       // PAUSE/STOP\r
884                         Pause_CDD_c6();\r
885                         break;\r
886 \r
887                 case 0x7:       // RESUME\r
888                         Resume_CDD_c7();\r
889                         break;\r
890 \r
891                 case 0x8:       // FAST FOWARD\r
892                         Fast_Foward_CDD_c8();\r
893                         break;\r
894 \r
895                 case 0x9:       // FAST REWIND\r
896                         Fast_Rewind_CDD_c9();\r
897                         break;\r
898 \r
899                 case 0xA:       // RECOVER INITIAL STATE (?)\r
900                         CDD_cA();\r
901                         break;\r
902 \r
903                 case 0xC:       // CLOSE TRAY\r
904                         Close_Tray_CDD_cC();\r
905                         break;\r
906 \r
907                 case 0xD:       // OPEN TRAY\r
908                         Open_Tray_CDD_cD();\r
909                         break;\r
910 \r
911                 default:        // UNKNOWN\r
912                         CDD_Def();\r
913                         break;\r
914         }\r
915 }\r
916 \r
917 void CDD_Reset(void)\r
918 {\r
919         // Reseting CDD\r
920 \r
921         memset(Pico_mcd->s68k_regs+0x34, 0, 2*2); // CDD.Fader, CDD.Control\r
922         Pico_mcd->cdd.Status = 0;\r
923         Pico_mcd->cdd.Minute = 0;\r
924         Pico_mcd->cdd.Seconde = 0;\r
925         Pico_mcd->cdd.Frame = 0;\r
926         Pico_mcd->cdd.Ext = 0;\r
927 \r
928         // clear receive status and transfer command\r
929         memset(Pico_mcd->s68k_regs+0x38, 0, 20);\r
930         Pico_mcd->s68k_regs[0x38+9] = 0xF;              // Default checksum\r
931 }\r
932 \r
933 \r