minimal working gtk-less build
[pcsx_rearmed.git] / plugins / dfcdrom / cdr.c
1 /*
2  * Copyright (c) 2010, Wei Mingzhi <whistler@openoffice.org>.
3  * All Rights Reserved.
4  *
5  * Based on: Cdrom for Psemu Pro like Emulators
6  * By: linuzappz <linuzappz@hotmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, see <http://www.gnu.org/licenses>.
20  */
21
22 #include "cdr.h"
23
24 #ifndef USE_NULL
25 static char *LibName = N_("CD-ROM Drive Reader");
26 #else
27 static char *LibName = N_("CDR NULL Plugin");
28 #endif
29
30 int initial_time = 0;
31
32 pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
33 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
34
35 CacheData *cdcache;
36 unsigned char *cdbuffer;
37 int cacheaddr;
38
39 crdata cr;
40
41 unsigned char lastTime[3];
42 pthread_t thread;
43 int subqread;
44 volatile int stopth, found, locked, playing;
45
46 long (*ReadTrackT[])() = {
47         ReadNormal,
48         ReadThreaded,
49 };
50
51 unsigned char* (*GetBufferT[])() = {
52         GetBNormal,
53         GetBThreaded,
54 };
55
56 long (*fReadTrack)();
57 unsigned char* (*fGetBuffer)();
58
59 void *CdrThread(void *arg);
60
61 long CDRinit(void) {
62         thread = (pthread_t)-1;
63         return 0;
64 }
65
66 long CDRshutdown(void) {
67         return 0;
68 }
69
70 long CDRopen(void) {
71         LoadConf();
72
73 #ifndef _MACOSX
74         if (IsCdHandleOpen())
75                 return 0; // it's already open
76 #endif
77
78         if (OpenCdHandle(CdromDev) == -1) { // if we can't open the cdrom we'll works as a null plugin
79                 fprintf(stderr, "CDR: Could not open %s\n", CdromDev);
80         }
81
82         fReadTrack = ReadTrackT[ReadMode];
83         fGetBuffer = GetBufferT[ReadMode];
84
85         if (ReadMode == THREADED) {
86                 cdcache = (CacheData *)malloc(CacheSize * sizeof(CacheData));
87                 if (cdcache == NULL) return -1;
88                 memset(cdcache, 0, CacheSize * sizeof(CacheData));
89
90                 found = 0;
91         } else {
92                 cdbuffer = cr.buf + 12; /* skip sync data */
93         }
94
95         if (ReadMode == THREADED) {
96                 pthread_attr_t attr;
97
98                 pthread_mutex_init(&mut, NULL);
99                 pthread_cond_init(&cond, NULL);
100                 locked = 0;
101
102                 pthread_attr_init(&attr);
103                 pthread_create(&thread, &attr, CdrThread, NULL);
104
105                 cacheaddr = -1;
106         } else thread = (pthread_t)-1;
107
108         playing = 0;
109         stopth = 0;
110         initial_time = 0;
111
112         return 0;
113 }
114
115 long CDRclose(void) {
116         if (!IsCdHandleOpen()) return 0;
117
118         if (playing) CDRstop();
119
120         CloseCdHandle();
121
122         if (thread != (pthread_t)-1) {
123                 if (locked == 0) {
124                         stopth = 1;
125                         while (locked == 0) usleep(5000);
126                 }
127
128                 stopth = 2;
129                 pthread_mutex_lock(&mut);
130                 pthread_cond_signal(&cond);
131                 pthread_mutex_unlock(&mut);
132
133                 pthread_join(thread, NULL);
134                 pthread_mutex_destroy(&mut);
135                 pthread_cond_destroy(&cond);
136         }
137
138         if (ReadMode == THREADED) {
139                 free(cdcache);
140         }
141
142         return 0;
143 }
144
145 // return Starting and Ending Track
146 // buffer:
147 //  byte 0 - start track
148 //  byte 1 - end track
149 long CDRgetTN(unsigned char *buffer) {
150         long ret;
151
152         if (!IsCdHandleOpen()) {
153                 buffer[0] = 1;
154                 buffer[1] = 1;
155                 return 0;
156         }
157
158         if (ReadMode == THREADED) pthread_mutex_lock(&mut);
159         ret = GetTN(buffer);
160         if (ReadMode == THREADED) pthread_mutex_unlock(&mut);
161
162         return ret;
163 }
164
165 // return Track Time
166 // buffer:
167 //  byte 0 - frame
168 //  byte 1 - second
169 //  byte 2 - minute
170 long CDRgetTD(unsigned char track, unsigned char *buffer) {
171         long ret;
172
173         if (!IsCdHandleOpen()) {
174                 memset(buffer + 1, 0, 3);
175                 return 0;
176         }
177
178         if (ReadMode == THREADED) pthread_mutex_lock(&mut);
179         ret = GetTD(track, buffer);
180         if (ReadMode == THREADED) pthread_mutex_unlock(&mut);
181
182         return ret;
183 }
184
185 // normal reading
186 long ReadNormal() {
187         if (ReadSector(&cr) == -1)
188                 return -1;
189
190         return 0;
191 }
192
193 unsigned char* GetBNormal() {
194         return cdbuffer;
195 }
196
197 // threaded reading (with cache)
198 long ReadThreaded() {
199         int addr = msf_to_lba(cr.msf.cdmsf_min0, cr.msf.cdmsf_sec0, cr.msf.cdmsf_frame0);
200         int i;
201
202         if (addr >= cacheaddr && addr < (cacheaddr + CacheSize) && cacheaddr != -1) {
203                 i = addr - cacheaddr;
204                 PRINTF("found %d\n", (addr - cacheaddr));
205                 cdbuffer = cdcache[i].cr.buf + 12;
206                 while (btoi(cdbuffer[0]) != cr.msf.cdmsf_min0 ||
207                            btoi(cdbuffer[1]) != cr.msf.cdmsf_sec0 ||
208                            btoi(cdbuffer[2]) != cr.msf.cdmsf_frame0) {
209                         if (locked == 1) {
210                                 if (cdcache[i].ret == 0) break;
211                                 return -1;
212                         }
213                         usleep(5000);
214                 }
215                 PRINTF("%x:%x:%x, %p, %p\n", cdbuffer[0], cdbuffer[1], cdbuffer[2], cdbuffer, cdcache);
216                 found = 1;
217
218                 return 0;
219         } else found = 0;
220
221         if (locked == 0) {
222                 stopth = 1;
223                 while (locked == 0) { usleep(5000); }
224                 stopth = 0;
225         }
226
227         // not found in cache
228         locked = 0;
229         pthread_mutex_lock(&mut);
230         pthread_cond_signal(&cond);
231         pthread_mutex_unlock(&mut);
232
233         return 0;
234 }
235
236 unsigned char* GetBThreaded() {
237         PRINTF("threadc %d\n", found);
238
239         if (found == 1) return cdbuffer;
240         cdbuffer = cdcache[0].cr.buf + 12;
241         while (btoi(cdbuffer[0]) != cr.msf.cdmsf_min0 ||
242                    btoi(cdbuffer[1]) != cr.msf.cdmsf_sec0 ||
243                    btoi(cdbuffer[2]) != cr.msf.cdmsf_frame0) {
244                 if (locked == 1) return NULL;
245                 usleep(5000);
246         }
247         if (cdcache[0].ret == -1) return NULL;
248
249         return cdbuffer;
250 }
251
252 void *CdrThread(void *arg) {
253         unsigned char curTime[3];
254         int i;
255
256         for (;;) {
257                 locked = 1;
258                 pthread_mutex_lock(&mut);
259                 pthread_cond_wait(&cond, &mut);
260
261                 if (stopth == 2) pthread_exit(NULL);
262                 // refill the buffer
263                 cacheaddr = msf_to_lba(cr.msf.cdmsf_min0, cr.msf.cdmsf_sec0, cr.msf.cdmsf_frame0);
264
265                 memcpy(curTime, &cr.msf, 3);
266
267                 PRINTF("start thc %d:%d:%d\n", curTime[0], curTime[1], curTime[2]);
268
269                 for (i = 0; i < CacheSize; i++) {
270                         memcpy(&cdcache[i].cr.msf, curTime, 3);
271                         PRINTF("reading %d:%d:%d\n", curTime[0], curTime[1], curTime[2]);
272                         cdcache[i].ret = ReadSector(&cdcache[i].cr);
273
274                         PRINTF("readed %x:%x:%x\n", cdcache[i].cr.buf[12], cdcache[i].cr.buf[13], cdcache[i].cr.buf[14]);
275                         if (cdcache[i].ret == -1) break;
276
277                         curTime[2]++;
278                         if (curTime[2] == 75) {
279                                 curTime[2] = 0;
280                                 curTime[1]++;
281                                 if (curTime[1] == 60) {
282                                         curTime[1] = 0;
283                                         curTime[0]++;
284                                 }
285                         }
286
287                         if (stopth) break;
288                 }
289
290                 pthread_mutex_unlock(&mut);
291         }
292
293         return NULL;
294 }
295
296 // read track
297 // time:
298 //  byte 0 - minute
299 //  byte 1 - second
300 //  byte 2 - frame
301 // uses bcd format
302 long CDRreadTrack(unsigned char *time) {
303         if (!IsCdHandleOpen()) {
304                 memset(cr.buf, 0, DATA_SIZE);
305                 return 0;
306         }
307
308         PRINTF("CDRreadTrack %d:%d:%d\n", btoi(time[0]), btoi(time[1]), btoi(time[2]));
309
310         if (UseSubQ) memcpy(lastTime, time, 3);
311         subqread = 0;
312
313         cr.msf.cdmsf_min0 = btoi(time[0]);
314         cr.msf.cdmsf_sec0 = btoi(time[1]);
315         cr.msf.cdmsf_frame0 = btoi(time[2]);
316
317         return fReadTrack();
318 }
319
320 // return readed track
321 unsigned char *CDRgetBuffer(void) {
322         return fGetBuffer();
323 }
324
325 // plays cdda audio
326 // sector:
327 //  byte 0 - minute
328 //  byte 1 - second
329 //  byte 2 - frame
330 // does NOT uses bcd format
331 long CDRplay(unsigned char *sector) {
332         long ret;
333
334         if (!IsCdHandleOpen())
335                 return 0;
336
337         // If play was called with the same time as the previous call,
338         // don't restart it. Of course, if play is called with a different
339         // track, stop playing the current stream.
340         if (playing) {
341                 if (msf_to_lba(sector[0], sector[1], sector[2]) == initial_time)
342                         return 0;
343                 else
344                         CDRstop();
345         }
346
347         initial_time = msf_to_lba(sector[0], sector[1], sector[2]);
348
349         if (ReadMode == THREADED) pthread_mutex_lock(&mut);
350         ret = PlayCDDA(sector);
351         if (ReadMode == THREADED) pthread_mutex_unlock(&mut);
352
353         if (ret == 0) {
354                 playing = 1;
355                 return 0;
356         }
357
358         return -1;
359 }
360
361 // stops cdda audio
362 long CDRstop(void) {
363         long ret;
364
365         if (!IsCdHandleOpen())
366                 return 0;
367
368         if (ReadMode == THREADED) pthread_mutex_lock(&mut);
369         ret = StopCDDA();
370         if (ReadMode == THREADED) pthread_mutex_unlock(&mut);
371
372         if (ret == 0) {
373                 playing = 0;
374                 initial_time = 0;
375
376                 return 0;
377         }
378
379         return -1;
380 }
381
382 // reads cdr status
383 // type:
384 //  0x00 - unknown
385 //  0x01 - data
386 //  0x02 - audio
387 //  0xff - no cdrom
388 // status: (only shell open supported)
389 //  0x00 - unknown
390 //  0x01 - error
391 //  0x04 - seek error
392 //  0x10 - shell open
393 //  0x20 - reading
394 //  0x40 - seeking
395 //  0x80 - playing
396 // time:
397 //  byte 0 - minute
398 //  byte 1 - second
399 //  byte 2 - frame
400
401 long CDRgetStatus(struct CdrStat *stat) {
402         long ret;
403
404         if (!IsCdHandleOpen())
405                 return -1;
406
407         if (ReadMode == THREADED) pthread_mutex_lock(&mut);
408         ret = GetStatus(playing, stat);
409         if (ReadMode == THREADED) pthread_mutex_unlock(&mut);
410
411         return ret;
412 }
413
414 unsigned char *CDRgetBufferSub(void) {
415         static unsigned char *p = NULL;
416
417         if (!UseSubQ) return NULL;
418         if (subqread) return p;
419
420         if (ReadMode == THREADED) pthread_mutex_lock(&mut);
421         p = ReadSub(lastTime);
422         if (ReadMode == THREADED) pthread_mutex_unlock(&mut);
423
424         if (p != NULL) subqread = 1;
425
426         return p;
427 }
428
429 // read CDDA sector into buffer
430 long CDRreadCDDA(unsigned char m, unsigned char s, unsigned char f, unsigned char *buffer) {
431         unsigned char msf[3] = {m, s, f};
432         unsigned char *p;
433
434         if (CDRreadTrack(msf) != 0) return -1;
435
436         p = CDRgetBuffer();
437         if (p == NULL) return -1;
438
439         memcpy(buffer, p - 12, CD_FRAMESIZE_RAW); // copy from the beginning of the sector
440         return 0;
441 }
442
443 // get Track End Time
444 long CDRgetTE(unsigned char track, unsigned char *m, unsigned char *s, unsigned char *f) {
445         long ret;
446
447         if (!IsCdHandleOpen()) return -1;
448
449         if (ReadMode == THREADED) pthread_mutex_lock(&mut);
450         ret = GetTE(track, m, s, f);
451         if (ReadMode == THREADED) pthread_mutex_unlock(&mut);
452
453         return ret;
454 }
455
456 #ifndef _MACOSX
457
458 void ExecCfg(char *arg) {
459         char cfg[256];
460         struct stat buf;
461
462         strcpy(cfg, "./cfgDFCdrom");
463         if (stat(cfg, &buf) != -1) {
464                 if (fork() == 0) {
465                         execl(cfg, "cfgDFCdrom", arg, NULL);
466                         exit(0);
467                 }
468                 return;
469         }
470
471         strcpy(cfg, "./cfg/DFCdrom");
472         if (stat(cfg, &buf) != -1) {
473                 if (fork() == 0) {
474                         execl(cfg, "cfgDFCdrom", arg, NULL);
475                         exit(0);
476                 }
477                 return;
478         }
479
480         fprintf(stderr, "cfgDFCdrom file not found!\n");
481 }
482
483 long CDRconfigure() {
484 #ifndef USE_NULL
485         ExecCfg("configure");
486 #endif
487         return 0;
488 }
489
490 void CDRabout() {
491         ExecCfg("about");
492 }
493
494 #endif
495
496 long CDRtest(void) {
497 #ifndef USE_NULL
498         if (OpenCdHandle(CdromDev) == -1)
499                 return -1;
500         CloseCdHandle();
501 #endif
502         return 0;
503 }
504
505 char *PSEgetLibName(void) {
506         return _(LibName);
507 }
508
509 unsigned long PSEgetLibType(void) {
510         return PSE_LT_CDR;
511 }
512
513 unsigned long PSEgetLibVersion(void) {
514         return 1 << 16;
515 }