X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=pico%2Fmedia.c;h=f9b053bd93e9d69f1a930082efddcf28304fd464;hb=HEAD;hp=b7fa7f56732e0c97ce0634db3bb73bc94472a9e6;hpb=9e38b1f0d61b1f3d22cb253921afad8c84691bc4;p=picodrive.git diff --git a/pico/media.c b/pico/media.c index b7fa7f56..51e3fbd8 100644 --- a/pico/media.c +++ b/pico/media.c @@ -8,7 +8,7 @@ #include #include "pico_int.h" -#include "cd/cue.h" +#include "cd/cd_parse.h" unsigned char media_id_header[0x100]; @@ -31,34 +31,50 @@ static void get_ext(const char *file, char *ext) strlwr_(ext); } -static int detect_media(const char *fname) +static int detect_media(const char *fname, const unsigned char *rom, unsigned int romsize) { 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]; + static const char *sms_exts[] = { "sms", "gg", "sg", "sc" }; + static const char *md_exts[] = { "gen", "smd", "md", "32x" }; + static const char *pico_exts[] = { "pco" }; + char buff0[512], buff[32]; + unsigned short *d16 = NULL; + pm_file *pmf = NULL; + const char *ext_ptr = NULL; + char ext[8]; int i; - get_ext(fname, ext); + ext[0] = '\0'; + if ((ext_ptr = strrchr(fname, '.'))) { + strncpy(ext, ext_ptr + 1, sizeof(ext)); + ext[sizeof(ext) - 1] = '\0'; + } // detect wrong extensions - if (!strcmp(ext, ".srm") || !strcmp(ext, "s.gz") || !strcmp(ext, ".mds")) // s.gz ~ .mds.gz + if (!strcasecmp(ext, "srm") || !strcasecmp(ext, "gz")) // s.gz ~ .mds.gz return PM_BAD_DETECT; - /* don't believe in extensions, except .cue */ - if (strcasecmp(ext, ".cue") == 0) + /* don't believe in extensions, except .cue and .chd */ + if (strcasecmp(ext, "cue") == 0 || strcasecmp(ext, "chd") == 0) return PM_CD; - pmf = pm_open(fname); - if (pmf == NULL) - return PM_BAD_DETECT; + /* Open rom file, if required */ + if (!rom) { + pmf = pm_open(fname); + if (pmf == NULL) + return PM_BAD_DETECT; + romsize = pmf->size; + } - if (pm_read(buff0, 32, pmf) != 32) { - pm_close(pmf); - return PM_BAD_DETECT; + if (!rom) { + if (pm_read(buff0, 512, pmf) != 512) { + pm_close(pmf); + return PM_BAD_DETECT; + } + } else { + if (romsize < 512) + return PM_BAD_DETECT; + memcpy(buff0, rom, 512); } if (strncasecmp("SEGADISCSYSTEM", buff0 + 0x00, 14) == 0 || @@ -68,28 +84,53 @@ static int detect_media(const char *fname) } /* 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) + if (romsize >= 0x4200 && (romsize & 0x3fff) == 0x200) { + buff[0] = '\0'; + + if (!rom) { + if (pm_seek(pmf, sms_offsets[0] + 0x200, SEEK_SET) == sms_offsets[0] + 0x200) + pm_read(buff, 16, pmf); + } else { + if (romsize >= sms_offsets[0] + 0x200 + 16) + memcpy(buff, rom + sms_offsets[0] + 0x200, 16); + } + + if (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; + /* fetch header info */ + memset(buff, '\0', 17); + if (!rom) { + if (pm_seek(pmf, 0x100, SEEK_SET) == 0x100) + pm_read(buff, 16, pmf); + } else { + if (romsize >= 0x100 + 16) + memcpy(buff, rom + 0x100, 16); } + /* PICO header? Almost always appropriately marked */ + if (strstr(buff, " PICO ")) + goto looks_like_pico; + /* MD header? Act as TMSS BIOS here */ + 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 (!rom) { + if (pm_seek(pmf, sms_offsets[i], SEEK_SET) != sms_offsets[i]) + continue; - if (pm_read(buff, 16, pmf) != 16) - continue; + if (pm_read(buff, 16, pmf) != 16) + continue; + } else { + if (romsize < sms_offsets[i] + 16) + continue; + + memcpy(buff, rom + sms_offsets[i], 16); + } if (strncmp("TMR SEGA", buff, 8) == 0) goto looks_like_sms; @@ -97,20 +138,31 @@ static int detect_media(const char *fname) extension_check: /* probably some headerless thing. Maybe check the extension after all. */ + ext_ptr = pmf && *pmf->ext ? pmf->ext : ext; + for (i = 0; i < ARRAY_SIZE(md_exts); i++) - if (strcasecmp(pmf->ext, md_exts[i]) == 0) + if (strcasecmp(ext_ptr, 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) + if (strcasecmp(ext_ptr, sms_exts[i]) == 0) goto looks_like_sms; + for (i = 0; i < ARRAY_SIZE(pico_exts); i++) + if (strcasecmp(ext_ptr, pico_exts[i]) == 0) + goto looks_like_pico; + /* 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) { + if ((((d16[0] << 16) | d16[1]) & 0xffffff) >= romsize) { lprintf("bad MD reset vector, assuming SMS\n"); goto looks_like_sms; } + d16 = (unsigned short *)(buff0 + 0x1a0); + if ((((d16[0] << 16) | d16[1]) & 0xffffff) != 0) { + lprintf("bad MD rom start, assuming SMS\n"); + goto looks_like_sms; + } looks_like_md: pm_close(pmf); @@ -119,6 +171,10 @@ looks_like_md: looks_like_sms: pm_close(pmf); return PM_MARK3; + +looks_like_pico: + pm_close(pmf); + return PM_PICO; } /* checks if fname points to valid MegaCD image */ @@ -129,26 +185,31 @@ int PicoCdCheck(const char *fname_in, int *pregion) 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; + enum cd_track_type type = CT_UNKNOWN; + cd_data_t *cd_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 { + if (!cd_data && (cd_data = cue_parse(fname_in)) == NULL) { get_ext(fname_in, ext); if (strcasecmp(ext, ".cue") == 0) return -1; } + // opens a chd + if (!cd_data && (cd_data = chd_parse(fname_in)) == NULL) { + get_ext(fname_in, ext); + if (strcasecmp(ext, ".chd") == 0) + return -1; + } - cd_f = pm_open(fname); - if (cue_data != NULL) - cue_destroy(cue_data); + if (cd_data != NULL) { + // 1st track contains the code + fname = cd_data->tracks[1].fname; + type = cd_data->tracks[1].type; + } - if (cd_f == NULL) return 0; // let the upper level handle this + cd_f = pm_open(fname); + cdparse_destroy(cd_data); + if (cd_f == NULL) return CT_UNKNOWN; // let the upper level handle this if (pm_read(buf, 32, cd_f) != 32) { pm_close(cd_f); @@ -192,34 +253,35 @@ int PicoCdCheck(const char *fname_in, int *pregion) } enum media_type_e PicoLoadMedia(const char *filename, + const unsigned char *rom, unsigned int romsize, const char *carthw_cfg_fname, const char *(*get_bios_filename)(int *region, const char *cd_fname), void (*do_region_override)(const char *media_filename)) { const char *rom_fname = filename; enum media_type_e media_type; - enum cd_img_type cd_img_type = CIT_NOT_CD; + enum cd_track_type cd_img_type = CT_UNKNOWN; + pm_file *rom_file = NULL; unsigned char *rom_data = NULL; unsigned int rom_size = 0; - pm_file *rom = NULL; int cd_region = 0; int ret; - media_type = detect_media(filename); + media_type = detect_media(filename, rom, romsize); if (media_type == PM_BAD_DETECT) goto out; - if ((PicoAHW & PAHW_MCD) && Pico_mcd != NULL) + if ((PicoIn.AHW & PAHW_MCD) && Pico_mcd != NULL) cdd_unload(); PicoCartUnload(); - PicoAHW = 0; - PicoQuirks = 0; + PicoIn.AHW = 0; + PicoIn.quirks = 0; if (media_type == PM_CD) { // check for MegaCD image cd_img_type = PicoCdCheck(filename, &cd_region); - if ((int)cd_img_type >= 0 && cd_img_type != CIT_NOT_CD) + if ((int)cd_img_type >= 0 && cd_img_type != CT_UNKNOWN) { // valid CD image, ask frontend for BIOS.. rom_fname = NULL; @@ -230,7 +292,7 @@ enum media_type_e PicoLoadMedia(const char *filename, goto out; } - PicoAHW |= PAHW_MCD; + PicoIn.AHW |= PAHW_MCD; } else { media_type = PM_BAD_CD; @@ -238,19 +300,22 @@ enum media_type_e PicoLoadMedia(const char *filename, } } else if (media_type == PM_MARK3) { - lprintf("detected SMS ROM\n"); - PicoAHW = PAHW_SMS; + PicoIn.AHW = PAHW_SMS; + } + else if (media_type == PM_PICO) { + PicoIn.AHW = PAHW_PICO; } - rom = pm_open(rom_fname); - if (rom == NULL) { - lprintf("Failed to open ROM\n"); - media_type = PM_ERROR; - goto out; + if (!rom) { + rom_file = pm_open(rom_fname); + if (rom_file == NULL) { + lprintf("Failed to open ROM\n"); + media_type = PM_ERROR; + goto out; + } } - ret = PicoCartLoad(rom, &rom_data, &rom_size, (PicoAHW & PAHW_SMS) ? 1 : 0); - pm_close(rom); + ret = PicoCartLoad(rom_file, rom, romsize, &rom_data, &rom_size, (PicoIn.AHW & PAHW_SMS) ? 1 : 0); if (ret != 0) { if (ret == 2) lprintf("Out of memory\n"); else if (ret == 3) lprintf("Read failed\n"); @@ -266,7 +331,7 @@ enum media_type_e PicoLoadMedia(const char *filename, goto out; } - if (!(PicoAHW & PAHW_SMS)) { + if (!(PicoIn.AHW & PAHW_SMS)) { unsigned short *d = (unsigned short *)(rom_data + 4); if ((((d[0] << 16) | d[1]) & 0xffffff) >= (int)rom_size) { lprintf("bad reset vector\n"); @@ -276,36 +341,63 @@ enum media_type_e PicoLoadMedia(const char *filename, } // load config for this ROM (do this before insert to get correct region) - if (!(PicoAHW & PAHW_MCD)) { + if (!(PicoIn.AHW & PAHW_MCD)) { memcpy(media_id_header, rom_data + 0x100, sizeof(media_id_header)); if (do_region_override != NULL) do_region_override(filename); } + // simple test for GG. Do this here since m.hardware is nulled in Insert + if ((PicoIn.AHW & PAHW_SMS) && !PicoIn.hwSelect) { + const char *ext = NULL; + if (rom_file && (*rom_file->ext != '\0')) { + ext = rom_file->ext; + } + else if ((ext = strrchr(filename, '.'))) { + if (*(++ext) == '\0') { + ext = NULL; + } + } + if (ext && !strcasecmp(ext,"gg")) { + PicoIn.AHW |= PAHW_GG; + lprintf("detected GG ROM\n"); + } else if (ext && !strcasecmp(ext,"sg")) { + PicoIn.AHW |= PAHW_SG; + lprintf("detected SG-1000 ROM\n"); + } else if (ext && !strcasecmp(ext,"sc")) { + PicoIn.AHW |= PAHW_SC; + lprintf("detected SC-3000 ROM\n"); + } else + lprintf("detected SMS ROM\n"); + } + if (PicoCartInsert(rom_data, rom_size, carthw_cfg_fname)) { media_type = PM_ERROR; goto out; } rom_data = NULL; // now belongs to PicoCart - Pico.m.ncart_in = 0; // insert CD if it was detected - if (cd_img_type != CIT_NOT_CD) { + Pico.m.ncart_in = 0; + if (cd_img_type != CT_UNKNOWN) { ret = cdd_load(filename, cd_img_type); if (ret != 0) { PicoCartUnload(); media_type = PM_BAD_CD; goto out; } - Pico.m.ncart_in = 1; + if (Pico.romsize <= 0x20000) + Pico.m.ncart_in = 1; } - if (PicoQuirks & PQUIRK_FORCE_6BTN) + if (PicoIn.quirks & PQUIRK_FORCE_6BTN) PicoSetInputDevice(0, PICO_INPUT_PAD_6BTN); out: + if (rom_file) + pm_close(rom_file); if (rom_data) - free(rom_data); + PicoCartUnload(); return media_type; }