void cdd_read_data(uint8 *dst) { /* only read DATA track sectors */ if ((cdd.lba >= 0) && (cdd.lba < cdd.toc.tracks[0].end)) { /* BIN format ? */ if (cdd.sectorSize == 2352) { /* skip 16-byte header */ pm_seek(cdd.toc.tracks[0].fd, cdd.lba * 2352 + 16, SEEK_SET); } /* read sector data (Mode 1 = 2048 bytes) */ pm_read(dst, 2048, cdd.toc.tracks[0].fd); } }
/* checks if romFileName points to valid MegaCD image * if so, checks for suitable BIOS */ int emu_cdCheck(int *pregion) { unsigned char buf[32]; pm_file *cd_f; int type = 0, region = 4; // 1: Japan, 4: US, 8: Europe cd_f = pm_open(romFileName); if (!cd_f) return 0; // let the upper level handle this if (pm_read(buf, 32, cd_f) != 32) { pm_close(cd_f); return 0; } if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x00, 14)) type = 1; // Sega CD (ISO) if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x10, 14)) type = 2; // Sega CD (BIN) if (type == 0) { pm_close(cd_f); return 0; } /* it seems we have a CD image here. Try to detect region now.. */ pm_seek(cd_f, (type == 1) ? 0x100+0x10B : 0x110+0x10B, SEEK_SET); pm_read(buf, 1, cd_f); pm_close(cd_f); if (buf[0] == 0x64) region = 8; // EU if (buf[0] == 0xa1) region = 1; // JAP lprintf("detected %s Sega/Mega CD image with %s region\n", type == 2 ? "BIN" : "ISO", region != 4 ? (region == 8 ? "EU" : "JAP") : "USA"); if (pregion != NULL) *pregion = region; return type; }
static int detect_media(const char *fname) { static const short sms_offsets[] = { 0x7ff0, 0x3ff0, 0x1ff0 }; static const char *sms_exts[] = { "sms", "gg", "sg" }; static const char *md_exts[] = { "gen", "bin", "smd" }; char buff0[32], buff[32]; unsigned short *d16; pm_file *pmf; char ext[5]; int i; get_ext(fname, ext); // detect wrong extensions if (!strcmp(ext, ".srm") || !strcmp(ext, "s.gz") || !strcmp(ext, ".mds")) // s.gz ~ .mds.gz return PM_BAD_DETECT; /* don't believe in extensions, except .cue */ if (strcasecmp(ext, ".cue") == 0) return PM_CD; pmf = pm_open(fname); if (pmf == NULL) return PM_BAD_DETECT; if (pm_read(buff0, 32, pmf) != 32) { pm_close(pmf); return PM_BAD_DETECT; } if (strncasecmp("SEGADISCSYSTEM", buff0 + 0x00, 14) == 0 || strncasecmp("SEGADISCSYSTEM", buff0 + 0x10, 14) == 0) { pm_close(pmf); return PM_CD; } /* check for SMD evil */ if (pmf->size >= 0x4200 && (pmf->size & 0x3fff) == 0x200) { if (pm_seek(pmf, sms_offsets[0] + 0x200, SEEK_SET) == sms_offsets[0] + 0x200 && pm_read(buff, 16, pmf) == 16 && strncmp("TMR SEGA", buff, 8) == 0) goto looks_like_sms; /* could parse further but don't bother */ goto extension_check; } /* MD header? Act as TMSS BIOS here */ if (pm_seek(pmf, 0x100, SEEK_SET) == 0x100 && pm_read(buff, 16, pmf) == 16) { if (strncmp(buff, "SEGA", 4) == 0 || strncmp(buff, " SEG", 4) == 0) goto looks_like_md; } for (i = 0; i < ARRAY_SIZE(sms_offsets); i++) { if (pm_seek(pmf, sms_offsets[i], SEEK_SET) != sms_offsets[i]) continue; if (pm_read(buff, 16, pmf) != 16) continue; if (strncmp("TMR SEGA", buff, 8) == 0) goto looks_like_sms; } extension_check: /* probably some headerless thing. Maybe check the extension after all. */ for (i = 0; i < ARRAY_SIZE(md_exts); i++) if (strcasecmp(pmf->ext, md_exts[i]) == 0) goto looks_like_md; for (i = 0; i < ARRAY_SIZE(sms_exts); i++) if (strcasecmp(pmf->ext, sms_exts[i]) == 0) goto looks_like_sms; /* If everything else fails, make a guess on the reset vector */ d16 = (unsigned short *)(buff0 + 4); if ((((d16[0] << 16) | d16[1]) & 0xffffff) >= pmf->size) { lprintf("bad MD reset vector, assuming SMS\n"); goto looks_like_sms; } looks_like_md: pm_close(pmf); return PM_MD_CART; looks_like_sms: pm_close(pmf); return PM_MARK3; }
/* checks if fname points to valid MegaCD image */ int PicoCdCheck(const char *fname_in, int *pregion) { const char *fname = fname_in; unsigned char buf[32]; pm_file *cd_f; int region = 4; // 1: Japan, 4: US, 8: Europe char ext[5]; cue_track_type type = CT_UNKNOWN; cue_data_t *cue_data = NULL; // opens a cue, or searches for one cue_data = cue_parse(fname_in); if (cue_data != NULL) { fname = cue_data->tracks[1].fname; type = cue_data->tracks[1].type; } else { get_ext(fname_in, ext); if (strcasecmp(ext, ".cue") == 0) return -1; } cd_f = pm_open(fname); if (cue_data != NULL) cue_destroy(cue_data); if (cd_f == NULL) return 0; // let the upper level handle this if (pm_read(buf, 32, cd_f) != 32) { pm_close(cd_f); return -1; } if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x00, 14)) { if (type && type != CT_ISO) elprintf(EL_STATUS, ".cue has wrong type: %i", type); type = CT_ISO; // Sega CD (ISO) } if (!strncasecmp("SEGADISCSYSTEM", (char *)buf+0x10, 14)) { if (type && type != CT_BIN) elprintf(EL_STATUS, ".cue has wrong type: %i", type); type = CT_BIN; // Sega CD (BIN) } if (type == CT_UNKNOWN) { pm_close(cd_f); return 0; } pm_seek(cd_f, (type == CT_ISO) ? 0x100 : 0x110, SEEK_SET); pm_read(media_id_header, sizeof(media_id_header), cd_f); /* it seems we have a CD image here. Try to detect region now.. */ pm_seek(cd_f, (type == CT_ISO) ? 0x100+0x10B : 0x110+0x10B, SEEK_SET); pm_read(buf, 1, cd_f); pm_close(cd_f); if (buf[0] == 0x64) region = 8; // EU if (buf[0] == 0xa1) region = 1; // JAP lprintf("detected %s Sega/Mega CD image with %s region\n", type == CT_BIN ? "BIN" : "ISO", region != 4 ? (region == 8 ? "EU" : "JAP") : "USA"); if (pregion != NULL) *pregion = region; return type; }
int cdd_context_load(uint8 *state) { int lba; int bufferptr = 0; #ifdef USE_LIBTREMOR #ifdef DISABLE_MANY_OGG_OPEN_FILES /* close previous track VORBIS file structure to save memory */ if (cdd.toc.tracks[cdd.index].vf.datasource) { ogg_free(cdd.index); } #endif #endif load_param(&cdd.cycles, sizeof(cdd.cycles)); load_param(&cdd.latency, sizeof(cdd.latency)); load_param(&cdd.index, sizeof(cdd.index)); load_param(&cdd.lba, sizeof(cdd.lba)); load_param(&cdd.scanOffset, sizeof(cdd.scanOffset)); load_param(&cdd.volume, sizeof(cdd.volume)); load_param(&cdd.status, sizeof(cdd.status)); /* adjust current LBA within track limit */ lba = cdd.lba; if (lba < cdd.toc.tracks[cdd.index].start) { lba = cdd.toc.tracks[cdd.index].start; } /* seek to current track position */ if (!cdd.index) { /* DATA track */ if (cdd.toc.tracks[0].fd) { pm_seek(cdd.toc.tracks[0].fd, lba * cdd.sectorSize, SEEK_SET); } } #ifdef USE_LIBTREMOR else if (cdd.toc.tracks[cdd.index].vf.seekable) { #ifdef DISABLE_MANY_OGG_OPEN_FILES /* VORBIS file need to be opened first */ ov_open(cdd.toc.tracks[cdd.index].fd,&cdd.toc.tracks[cdd.index].vf,0,0); #endif /* VORBIS AUDIO track */ ov_pcm_seek(&cdd.toc.tracks[cdd.index].vf, (lba - cdd.toc.tracks[cdd.index].start) * 588 - cdd.toc.tracks[cdd.index].offset); } #endif #if 0 else if (cdd.toc.tracks[cdd.index].fd) { /* PCM AUDIO track */ fseek(cdd.toc.tracks[cdd.index].fd, (lba * 2352) - cdd.toc.tracks[cdd.index].offset, SEEK_SET); } #else else { cdd_change_track(cdd.index, lba); } #endif return bufferptr; }
/* this is was a try to fight slow SD access of GP2X */ PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba) { int is_bin, offs, read_len, moved = 0; reads++; is_bin = Pico_mcd->TOC.Tracks[0].ftype == CT_BIN; if (PicoCDBuffers <= 0) { /* no buffering */ int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11); pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET); pm_read(dest, 2048, Pico_mcd->TOC.Tracks[0].F); return; } /* hit? */ offs = lba - prev_lba; if (offs >= 0 && offs < PicoCDBuffers) { hits++; if (offs == 0) dprintf("CD buffer seek to old %i -> %i\n", prev_lba, lba); memcpy32(dest, (int *)(cd_buffer + offs*2048), 2048/4); return; } if (prev_lba + PicoCDBuffers != lba) { int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11); dprintf("CD buffer seek %i -> %i\n", prev_lba, lba); pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET); } dprintf("CD buffer miss %i -> %i\n", prev_lba, lba); if (lba < prev_lba && prev_lba - lba < PicoCDBuffers) { read_len = prev_lba - lba; dprintf("CD buffer move=%i, read_len=%i", PicoCDBuffers - read_len, read_len); memmove(cd_buffer + read_len*2048, cd_buffer, (PicoCDBuffers - read_len)*2048); moved = 1; } else { read_len = PicoCDBuffers; } if (PicoMessage != NULL && read_len >= 512) { PicoMessage("Buffering data..."); } if (is_bin) { int i = 0; #ifdef _PSP_FW_VERSION int bufs = (read_len*2048) / (2048+304); pm_read(cd_buffer, bufs*(2048+304), Pico_mcd->TOC.Tracks[0].F); for (i = 1; i < bufs; i++) // should really use memmove here, but my memcpy32 implementation is also suitable here memcpy32((int *)(cd_buffer + i*2048), (int *)(cd_buffer + i*(2048+304)), 2048/4); #endif for (; i < read_len - 1; i++) { pm_read(cd_buffer + i*2048, 2048 + 304, Pico_mcd->TOC.Tracks[0].F); // pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR); // seeking is slower, in PSP case even more } // further data might be moved, do not overwrite pm_read(cd_buffer + i*2048, 2048, Pico_mcd->TOC.Tracks[0].F); pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR); } else { pm_read(cd_buffer, read_len*2048, Pico_mcd->TOC.Tracks[0].F); } memcpy32(dest, (int *) cd_buffer, 2048/4); prev_lba = lba; if (moved) { /* file pointer must point to the same data in file, as would-be data after our buffer */ int where_seek; lba += PicoCDBuffers; where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11); pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET); } }