bool CDIF_ReadRawSector(uint8 *buf, uint32 lba) { bool found = FALSE; // This shouldn't happen, the emulated-system-specific CDROM emulation code should make sure the emulated program doesn't try // to read past the last "real" sector of the disc. if(lba >= toc.tracks[100].lba) { printf("Attempt to read LBA %d, >= LBA %d\n", lba, toc.tracks[100].lba); return(FALSE); } ReadThreadQueue->Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba, 0, 0, 0, NULL)); do { MDFND_LockMutex(SBMutex); for(int i = 0; i < SBSize; i++) { if(SectorBuffers[i].valid && SectorBuffers[i].lba == lba) { memcpy(buf, SectorBuffers[i].data, 2352 + 96); found = TRUE; } } MDFND_UnlockMutex(SBMutex); if(!found) MDFND_Sleep(1); } while(!found); return(TRUE); }
void CDIF_MT::HintReadSector(uint32 lba) { if(UnrecoverableError) return; ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba)); }
bool CDIF_Close(void) { ReadThreadQueue->Write(CDIF_Message(CDIF_MSG_DIEDIEDIE, 0, 0, 0, 0, NULL)); MDFND_WaitThread(CDReadThread, NULL); if(SectorBuffers) { free(SectorBuffers); SectorBuffers = NULL; } if(ReadThreadQueue) { delete ReadThreadQueue; ReadThreadQueue = NULL; } if(EmuThreadQueue) { delete EmuThreadQueue; EmuThreadQueue = NULL; } if(SBMutex) { MDFND_DestroyMutex(SBMutex); SBMutex = NULL; } return(1); }
CDIF_MT::~CDIF_MT() { bool thread_deaded_failed = false; try { ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_DIEDIEDIE)); } catch(std::exception &e) { log_cb(RETRO_LOG_ERROR, "%s.\n", e.what()); thread_deaded_failed = true; } if(!thread_deaded_failed) sthread_join((sthread_t*)CDReadThread); if(SBMutex) { slock_free((slock_t*)SBMutex); SBMutex = NULL; } if(disc_cdaccess) { delete disc_cdaccess; disc_cdaccess = NULL; } }
bool CDIF_MT::ReadRawSector(uint8 *buf, uint32 lba) { bool found = FALSE; bool error_condition = false; if(UnrecoverableError) { memset(buf, 0, 2352 + 96); return(false); } // This shouldn't happen, the emulated-system-specific CDROM emulation code should make sure the emulated program doesn't try // to read past the last "real" sector of the disc. if(lba >= disc_toc.tracks[100].lba) { printf("Attempt to read LBA %d, >= LBA %d\n", lba, disc_toc.tracks[100].lba); return(FALSE); } ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba)); slock_lock((slock_t*)SBMutex); do { int i; for(i = 0; i < SBSize; i++) { if(SectorBuffers[i].valid && SectorBuffers[i].lba == lba) { error_condition = SectorBuffers[i].error; memcpy(buf, SectorBuffers[i].data, 2352 + 96); found = TRUE; } } if(!found) scond_wait((scond_t*)SBCond, (slock_t*)SBMutex); } while(!found); slock_unlock((slock_t*)SBMutex); return(!error_condition); }
bool CDIF_MT::Eject(bool eject_status) { if(UnrecoverableError) return(false); try { CDIF_Message msg; ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_EJECT, eject_status)); EmuThreadQueue.Read(&msg); } catch(std::exception &e) { log_cb(RETRO_LOG_ERROR, "Error on eject/insert attempt: %s\n", e.what()); return(false); } return(true); }
bool CDIF_HintReadSector(uint32 lba) { ReadThreadQueue->Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba, 0, 0, 0, NULL)); return(1); }
static int ReadThreadStart(void *arg) { char *device_name = (char *)arg; bool Running = TRUE; MDFN_printf(_("Loading %s...\n\n"), device_name ? device_name : _("PHYSICAL CDROM DISC")); MDFN_indent(1); if(!(p_cdrfile = cdrfile_open(device_name))) { MDFN_indent(-1); EmuThreadQueue->Write(CDIF_Message(CDIF_MSG_INIT_DONE, FALSE, 0, 0, 0, NULL)); return(0); } if(!cdrfile_read_toc(p_cdrfile, &toc)) { puts("Error reading TOC"); MDFN_indent(-1); EmuThreadQueue->Write(CDIF_Message(CDIF_MSG_INIT_DONE, FALSE, 0, 0, 0, NULL)); return(0); } if(toc.first_track < 1 || toc.last_track > 99 || toc.first_track > toc.last_track) { puts("First/Last track numbers bad"); MDFN_indent(-1); EmuThreadQueue->Write(CDIF_Message(CDIF_MSG_INIT_DONE, FALSE, 0, 0, 0, NULL)); return(0); } for(int32 track = toc.first_track; track <= toc.last_track; track++) { MDFN_printf(_("Track %2d, LBA: %6d %s\n"), track, toc.tracks[track].lba, (toc.tracks[track].control & 0x4) ? "DATA" : "AUDIO"); } MDFN_printf("Leadout: %6d\n", toc.tracks[100].lba); MDFN_indent(-1); EmuThreadQueue->Write(CDIF_Message(CDIF_MSG_INIT_DONE, TRUE, 0, 0, 0, NULL)); while(Running) { CDIF_Message msg; // Only do a blocking-wait for a message if we don't have any sectors to read-ahead. // MDFN_DispMessage("%d %d %d\n", last_read_lba, ra_lba, ra_count); if(ReadThreadQueue->Read(&msg, ra_count ? FALSE : TRUE)) { switch(msg.message) { case CDIF_MSG_DIEDIEDIE: Running = FALSE; break; case CDIF_MSG_READ_SECTOR: { static const int max_ra = 16; static const int initial_ra = 1; static const int speedmult_ra = 2; uint32 new_lba = msg.args[0]; assert((unsigned int)max_ra < (SBSize / 4)); if(new_lba == (last_read_lba + 1)) { int how_far_ahead = ra_lba - new_lba; assert(how_far_ahead >= 0); if(how_far_ahead <= max_ra) ra_count = std::min(speedmult_ra, 1 + max_ra - how_far_ahead); else ra_count++; } else { ra_lba = new_lba; ra_count = initial_ra; } last_read_lba = new_lba; } break; } } // Don't read >= the "end" of the disc, silly snake. Slither. if(ra_count && ra_lba == toc.tracks[100].lba) { ra_count = 0; //printf("Ephemeral scarabs: %d!\n", ra_lba); } if(ra_count) { uint8 tmpbuf[2352 + 96]; if(!cdrfile_read_raw_sector(p_cdrfile, tmpbuf, ra_lba)) { printf("Sector %d read error! Abandon ship!", ra_lba); memset(tmpbuf, 0, sizeof(tmpbuf)); } MDFND_LockMutex(SBMutex); SectorBuffers[SBWritePos].lba = ra_lba; memcpy(SectorBuffers[SBWritePos].data, tmpbuf, 2352 + 96); SectorBuffers[SBWritePos].valid = TRUE; SBWritePos = (SBWritePos + 1) % SBSize; MDFND_UnlockMutex(SBMutex); ra_lba++; ra_count--; } } if(p_cdrfile) { cdrfile_destroy(p_cdrfile); p_cdrfile = NULL; } return(1); }
int CDIF_MT::ReadThreadStart() { bool Running = TRUE; DiscEjected = true; SBWritePos = 0; ra_lba = 0; ra_count = 0; last_read_lba = ~0U; try { RT_EjectDisc(false, true); } catch(std::exception &e) { EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_FATAL_ERROR, std::string(e.what()))); return(0); } EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_DONE)); while(Running) { CDIF_Message msg; // Only do a blocking-wait for a message if we don't have any sectors to read-ahead. // MDFN_DispMessage("%d %d %d\n", last_read_lba, ra_lba, ra_count); if(ReadThreadQueue.Read(&msg, ra_count ? FALSE : TRUE)) { switch(msg.message) { case CDIF_MSG_DIEDIEDIE: Running = FALSE; break; case CDIF_MSG_EJECT: try { RT_EjectDisc(msg.args[0]); EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_DONE)); } catch(std::exception &e) { EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_FATAL_ERROR, std::string(e.what()))); } break; case CDIF_MSG_READ_SECTOR: { static const int max_ra = 16; static const int initial_ra = 1; static const int speedmult_ra = 2; uint32_t new_lba = msg.args[0]; assert((unsigned int)max_ra < (SBSize / 4)); if(last_read_lba != ~0U && new_lba == (last_read_lba + 1)) { int how_far_ahead = ra_lba - new_lba; if(how_far_ahead <= max_ra) ra_count = MIN(speedmult_ra, 1 + max_ra - how_far_ahead); else ra_count++; } else if(new_lba != last_read_lba) { ra_lba = new_lba; ra_count = initial_ra; } last_read_lba = new_lba; } break; } } // Don't read >= the "end" of the disc, silly snake. Slither. if(ra_count && ra_lba == disc_toc.tracks[100].lba) { ra_count = 0; //printf("Ephemeral scarabs: %d!\n", ra_lba); } if(ra_count) { uint8_t tmpbuf[2352 + 96]; bool error_condition = false; try { disc_cdaccess->Read_Raw_Sector(tmpbuf, ra_lba); } catch(std::exception &e) { log_cb(RETRO_LOG_ERROR, "Sector %u read error: %s\n", ra_lba, e.what()); memset(tmpbuf, 0, sizeof(tmpbuf)); error_condition = true; } slock_lock((slock_t*)SBMutex); SectorBuffers[SBWritePos].lba = ra_lba; memcpy(SectorBuffers[SBWritePos].data, tmpbuf, 2352 + 96); SectorBuffers[SBWritePos].valid = TRUE; SectorBuffers[SBWritePos].error = error_condition; SBWritePos = (SBWritePos + 1) % SBSize; scond_signal((scond_t*)SBCond); slock_unlock((slock_t*)SBMutex); ra_lba++; ra_count--; } } return(1); }