/* * Cdrom for Psemu Pro like Emulators * * By: linuzappz * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "cdr.h" #ifdef ENABLE_NLS #include #include #define _(x) gettext(x) #define N_(x) (x) #else #define _(x) (x) #define N_(x) (x) #endif #ifdef __linux__ static inline int msf_to_lba(char m, char s, char f) { return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; } int initial_time = 0; pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; long (*ReadTrackT[])() = { ReadNormal, ReadThreaded, }; unsigned char* (*GetBufferT[])() = { GetBNormal, GetBThreaded, }; long (*fReadTrack)(); unsigned char* (*fGetBuffer)(); void *CdrThread(void *arg); char *LibName = N_("CD-ROM Drive Reader"); #else char *LibName = N_("CDR NULL Plugin"); #endif char *PSEgetLibName(void) { return _(LibName); } unsigned long PSEgetLibType(void) { return PSE_LT_CDR; } unsigned long PSEgetLibVersion(void) { return 1 << 16; } #ifdef __linux__ long CDRinit(void) { cdHandle = -1; thread = -1; return 0; } long CDRshutdown(void) { return 0; } long CDRopen(void) { LoadConf(); if (cdHandle > 0) return 0; /* it's already open */ cdHandle = open(CdromDev, O_RDONLY); if (cdHandle != -1) { // if we can't open the cdrom we'll works as a null plugin ioctl(cdHandle, CDROM_LOCKDOOR, 0); // ioctl(cdHandle, CDROMSTART, NULL); ioctl(cdHandle, CDROM_SELECT_SPEED, CdrSpeed); } else { fprintf(stderr, "CDR: Could not open %s\n", CdromDev); } fReadTrack = ReadTrackT[ReadMode]; fGetBuffer = GetBufferT[ReadMode]; if (ReadMode == THREADED) { cdcache = (CacheData *)malloc(CacheSize * sizeof(CacheData)); if (cdcache == NULL) return -1; memset(cdcache, 0, CacheSize * sizeof(CacheData)); } else { cdbuffer = cr.buf + 12; /* skip sync data */ } if (ReadMode == THREADED) { pthread_attr_t attr; pthread_mutex_init(&mut, NULL); pthread_cond_init(&cond, NULL); locked = 0; pthread_attr_init(&attr); pthread_create(&thread, &attr, CdrThread, NULL); cacheaddr = -1; } else thread = -1; playing = 0; stopth = 0; initial_time = 0; return 0; } long CDRclose(void) { if (cdHandle < 1) return 0; if (playing) CDRstop(); close(cdHandle); cdHandle = -1; if (thread != -1) { if (locked == 0) { stopth = 1; while (locked == 0) usleep(5000); } stopth = 2; pthread_mutex_lock(&mut); pthread_cond_signal(&cond); pthread_mutex_unlock(&mut); pthread_join(thread, NULL); pthread_mutex_destroy(&mut); pthread_cond_destroy(&cond); } if (ReadMode == THREADED) { free(cdcache); } return 0; } // return Starting and Ending Track // buffer: // byte 0 - start track // byte 1 - end track long CDRgetTN(unsigned char *buffer) { struct cdrom_tochdr toc; if (cdHandle < 1) { buffer[0] = 1; buffer[1] = 1; return 0; } if (ioctl(cdHandle, CDROMREADTOCHDR, &toc) == -1) return -1; buffer[0] = toc.cdth_trk0; // start track buffer[1] = toc.cdth_trk1; // end track return 0; } // return Track Time // buffer: // byte 0 - frame // byte 1 - second // byte 2 - minute long CDRgetTD(unsigned char track, unsigned char *buffer) { struct cdrom_tocentry entry; if (cdHandle < 1) { memset(buffer + 1, 0, 3); return 0; } if (track == 0) track = 0xaa; // total time entry.cdte_track = track; entry.cdte_format = CDROM_MSF; if (ioctl(cdHandle, CDROMREADTOCENTRY, &entry) == -1) return -1; buffer[0] = entry.cdte_addr.msf.frame; /* frame */ buffer[1] = entry.cdte_addr.msf.second; /* second */ buffer[2] = entry.cdte_addr.msf.minute; /* minute */ return 0; } // normal reading long ReadNormal() { if (ioctl(cdHandle, CDROMREADRAW, &cr) == -1) return -1; return 0; } unsigned char* GetBNormal() { return cdbuffer; } // threaded reading (with cache) long ReadThreaded() { int addr = msf_to_lba(cr.msf.cdmsf_min0, cr.msf.cdmsf_sec0, cr.msf.cdmsf_frame0); int i; if (addr >= cacheaddr && addr < (cacheaddr + CacheSize) && cacheaddr != -1) { i = addr - cacheaddr; // printf("found %d\n", (addr - cacheaddr)); cdbuffer = cdcache[i].cr.buf + 12; while (btoi(cdbuffer[0]) != cr.msf.cdmsf_min0 || btoi(cdbuffer[1]) != cr.msf.cdmsf_sec0 || btoi(cdbuffer[2]) != cr.msf.cdmsf_frame0) { if (locked == 1) { if (cdcache[i].ret == 0) break; return -1; } usleep(5000); } // printf("%x:%x:%x, %p, %p\n", cdbuffer[0], cdbuffer[1], cdbuffer[2], cdbuffer, cdcache); found = 1; return 0; } else found = 0; if (locked == 0) { stopth = 1; while (locked == 0) { usleep(5000); } stopth = 0; } // not found in cache locked = 0; pthread_mutex_lock(&mut); pthread_cond_signal(&cond); pthread_mutex_unlock(&mut); return 0; } unsigned char* GetBThreaded() { // printf("threadc %d\n", found); if (found == 1) { found = 0; return cdbuffer; } cdbuffer = cdcache[0].cr.buf + 12; while (btoi(cdbuffer[0]) != cr.msf.cdmsf_min0 || btoi(cdbuffer[1]) != cr.msf.cdmsf_sec0 || btoi(cdbuffer[2]) != cr.msf.cdmsf_frame0) { if (locked == 1) return NULL; usleep(5000); } if (cdcache[0].ret == -1) return NULL; return cdbuffer; } // read track // time: // byte 0 - minute // byte 1 - second // byte 2 - frame // uses bcd format long CDRreadTrack(unsigned char *time) { if (cdHandle < 1) { memset(cr.buf, 0, DATA_SIZE); return 0; } // printf("CDRreadTrack %d:%d:%d\n", btoi(time[0]), btoi(time[1]), btoi(time[2])); if (UseSubQ) memcpy(lastTime, time, 3); subqread = 0; cr.msf.cdmsf_min0 = btoi(time[0]); cr.msf.cdmsf_sec0 = btoi(time[1]); cr.msf.cdmsf_frame0 = btoi(time[2]); return fReadTrack(); } void *CdrThread(void *arg) { unsigned char curTime[3]; int i; for (;;) { locked = 1; pthread_mutex_lock(&mut); pthread_cond_wait(&cond, &mut); if (stopth == 2) pthread_exit(NULL); // refill the buffer cacheaddr = msf_to_lba(cr.msf.cdmsf_min0, cr.msf.cdmsf_sec0, cr.msf.cdmsf_frame0); memcpy(curTime, &cr.msf, 3); // printf("start thc %d:%d:%d\n", curTime[0], curTime[1], curTime[2]); for (i=0; iTime, &sc.cdsc_absaddr.msf, 3); } ret = ioctl(cdHandle, CDROM_DISC_STATUS); switch (ret) { case CDS_AUDIO: stat->Type = 0x02; break; case CDS_DATA_1: case CDS_DATA_2: case CDS_XA_2_1: case CDS_XA_2_2: stat->Type = 0x01; break; } ret = ioctl(cdHandle, CDROM_DRIVE_STATUS); switch (ret) { case CDS_NO_DISC: case CDS_TRAY_OPEN: stat->Type = 0xff; stat->Status |= 0x10; break; default: ioctl(cdHandle, CDROM_LOCKDOOR, 0); break; } switch (sc.cdsc_audiostatus) { case CDROM_AUDIO_PLAY: stat->Status |= 0x80; break; } memcpy(&ostat, stat, sizeof(struct CdrStat)); return 0; } struct SubQ { char res0[12]; unsigned char ControlAndADR; unsigned char TrackNumber; unsigned char IndexNumber; unsigned char TrackRelativeAddress[3]; unsigned char Filler; unsigned char AbsoluteAddress[3]; char res1[72]; }; struct SubQ subq; unsigned char *CDRgetBufferSub(void) { struct cdrom_subchnl subchnl; int ret; if (!UseSubQ) return NULL; if (subqread) return (unsigned char *)&subq; cr.msf.cdmsf_min0 = btoi(lastTime[0]); cr.msf.cdmsf_sec0 = btoi(lastTime[1]); cr.msf.cdmsf_frame0 = btoi(lastTime[2]); if (ioctl(cdHandle, CDROMSEEK, &cr.msf) == -1) { // will be slower, but there's no other way to make it accurate if (ioctl(cdHandle, CDROMREADRAW, &cr) == -1) return NULL; } subchnl.cdsc_format = CDROM_MSF; ret = ioctl(cdHandle, CDROMSUBCHNL, &subchnl); if (ret == -1) return NULL; subqread = 1; subq.TrackNumber = subchnl.cdsc_trk; subq.IndexNumber = subchnl.cdsc_ind; subq.TrackRelativeAddress[0] = itob(subchnl.cdsc_reladdr.msf.minute); subq.TrackRelativeAddress[1] = itob(subchnl.cdsc_reladdr.msf.second); subq.TrackRelativeAddress[2] = itob(subchnl.cdsc_reladdr.msf.frame); subq.AbsoluteAddress[0] = itob(subchnl.cdsc_absaddr.msf.minute); subq.AbsoluteAddress[1] = itob(subchnl.cdsc_absaddr.msf.second); subq.AbsoluteAddress[2] = itob(subchnl.cdsc_absaddr.msf.frame); #if 0 printf("subq : %x,%x : %x,%x,%x : %x,%x,%x\n", subchnl.cdsc_trk, subchnl.cdsc_ind, itob(subchnl.cdsc_reladdr.msf.minute), itob(subchnl.cdsc_reladdr.msf.second), itob(subchnl.cdsc_reladdr.msf.frame), itob(subchnl.cdsc_absaddr.msf.minute), itob(subchnl.cdsc_absaddr.msf.second), itob(subchnl.cdsc_absaddr.msf.frame)); #endif return (unsigned char *)&subq; } void ExecCfg(char *arg) { char cfg[256]; struct stat buf; strcpy(cfg, "./cfgDFCdrom"); if (stat(cfg, &buf) != -1) { strcat(cfg, " "); strcat(cfg, arg); system(cfg); return; } strcpy(cfg, "./cfg/DFCdrom"); if (stat(cfg, &buf) != -1) { strcat(cfg, " "); strcat(cfg, arg); system(cfg); return; } printf("cfgDFCdrom file not found!\n"); } long CDRconfigure() { ExecCfg("configure"); return 0; } void CDRabout() { ExecCfg("about"); } long CDRtest(void) { cdHandle = open(CdromDev, O_RDONLY); if (cdHandle == -1) return -1; close(cdHandle); cdHandle = -1; return 0; } #else long CDRinit(void) { return 0; } long CDRshutdown(void) { return 0; } long CDRopen(void) { return 0; } long CDRclose(void) { return 0; } long CDRgetTN(unsigned char *buffer) { buffer[0] = 1; buffer[1] = 1; return 0; } long CDRgetTD(unsigned char track, unsigned char *buffer) { memset(buffer + 1, 0, 3); return 0; } long CDRreadTrack(unsigned char *time) { return -1; } unsigned char *CDRgetBuffer(void) { return NULL; } long CDRplay(unsigned char *sector) { return 0; } long CDRstop(void) { return 0; } long CDRconfigure() { return 0; } void CDRabout() { } #endif