Commit | Line | Data |
---|---|---|
ef79bbde P |
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 | } |