cd: better cd change handling, perhaps?
[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 \r
27 static int CD_Present = 0;\r
28 \r
29 \r
30 #define CHECK_TRAY_OPEN                         \\r
31 if (Pico_mcd->scd.Status_CDD == TRAY_OPEN)      \\r
32 {                                                                       \\r
33         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;        \\r
34                                                                         \\r
35         Pico_mcd->cdd.Minute = 0;                                       \\r
36         Pico_mcd->cdd.Seconde = 0;                              \\r
37         Pico_mcd->cdd.Frame = 0;                                        \\r
38         Pico_mcd->cdd.Ext = 0;                                  \\r
39                                                                         \\r
40         Pico_mcd->scd.CDD_Complete = 1;                         \\r
41                                                                         \\r
42         return 2;                                               \\r
43 }\r
44 \r
45 \r
46 #define CHECK_CD_PRESENT                        \\r
47 if (!CD_Present)                                        \\r
48 {                                                                       \\r
49         Pico_mcd->scd.Status_CDD = NOCD;                        \\r
50         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;        \\r
51                                                                         \\r
52         Pico_mcd->cdd.Minute = 0;                                       \\r
53         Pico_mcd->cdd.Seconde = 0;                              \\r
54         Pico_mcd->cdd.Frame = 0;                                        \\r
55         Pico_mcd->cdd.Ext = 0;                                  \\r
56                                                                         \\r
57         Pico_mcd->scd.CDD_Complete = 1;                         \\r
58                                                                         \\r
59         return 3;                                               \\r
60 }\r
61 \r
62 \r
63 static int MSF_to_LBA(_msf *MSF)\r
64 {\r
65         return (MSF->M * 60 * 75) + (MSF->S * 75) + MSF->F - 150;\r
66 }\r
67 \r
68 \r
69 PICO_INTERNAL void LBA_to_MSF(int lba, _msf *MSF)\r
70 {\r
71         if (lba < -150) lba = 0;\r
72         else lba += 150;\r
73         MSF->M = lba / (60 * 75);\r
74         MSF->S = (lba / 75) % 60;\r
75         MSF->F = lba % 75;\r
76 }\r
77 \r
78 \r
79 static unsigned int MSF_to_Track(_msf *MSF)\r
80 {\r
81         int i, Start, Cur;\r
82 \r
83         Start = (MSF->M << 16) + (MSF->S << 8) + MSF->F;\r
84 \r
85         for(i = 1; i <= (Pico_mcd->TOC.Last_Track + 1); i++)\r
86         {\r
87                 Cur = Pico_mcd->TOC.Tracks[i - 1].MSF.M << 16;\r
88                 Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.S << 8;\r
89                 Cur += Pico_mcd->TOC.Tracks[i - 1].MSF.F;\r
90 \r
91                 if (Cur > Start) break;\r
92         }\r
93 \r
94         --i;\r
95 \r
96         if (i > Pico_mcd->TOC.Last_Track) return 100;\r
97         else if (i < 1) i = 1;\r
98 \r
99         return (unsigned) i;\r
100 }\r
101 \r
102 \r
103 static unsigned int LBA_to_Track(int lba)\r
104 {\r
105         _msf MSF;\r
106 \r
107         LBA_to_MSF(lba, &MSF);\r
108         return MSF_to_Track(&MSF);\r
109 }\r
110 \r
111 \r
112 static void Track_to_MSF(int track, _msf *MSF)\r
113 {\r
114         if (track < 1) track = 1;\r
115         else if (track > Pico_mcd->TOC.Last_Track) track = Pico_mcd->TOC.Last_Track;\r
116 \r
117         MSF->M = Pico_mcd->TOC.Tracks[track - 1].MSF.M;\r
118         MSF->S = Pico_mcd->TOC.Tracks[track - 1].MSF.S;\r
119         MSF->F = Pico_mcd->TOC.Tracks[track - 1].MSF.F;\r
120 }\r
121 \r
122 \r
123 PICO_INTERNAL int Track_to_LBA(int track)\r
124 {\r
125         _msf MSF;\r
126 \r
127         Track_to_MSF(track, &MSF);\r
128         return MSF_to_LBA(&MSF);\r
129 }\r
130 \r
131 \r
132 PICO_INTERNAL void Check_CD_Command(void)\r
133 {\r
134         cdprintf("CHECK CD COMMAND");\r
135 \r
136         // Check CDC\r
137         if (Pico_mcd->scd.Status_CDC & 1)                       // CDC is reading data ...\r
138         {\r
139                 cdprintf("Got a read command");\r
140 \r
141                 // DATA ?\r
142                 if (Pico_mcd->scd.Cur_Track == 1)\r
143                      Pico_mcd->s68k_regs[0x36] |=  0x01;\r
144                 else Pico_mcd->s68k_regs[0x36] &= ~0x01;                        // AUDIO\r
145 \r
146                 if (Pico_mcd->scd.File_Add_Delay == 0)\r
147                 {\r
148                         FILE_Read_One_LBA_CDC();\r
149                 }\r
150                 else Pico_mcd->scd.File_Add_Delay--;\r
151         }\r
152 \r
153         // Check CDD\r
154         if (Pico_mcd->scd.CDD_Complete)\r
155         {\r
156                 Pico_mcd->scd.CDD_Complete = 0;\r
157 \r
158                 CDD_Export_Status();\r
159         }\r
160 \r
161         if (Pico_mcd->scd.Status_CDD == FAST_FOW)\r
162         {\r
163                 Pico_mcd->scd.Cur_LBA += 10;\r
164                 CDC_Update_Header();\r
165 \r
166         }\r
167         else if (Pico_mcd->scd.Status_CDD == FAST_REV)\r
168         {\r
169                 Pico_mcd->scd.Cur_LBA -= 10;\r
170                 if (Pico_mcd->scd.Cur_LBA < -150) Pico_mcd->scd.Cur_LBA = -150;\r
171                 CDC_Update_Header();\r
172         }\r
173 }\r
174 \r
175 \r
176 PICO_INTERNAL int Init_CD_Driver(void)\r
177 {\r
178         return 0;\r
179 }\r
180 \r
181 \r
182 PICO_INTERNAL void End_CD_Driver(void)\r
183 {\r
184         Unload_ISO();\r
185 }\r
186 \r
187 \r
188 PICO_INTERNAL void Reset_CD(void)\r
189 {\r
190         Pico_mcd->scd.Cur_Track = 0;\r
191         Pico_mcd->scd.Cur_LBA = -150;\r
192         Pico_mcd->scd.Status_CDC &= ~1;\r
193         if (Pico_mcd->scd.Status_CDD != TRAY_OPEN)\r
194                 Pico_mcd->scd.Status_CDD = CD_Present ? READY : NOCD;\r
195         Pico_mcd->scd.CDD_Complete = 0;\r
196         Pico_mcd->scd.File_Add_Delay = 0;\r
197 }\r
198 \r
199 \r
200 int Insert_CD(const char *cdimg_name, int type)\r
201 {\r
202         int ret = 1;\r
203 \r
204         CD_Present = 0;\r
205 \r
206         if (cdimg_name != NULL && type != CIT_NOT_CD)\r
207         {\r
208                 ret = Load_CD_Image(cdimg_name, type);\r
209                 if (ret == 0) {\r
210                         CD_Present = 1;\r
211 \r
212                         if (Pico_mcd->scd.Status_CDD == TRAY_OPEN)\r
213                         {\r
214                                 if (Pico_mcd->bios[0x122 ^ 1] == '2')\r
215                                         Close_Tray_CDD_cC();\r
216                                 // else bios will issue it\r
217                         }\r
218                         else\r
219                         {\r
220                                 Pico_mcd->scd.Status_CDD = READY;\r
221                         }\r
222                 }\r
223         }\r
224 \r
225         if (Pico_mcd->scd.Status_CDD != TRAY_OPEN && !CD_Present)\r
226                 Pico_mcd->scd.Status_CDD = NOCD;\r
227 \r
228         return ret;\r
229 }\r
230 \r
231 \r
232 int Stop_CD(void)\r
233 {\r
234         int ret = CD_Present;\r
235 \r
236         Unload_ISO();\r
237         CD_Present = 0;\r
238 \r
239         return ret;\r
240 }\r
241 \r
242 \r
243 /*\r
244 PICO_INTERNAL void Change_CD(void)\r
245 {\r
246         if (Pico_mcd->scd.Status_CDD == TRAY_OPEN) Close_Tray_CDD_cC();\r
247         else Open_Tray_CDD_cD();\r
248 }\r
249 */\r
250 \r
251 PICO_INTERNAL int Get_Status_CDD_c0(void)\r
252 {\r
253         cdprintf("Status command : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
254 \r
255         // Clear immediat status\r
256         if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0200)\r
257                 Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
258         else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0700)\r
259                 Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
260         else if ((Pico_mcd->cdd.Status & 0x0F00) == 0x0E00)\r
261                 Pico_mcd->cdd.Status = (Pico_mcd->scd.Status_CDD & 0xFF00) | (Pico_mcd->cdd.Status & 0x00FF);\r
262 \r
263         Pico_mcd->scd.CDD_Complete = 1;\r
264 \r
265         return 0;\r
266 }\r
267 \r
268 \r
269 PICO_INTERNAL int Stop_CDD_c1(void)\r
270 {\r
271         CHECK_TRAY_OPEN\r
272 \r
273         Pico_mcd->scd.Status_CDC &= ~1;                         // Stop CDC read\r
274 \r
275         if (CD_Present) Pico_mcd->scd.Status_CDD = STOPPED;\r
276         else Pico_mcd->scd.Status_CDD = NOCD;\r
277         Pico_mcd->cdd.Status = 0x0000;\r
278 \r
279         Pico_mcd->s68k_regs[0x36] |= 0x01;                      // Data bit set because stopped\r
280 \r
281         Pico_mcd->cdd.Minute = 0;\r
282         Pico_mcd->cdd.Seconde = 0;\r
283         Pico_mcd->cdd.Frame = 0;\r
284         Pico_mcd->cdd.Ext = 0;\r
285 \r
286         Pico_mcd->scd.CDD_Complete = 1;\r
287 \r
288         return 0;\r
289 }\r
290 \r
291 \r
292 PICO_INTERNAL int Get_Pos_CDD_c20(void)\r
293 {\r
294         _msf MSF;\r
295 \r
296         cdprintf("command 200 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
297 \r
298         CHECK_TRAY_OPEN\r
299 \r
300         Pico_mcd->cdd.Status &= 0xFF;\r
301         if (!CD_Present)\r
302         {\r
303                 Pico_mcd->scd.Status_CDD = NOCD;\r
304                 Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
305         }\r
306 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
307         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
308 \r
309         cdprintf("Status CDD = %.4X  Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);\r
310 \r
311         LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
312 \r
313         Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);\r
314         Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);\r
315         Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);\r
316         Pico_mcd->cdd.Ext = 0;\r
317 \r
318         Pico_mcd->scd.CDD_Complete = 1;\r
319 \r
320         return 0;\r
321 }\r
322 \r
323 \r
324 PICO_INTERNAL int Get_Track_Pos_CDD_c21(void)\r
325 {\r
326         int elapsed_time;\r
327         _msf MSF;\r
328 \r
329         cdprintf("command 201 : Cur LBA = %d", Pico_mcd->scd.Cur_LBA);\r
330 \r
331         CHECK_TRAY_OPEN\r
332 \r
333         Pico_mcd->cdd.Status &= 0xFF;\r
334         if (!CD_Present)\r
335         {\r
336                 Pico_mcd->scd.Status_CDD = NOCD;\r
337                 Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
338         }\r
339 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
340         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
341 \r
342         elapsed_time = Pico_mcd->scd.Cur_LBA - Track_to_LBA(LBA_to_Track(Pico_mcd->scd.Cur_LBA));\r
343         LBA_to_MSF(elapsed_time - 150, &MSF);\r
344 \r
345         cdprintf("   elapsed = %d", elapsed_time);\r
346 \r
347         Pico_mcd->cdd.Minute = INT_TO_BCDW(MSF.M);\r
348         Pico_mcd->cdd.Seconde = INT_TO_BCDW(MSF.S);\r
349         Pico_mcd->cdd.Frame = INT_TO_BCDW(MSF.F);\r
350         Pico_mcd->cdd.Ext = 0;\r
351 \r
352         Pico_mcd->scd.CDD_Complete = 1;\r
353 \r
354         return 0;\r
355 }\r
356 \r
357 \r
358 PICO_INTERNAL int Get_Current_Track_CDD_c22(void)\r
359 {\r
360         cdprintf("Status CDD = %.4X  Status = %.4X", Pico_mcd->scd.Status_CDD, Pico_mcd->cdd.Status);\r
361 \r
362         CHECK_TRAY_OPEN\r
363 \r
364         Pico_mcd->cdd.Status &= 0xFF;\r
365         if (!CD_Present)\r
366         {\r
367                 Pico_mcd->scd.Status_CDD = NOCD;\r
368                 Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
369         }\r
370 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
371         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
372 \r
373         Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);\r
374 \r
375         if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
376         else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
377         Pico_mcd->cdd.Seconde = 0;\r
378         Pico_mcd->cdd.Frame = 0;\r
379         Pico_mcd->cdd.Ext = 0;\r
380 \r
381         Pico_mcd->scd.CDD_Complete = 1;\r
382 \r
383         return 0;\r
384 }\r
385 \r
386 \r
387 PICO_INTERNAL int Get_Total_Lenght_CDD_c23(void)\r
388 {\r
389         CHECK_TRAY_OPEN\r
390 \r
391         Pico_mcd->cdd.Status &= 0xFF;\r
392         if (!CD_Present)\r
393         {\r
394                 Pico_mcd->scd.Status_CDD = NOCD;\r
395                 Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
396         }\r
397 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
398         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
399 \r
400         Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.M);\r
401         Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.S);\r
402         Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[Pico_mcd->TOC.Last_Track].MSF.F);\r
403         Pico_mcd->cdd.Ext = 0;\r
404 \r
405         Pico_mcd->scd.CDD_Complete = 1;\r
406 \r
407         return 0;\r
408 }\r
409 \r
410 \r
411 PICO_INTERNAL int Get_First_Last_Track_CDD_c24(void)\r
412 {\r
413         CHECK_TRAY_OPEN\r
414 \r
415         Pico_mcd->cdd.Status &= 0xFF;\r
416         if (!CD_Present)\r
417         {\r
418                 Pico_mcd->scd.Status_CDD = NOCD;\r
419         }\r
420 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
421         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
422 \r
423         Pico_mcd->cdd.Minute = INT_TO_BCDW(1);\r
424         Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Last_Track);\r
425         Pico_mcd->cdd.Frame = 0;\r
426         Pico_mcd->cdd.Ext = 0;\r
427 \r
428         Pico_mcd->scd.CDD_Complete = 1;\r
429 \r
430         return 0;\r
431 }\r
432 \r
433 \r
434 PICO_INTERNAL int Get_Track_Adr_CDD_c25(void)\r
435 {\r
436         int track_number;\r
437 \r
438         CHECK_TRAY_OPEN\r
439 \r
440         // track number in TC4 & TC5\r
441 \r
442         track_number = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
443 \r
444         Pico_mcd->cdd.Status &= 0xFF;\r
445         if (!CD_Present)\r
446         {\r
447                 Pico_mcd->scd.Status_CDD = NOCD;\r
448                 Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
449         }\r
450 //      else if (!(CDC.CTRL.B.B0 & 0x80)) Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
451         Pico_mcd->cdd.Status |= Pico_mcd->scd.Status_CDD;\r
452 \r
453         if (track_number > Pico_mcd->TOC.Last_Track) track_number = Pico_mcd->TOC.Last_Track;\r
454         else if (track_number < 1) track_number = 1;\r
455 \r
456         Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.M);\r
457         Pico_mcd->cdd.Seconde = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.S);\r
458         Pico_mcd->cdd.Frame = INT_TO_BCDW(Pico_mcd->TOC.Tracks[track_number - 1].MSF.F);\r
459         Pico_mcd->cdd.Ext = track_number % 10;\r
460 \r
461         if (track_number == 1) Pico_mcd->cdd.Frame |= 0x0800; // data track\r
462 \r
463         Pico_mcd->scd.CDD_Complete = 1;\r
464         return 0;\r
465 }\r
466 \r
467 \r
468 PICO_INTERNAL int Play_CDD_c3(void)\r
469 {\r
470         _msf MSF;\r
471         int delay, new_lba;\r
472 \r
473         CHECK_TRAY_OPEN\r
474         CHECK_CD_PRESENT\r
475 \r
476         // MSF of the track to play in TC buffer\r
477 \r
478         MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);\r
479         MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
480         MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);\r
481 \r
482         Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);\r
483 \r
484         new_lba = MSF_to_LBA(&MSF);\r
485         delay = new_lba - Pico_mcd->scd.Cur_LBA;\r
486         if (delay < 0) delay = -delay;\r
487         delay >>= 12;\r
488 \r
489         if (Pico_mcd->scd.Cur_LBA > 0 && delay < 13)\r
490                 // based on genplus GX\r
491                 delay = 13;\r
492 \r
493         Pico_mcd->scd.Cur_LBA = new_lba;\r
494         CDC_Update_Header();\r
495 \r
496         cdprintf("Read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);\r
497 \r
498         if (Pico_mcd->scd.Status_CDD != PLAYING) delay += 20;\r
499 \r
500         Pico_mcd->scd.Status_CDD = PLAYING;\r
501         Pico_mcd->cdd.Status = 0x0102;\r
502 //      Pico_mcd->cdd.Status = COMM_OK;\r
503 \r
504         if (Pico_mcd->scd.File_Add_Delay == 0) Pico_mcd->scd.File_Add_Delay = delay;\r
505 \r
506         if (Pico_mcd->scd.Cur_Track == 1)\r
507         {\r
508                 Pico_mcd->s68k_regs[0x36] |=  0x01;                             // DATA\r
509         }\r
510         else\r
511         {\r
512                 Pico_mcd->s68k_regs[0x36] &= ~0x01;                             // AUDIO\r
513                 cdda_start_play();\r
514         }\r
515 \r
516         if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
517         else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
518         Pico_mcd->cdd.Seconde = 0;\r
519         Pico_mcd->cdd.Frame = 0;\r
520         Pico_mcd->cdd.Ext = 0;\r
521 \r
522         Pico_mcd->scd.Status_CDC |= 1;                  // Read data with CDC\r
523 \r
524         Pico_mcd->scd.CDD_Complete = 1;\r
525         return 0;\r
526 }\r
527 \r
528 \r
529 PICO_INTERNAL int Seek_CDD_c4(void)\r
530 {\r
531         _msf MSF;\r
532 \r
533         CHECK_TRAY_OPEN\r
534         CHECK_CD_PRESENT\r
535 \r
536         // MSF to seek in TC buffer\r
537 \r
538         MSF.M = (Pico_mcd->s68k_regs[0x38+10+2] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+3] & 0xF);\r
539         MSF.S = (Pico_mcd->s68k_regs[0x38+10+4] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+5] & 0xF);\r
540         MSF.F = (Pico_mcd->s68k_regs[0x38+10+6] & 0xF) * 10 + (Pico_mcd->s68k_regs[0x38+10+7] & 0xF);\r
541 \r
542         Pico_mcd->scd.Cur_Track = MSF_to_Track(&MSF);\r
543         Pico_mcd->scd.Cur_LBA = MSF_to_LBA(&MSF);\r
544         CDC_Update_Header();\r
545 \r
546         Pico_mcd->scd.Status_CDC &= ~1;                         // Stop CDC read\r
547 \r
548         Pico_mcd->scd.Status_CDD = READY;\r
549         Pico_mcd->cdd.Status = 0x0200;\r
550 \r
551         // DATA ?\r
552         if (Pico_mcd->scd.Cur_Track == 1)\r
553              Pico_mcd->s68k_regs[0x36] |=  0x01;\r
554         else Pico_mcd->s68k_regs[0x36] &= ~0x01;                // AUDIO\r
555 \r
556         Pico_mcd->cdd.Minute = 0;\r
557         Pico_mcd->cdd.Seconde = 0;\r
558         Pico_mcd->cdd.Frame = 0;\r
559         Pico_mcd->cdd.Ext = 0;\r
560 \r
561         Pico_mcd->scd.CDD_Complete = 1;\r
562 \r
563         return 0;\r
564 }\r
565 \r
566 \r
567 PICO_INTERNAL int Pause_CDD_c6(void)\r
568 {\r
569         CHECK_TRAY_OPEN\r
570         CHECK_CD_PRESENT\r
571 \r
572         Pico_mcd->scd.Status_CDC &= ~1;                 // Stop CDC read to start a new one if raw data\r
573 \r
574         Pico_mcd->scd.Status_CDD = READY;\r
575         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
576 \r
577         Pico_mcd->s68k_regs[0x36] |= 0x01;              // Data bit set because stopped\r
578 \r
579         Pico_mcd->cdd.Minute = 0;\r
580         Pico_mcd->cdd.Seconde = 0;\r
581         Pico_mcd->cdd.Frame = 0;\r
582         Pico_mcd->cdd.Ext = 0;\r
583 \r
584         Pico_mcd->scd.CDD_Complete = 1;\r
585 \r
586         return 0;\r
587 }\r
588 \r
589 \r
590 PICO_INTERNAL int Resume_CDD_c7(void)\r
591 {\r
592         CHECK_TRAY_OPEN\r
593         CHECK_CD_PRESENT\r
594 \r
595         Pico_mcd->scd.Cur_Track = LBA_to_Track(Pico_mcd->scd.Cur_LBA);\r
596 \r
597 #ifdef DEBUG_CD\r
598         {\r
599                 _msf MSF;\r
600                 LBA_to_MSF(Pico_mcd->scd.Cur_LBA, &MSF);\r
601                 cdprintf("Resume read : Cur LBA = %d, M=%d, S=%d, F=%d", Pico_mcd->scd.Cur_LBA, MSF.M, MSF.S, MSF.F);\r
602         }\r
603 #endif\r
604 \r
605         Pico_mcd->scd.Status_CDD = PLAYING;\r
606         Pico_mcd->cdd.Status = 0x0102;\r
607 \r
608         if (Pico_mcd->scd.Cur_Track == 1)\r
609         {\r
610                 Pico_mcd->s68k_regs[0x36] |=  0x01;                             // DATA\r
611         }\r
612         else\r
613         {\r
614                 Pico_mcd->s68k_regs[0x36] &= ~0x01;                             // AUDIO\r
615                 cdda_start_play();\r
616         }\r
617 \r
618         if (Pico_mcd->scd.Cur_Track == 100) Pico_mcd->cdd.Minute = 0x0A02;\r
619         else Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
620         Pico_mcd->cdd.Seconde = 0;\r
621         Pico_mcd->cdd.Frame = 0;\r
622         Pico_mcd->cdd.Ext = 0;\r
623 \r
624         Pico_mcd->scd.Status_CDC |= 1;                  // Read data with CDC\r
625 \r
626         Pico_mcd->scd.CDD_Complete = 1;\r
627         return 0;\r
628 }\r
629 \r
630 \r
631 PICO_INTERNAL int Fast_Foward_CDD_c8(void)\r
632 {\r
633         CHECK_TRAY_OPEN\r
634         CHECK_CD_PRESENT\r
635 \r
636         Pico_mcd->scd.Status_CDC &= ~1;                         // Stop CDC read\r
637 \r
638         Pico_mcd->scd.Status_CDD = FAST_FOW;\r
639         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD | 2;\r
640 \r
641         Pico_mcd->cdd.Minute = INT_TO_BCDW(Pico_mcd->scd.Cur_Track);\r
642         Pico_mcd->cdd.Seconde = 0;\r
643         Pico_mcd->cdd.Frame = 0;\r
644         Pico_mcd->cdd.Ext = 0;\r
645 \r
646         Pico_mcd->scd.CDD_Complete = 1;\r
647 \r
648         return 0;\r
649 }\r
650 \r
651 \r
652 PICO_INTERNAL int Fast_Rewind_CDD_c9(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_REV;\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 Close_Tray_CDD_cC(void)\r
674 {\r
675         Pico_mcd->scd.Status_CDC &= ~1;                 // Stop CDC read\r
676 \r
677         elprintf(EL_STATUS, "tray close\n");\r
678 \r
679         if (PicoMCDcloseTray != NULL)\r
680                 PicoMCDcloseTray();\r
681 \r
682         Pico_mcd->scd.Status_CDD = CD_Present ? STOPPED : NOCD;\r
683         Pico_mcd->cdd.Status = 0x0000;\r
684 \r
685         Pico_mcd->cdd.Minute = 0;\r
686         Pico_mcd->cdd.Seconde = 0;\r
687         Pico_mcd->cdd.Frame = 0;\r
688         Pico_mcd->cdd.Ext = 0;\r
689 \r
690         Pico_mcd->scd.CDD_Complete = 1;\r
691 \r
692         return 0;\r
693 }\r
694 \r
695 \r
696 PICO_INTERNAL int Open_Tray_CDD_cD(void)\r
697 {\r
698         CHECK_TRAY_OPEN\r
699 \r
700         Pico_mcd->scd.Status_CDC &= ~1;                 // Stop CDC read\r
701 \r
702         elprintf(EL_STATUS, "tray open\n");\r
703 \r
704         Unload_ISO();\r
705         CD_Present = 0;\r
706 \r
707         if (PicoMCDopenTray != NULL)\r
708                 PicoMCDopenTray();\r
709 \r
710         Pico_mcd->scd.Status_CDD = TRAY_OPEN;\r
711         Pico_mcd->cdd.Status = 0x0E00;\r
712 \r
713         Pico_mcd->cdd.Minute = 0;\r
714         Pico_mcd->cdd.Seconde = 0;\r
715         Pico_mcd->cdd.Frame = 0;\r
716         Pico_mcd->cdd.Ext = 0;\r
717 \r
718         Pico_mcd->scd.CDD_Complete = 1;\r
719 \r
720         return 0;\r
721 }\r
722 \r
723 \r
724 PICO_INTERNAL int CDD_cA(void)\r
725 {\r
726         CHECK_TRAY_OPEN\r
727         CHECK_CD_PRESENT\r
728 \r
729         Pico_mcd->scd.Status_CDC &= ~1;\r
730 \r
731         Pico_mcd->scd.Status_CDD = READY;\r
732         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
733 \r
734         Pico_mcd->cdd.Minute = 0;\r
735         Pico_mcd->cdd.Seconde = INT_TO_BCDW(1);\r
736         Pico_mcd->cdd.Frame = INT_TO_BCDW(1);\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_Def(void)\r
746 {\r
747         Pico_mcd->cdd.Status = Pico_mcd->scd.Status_CDD;\r
748 \r
749         Pico_mcd->cdd.Minute = 0;\r
750         Pico_mcd->cdd.Seconde = 0;\r
751         Pico_mcd->cdd.Frame = 0;\r
752         Pico_mcd->cdd.Ext = 0;\r
753 \r
754         return 0;\r
755 }\r
756 \r
757 \r