From 26a2d8ee27a06598f332d43f248859af5ce1da16 Mon Sep 17 00:00:00 2001 From: Zakk Date: Sun, 27 Dec 2020 16:39:44 -0500 Subject: [PATCH] Add CHD support for ao486 CD-ROM --- cd.h | 4 +- lib/libchdr/include/libchdr/chd.h | 1 + menu.cpp | 9 +- support/chd/mister_chd.cpp | 12 ++- support/chd/mister_chd.h | 2 +- support/megacd/megacdd.cpp | 6 +- support/pcecd/pcecdd.cpp | 6 +- support/x86/x86.cpp | 15 ++- support/x86/x86_cdrom.cpp | 169 +++++++++++++++++++++++++++--- support/x86/x86_ide.cpp | 11 +- support/x86/x86_ide.h | 10 ++ 11 files changed, 209 insertions(+), 36 deletions(-) diff --git a/cd.h b/cd.h index 0129315..4795edc 100644 --- a/cd.h +++ b/cd.h @@ -12,7 +12,7 @@ typedef struct int end; int type; int sector_size; -} track_t; +} cd_track_t; typedef struct { @@ -20,7 +20,7 @@ typedef struct int last; int sectorSize; chd_file *chd_f; - track_t tracks[100]; + cd_track_t tracks[100]; // fileTYPE sub; } toc_t; diff --git a/lib/libchdr/include/libchdr/chd.h b/lib/libchdr/include/libchdr/chd.h index 61b149d..6d86a90 100644 --- a/lib/libchdr/include/libchdr/chd.h +++ b/lib/libchdr/include/libchdr/chd.h @@ -418,6 +418,7 @@ CHD_EXPORT chd_error chd_codec_config(chd_file *chd, int param, void *config); /* return a string description of a codec */ CHD_EXPORT const char *chd_get_codec_name(UINT32 codec); + #ifdef __cplusplus } #endif diff --git a/menu.cpp b/menu.cpp index 91004b7..c2d4cf1 100644 --- a/menu.cpp +++ b/menu.cpp @@ -1973,15 +1973,14 @@ void HandleUI(void) memcpy(Selected_tmp, Selected_S[(int)ioctl_index], sizeof(Selected_tmp)); if (is_x86()) strcpy(Selected_tmp, x86_get_image_path(ioctl_index)); - if (is_pce() || is_megacd()) + if (is_pce() || is_megacd() || is_x86()) { - if (!strncasecmp(fs_pFileExt, "CUE", 3)) - { + //if (!strncasecmp(fs_pFileExt, "CUE", 3)) + //{ //look for CHD too - printf("LOOK FOR CHD\n"); strcat(fs_pFileExt, "CHD"); strcat(ext, "CHD"); - } + //} int num = ScanDirectory(Selected_tmp, SCANF_INIT, fs_pFileExt, 0); memcpy(Selected_tmp, Selected_S[(int)ioctl_index], sizeof(Selected_tmp)); diff --git a/support/chd/mister_chd.cpp b/support/chd/mister_chd.cpp index e7bf241..37454d6 100644 --- a/support/chd/mister_chd.cpp +++ b/support/chd/mister_chd.cpp @@ -48,7 +48,7 @@ chd_error mister_load_chd(const char *filename, toc_t *cd_toc) return CHDERR_NO_INTERFACE; //I'm not sure this error condition is possible, so just use whatever } - mister_chd_log("hunkbytes %d unitbytes %d logical length %d\n", chd_header->hunkbytes, chd_header->unitbytes, chd_header->logicalbytes); + mister_chd_log("hunkbytes %d unitbytes %d logical length %llu\n", chd_header->hunkbytes, chd_header->unitbytes, chd_header->logicalbytes); //Load track info int sector_cnt = 0; @@ -75,13 +75,19 @@ chd_error mister_load_chd(const char *filename, toc_t *cd_toc) cd_toc->tracks[cd_toc->last].start = 0; } - if (!strcmp(track_type, "MODE1_RAW") || !strcmp(track_type, "MODE2_RAW")) + if (!strcmp(track_type, "MODE1_RAW")) { cd_toc->tracks[cd_toc->last].sector_size = 2352; cd_toc->tracks[cd_toc->last].type = 1; + } else if (!strcmp(track_type, "MODE2_RAW")) { + cd_toc->tracks[cd_toc->last].sector_size = 2352; + cd_toc->tracks[cd_toc->last].type = 2; } else if (!strcmp(track_type, "MODE1")) { cd_toc->tracks[cd_toc->last].sector_size = 2048; cd_toc->tracks[cd_toc->last].type = 1; + } else if (!strcmp(track_type, "MODE2")) { + cd_toc->tracks[cd_toc->last].sector_size = 2336; + cd_toc->tracks[cd_toc->last].type = 2; } else if (!strcmp(track_type, "AUDIO")) { cd_toc->tracks[cd_toc->last].sector_size = 2352; cd_toc->tracks[cd_toc->last].type = 0; @@ -105,7 +111,7 @@ chd_error mister_load_chd(const char *filename, toc_t *cd_toc) } -chd_error mister_chd_read_sector(chd_file *chd_f, int lba, uint8_t d_offset, uint8_t s_offset, int length, uint8_t *destbuf, uint8_t *hunkbuf, int *hunknum) +chd_error mister_chd_read_sector(chd_file *chd_f, int lba, uint32_t d_offset, uint32_t s_offset, int length, uint8_t *destbuf, uint8_t *hunkbuf, int *hunknum) { int tmphnum = 0; diff --git a/support/chd/mister_chd.h b/support/chd/mister_chd.h index e422040..721de79 100644 --- a/support/chd/mister_chd.h +++ b/support/chd/mister_chd.h @@ -6,7 +6,7 @@ #include #include "../../cd.h" -chd_error mister_chd_read_sector(chd_file *chd_f, int lba, uint8_t d_offset, uint8_t s_offset, int length, uint8_t *destbuf, uint8_t *hunkbuf, int *hunknum); +chd_error mister_chd_read_sector(chd_file *chd_f, int lba, uint32_t d_offset, uint32_t s_offset, int length, uint8_t *destbuf, uint8_t *hunkbuf, int *hunknum); chd_error mister_load_chd(const char *filename, toc_t *cd_toc); #endif diff --git a/support/megacd/megacdd.cpp b/support/megacd/megacdd.cpp index 0413d30..f92dbaa 100644 --- a/support/megacd/megacdd.cpp +++ b/support/megacd/megacdd.cpp @@ -244,13 +244,13 @@ int cdd_t::Load(const char *filename) Unload(); - const char *ext = filename+strlen(filename)-3; - if (!strncasecmp("CUE", ext, 3)) + const char *ext = filename+strlen(filename)-4; + if (!strncasecmp(".cue", ext, 4)) { if (LoadCUE(filename)) { return (-1); } - } else if (!strncasecmp("CHD", ext, 3)) { + } else if (!strncasecmp(".chd", ext, 4)) { chd_error err = mister_load_chd(filename, &this->toc); if (err != CHDERR_NONE) { diff --git a/support/pcecd/pcecdd.cpp b/support/pcecd/pcecdd.cpp index 735ccbb..ce5c53f 100644 --- a/support/pcecd/pcecdd.cpp +++ b/support/pcecd/pcecdd.cpp @@ -251,11 +251,11 @@ int pcecdd_t::Load(const char *filename) { Unload(); - const char *ext = filename+strlen(filename)-3; - if (!strncasecmp("CUE", ext, 3)) + const char *ext = filename+strlen(filename)-4; + if (!strncasecmp(".cue", ext, 4)) { if (LoadCUE(filename)) return -1; - } else if (!strncasecmp("CHD", ext, 3)) { + } else if (!strncasecmp(".chd", ext, 4)) { mister_load_chd(filename, &this->toc); if (this->chd_hunkbuf) { diff --git a/support/x86/x86.cpp b/support/x86/x86.cpp index 121ddb4..356da26 100644 --- a/support/x86/x86.cpp +++ b/support/x86/x86.cpp @@ -245,11 +245,18 @@ static int img_mount(fileTYPE *f, const char *name, int rw) FileClose(f); int writable = 0, ret = 0; - if (strlen(name)) + int len = strlen(name); + if (len) { - writable = rw && FileCanWrite(name); - ret = FileOpenEx(f, name, writable ? (O_RDWR | O_SYNC) : O_RDONLY); - if (!ret) printf("Failed to open file %s\n", name); + const char *ext = name+len-4; + if (!strncasecmp(".chd", ext, 4)) + { + ret = 1; + } else { + writable = rw && FileCanWrite(name); + ret = FileOpenEx(f, name, writable ? (O_RDWR | O_SYNC) : O_RDONLY); + if (!ret) printf("Failed to open file %s\n", name); + } } if (!ret) diff --git a/support/x86/x86_cdrom.cpp b/support/x86/x86_cdrom.cpp index 2f26dd0..8dfe6d3 100644 --- a/support/x86/x86_cdrom.cpp +++ b/support/x86/x86_cdrom.cpp @@ -17,11 +17,13 @@ #include "../../user_io.h" #include "../../file_io.h" #include "../../hardware.h" +#include "../../cd.h" +#include "../../lib/libchdr/include/libchdr/chd.h" #include "x86.h" #include "x86_ide.h" #include "x86_cdrom.h" -#if 0 +#if 0 #define dbg_printf printf #define dbg_print_regs ide_print_regs #define dbg_hexdump hexdump @@ -47,6 +49,7 @@ #define CD_ERR_NO_DISK ((2 << 4) | ATA_ERR_ABRT) + typedef struct { unsigned char min; @@ -240,6 +243,87 @@ static int add_track(drive_t *drv, track_t *curr, uint32_t &shift, const int32_t return 1; } +static const char* load_chd_file(drive_t *drv, const char *chdfile) +{ + + //Borrow the cd.h "toc_t" and mister_chd* parse function. Then translate the toc_t to drive_t+track_t. + //TODO: abstract all the bin/cue+chd+iso parsing and reading into a shared class + // + + const char *ext = chdfile+strlen(chdfile)-4; + uint32_t total_sector_size = 0; + + + if (strncasecmp(".chd", ext, 4)) + { + //Not a CHD + return 0; + } + toc_t tmpTOC = { }; + memset(drv->track, 0, sizeof(drv->track)); + drv->track_cnt = 0; + chd_error err = mister_load_chd(chdfile, &tmpTOC); + if (err != CHDERR_NONE) + { + return 0; + } + + if (drv->chd_hunkbuf) + { + free(drv->chd_hunkbuf); + } + + drv->chd_hunkbuf = (uint8_t *)malloc(CD_FRAME_SIZE * CD_FRAMES_PER_HUNK); + drv->chd_hunknum = -1; + drv->chd_f = tmpTOC.chd_f; + + //don't use add_track, just do it ourselves... + for(int i = 0; i <= tmpTOC.last; i++) + { + cd_track_t *chd_track = &tmpTOC.tracks[i]; + track_t *trk = &drv->track[i]; + trk->number = i+1; + trk->sectorSize = chd_track->sector_size; + if (chd_track->type) + { + trk->attr = 0x40; + if (chd_track->type == 2) + { + trk->mode2 = true; + } + + } + + trk->chd_offset = chd_track->offset; + trk->start = chd_track->start; + trk->length = chd_track->end - chd_track->start; + drv->track_cnt++; + total_sector_size += trk->length * trk->sectorSize; + } + + //Add the lead-out track + + track_t *lead_out = &drv->track[drv->track_cnt]; + lead_out->number = drv->track_cnt+1; + lead_out->attr = 0; + lead_out->start = tmpTOC.tracks[tmpTOC.last].end; + lead_out->length = 0; + + drv->total_sectors = total_sector_size / 512; + drv->chd_total_size = total_sector_size; + + for(uint8_t i = 0; i < drv->track_cnt; i++) + { + if (drv->track[i].attr == 0x40) + { + drv->data_num = i; + } + } + + return chdfile; +} + + static const char* load_cue_file(drive_t *drv, const char *cuefile) { memset(drv->track, 0, sizeof(drv->track)); @@ -881,6 +965,8 @@ static void read_cd_sectors(ide_config *ide, int cnt) void cdrom_read(ide_config *ide) { uint32_t cnt = ide->regs.pkt_cnt; + drive_t *drive = &ide->drive[ide->regs.drv]; + if ((cnt * 4) > ide_io_max_size) cnt = ide_io_max_size / 4; while ((cnt * 2048) > ide->regs.pkt_size_limit) @@ -889,12 +975,13 @@ void cdrom_read(ide_config *ide) cnt--; } + if (cnt != ide->regs.pkt_cnt) { dbg_printf("** partial CD read\n"); } - if (ide->state == IDE_STATE_INIT_RW) + if (ide->state == IDE_STATE_INIT_RW && !drive->chd_f) { uint32_t pos = ide->regs.pkt_lba * ide->drive[ide->regs.drv].track[ide->drive[ide->regs.drv].data_num].sectorSize; @@ -902,7 +989,32 @@ void cdrom_read(ide_config *ide) ide->null = (FileSeek(ide->drive[ide->regs.drv].f, pos, SEEK_SET) < 0); } - read_cd_sectors(ide, cnt); + + if (drive->chd_f) { + + uint32_t hdr = drive->track[drive->data_num].mode2 ? 24 : 16; + if (drive->track[drive->data_num].sectorSize == 2048) + { + hdr = 0; + } + uint32_t d_offset = 0; + + if (ide->state == IDE_STATE_INIT_RW) + { + drive->chd_last_partial_lba = ide->regs.pkt_lba; + } + + for(uint32_t i = 0; i < cnt; i++) + { + + mister_chd_read_sector(drive->chd_f, drive->chd_last_partial_lba + drive->track[drive->data_num].chd_offset, d_offset, hdr, 2048, ide_buf, drive->chd_hunkbuf, &drive->chd_hunknum); + d_offset += 2048; + drive->chd_last_partial_lba++; + } + + } else { + read_cd_sectors(ide, cnt); + } dbg_printf("\nsector:\n"); dbg_hexdump(ide_buf, 512, 0); @@ -1093,10 +1205,17 @@ void cdrom_handle_pkt(ide_config *ide) break; case 0x25: // read capacity - //printf("** Read Capacity\n"); + dbg_printf("** Read Capacity\n"); if (!drv->load_state) { - uint32_t tmp = drv->f->size / 2048;; + uint32_t tmp = 0; + + if (drv->chd_f) + { + tmp = drv->chd_total_size / 2048; + } else { + tmp = drv->f->size / 2048; + } ide_buf[0] = tmp >> 24; ide_buf[1] = tmp >> 16; ide_buf[2] = tmp >> 8; @@ -1114,39 +1233,45 @@ void cdrom_handle_pkt(ide_config *ide) break; case 0x2B: // seek + + dbg_printf("** Seek\n"); drv->playing = 0; drv->paused = 0; cdrom_reply(ide, 0); break; case 0x1E: // lock the cd door - doing nothing. + dbg_printf("** Lock Door\n"); cdrom_reply(ide, 0); break; case 0x5A: // mode sense + dbg_printf("** Mode Sense\n"); pkt_send(ide, ide_buf, mode_sense(cmdbuf[2])); break; case 0x42: // read sub - dbg_printf("read sub:\n"); + dbg_printf("** read sub:\n"); pkt_send(ide, ide_buf, read_subchannel(drv, cmdbuf)); break; case 0x43: // read TOC + dbg_printf("** Read TOC\n"); pkt_send(ide, ide_buf, read_toc(drv, cmdbuf)); break; case 0x12: // inquiry + dbg_printf("** Inquiry\n"); pkt_send(ide, ide_buf, cd_inquiry(cmdbuf[4])); break; case 0x03: // mode sense - dbg_printf("get sense:\n"); + dbg_printf("** get sense:\n"); pkt_send(ide, ide_buf, get_sense(drv)); break; case 0x55: // mode select - printf("mode select\n"); + dbg_printf("** mode select\n"); ide->regs.cylinder = (cmdbuf[7] << 8) | cmdbuf[8]; if (ide->regs.cylinder > 512) ide->regs.cylinder = 512; ide->regs.pkt_io_size = (ide->regs.cylinder + 1) / 2; @@ -1157,24 +1282,25 @@ void cdrom_handle_pkt(ide_config *ide) break; case 0x00: // test unit ready + dbg_printf("** Test Unit Ready\n"); if (!drv->load_state) cdrom_reply(ide, 0); else cdrom_nodisk(ide); break; case 0x45: // play lba - printf("CD PLAY AUDIO(10)\n"); + dbg_printf("** CD PLAY AUDIO(10)\n"); play_audio10(drv, cmdbuf); cdrom_reply(ide, 0); break; case 0x47: // play msf - printf("CD PLAY AUDIO MSF\n"); + dbg_printf("** CD PLAY AUDIO MSF\n"); play_audio_msf(drv, cmdbuf); cdrom_reply(ide, 0); break; case 0x4B: // pause/resume - printf("CD PAUSE/RESUME\n"); + dbg_printf("** CD PAUSE/RESUME\n"); pause_resume(drv, cmdbuf); cdrom_reply(ide, 0); break; @@ -1294,6 +1420,23 @@ void cdrom_reply(ide_config *ide, uint8_t error) ide_set_regs(ide); } +void cdrom_close_chd(drive_t *drv) +{ + + if (drv->chd_f) + { + chd_close(drv->chd_f); + drv->chd_f = NULL; + } + + if (drv->chd_hunkbuf) + { + free(drv->chd_hunkbuf); + drv->chd_hunkbuf = NULL; + } + drv->chd_hunknum = -1; +} + const char* cdrom_parse(uint32_t num, const char *filename) { const char *res = 0; @@ -1303,7 +1446,9 @@ const char* cdrom_parse(uint32_t num, const char *filename) const char *path = getFullPath(filename); int drv = num & 1; num >>= 1; - res = load_cue_file(&ide_inst[num].drive[drv], path); + cdrom_close_chd(&ide_inst[num].drive[drv]); + res = load_chd_file(&ide_inst[num].drive[drv], path); + if (!res) res = load_cue_file(&ide_inst[num].drive[drv], path); if (!res) res = load_iso_file(&ide_inst[num].drive[drv], path); } return res; diff --git a/support/x86/x86_ide.cpp b/support/x86/x86_ide.cpp index b990ba6..a0120a1 100644 --- a/support/x86/x86_ide.cpp +++ b/support/x86/x86_ide.cpp @@ -115,7 +115,7 @@ void x86_ide_set(uint32_t num, uint32_t baseaddr, fileTYPE *f, int ver, int cd) drive->cylinders = 0; drive->heads = 0; drive->spt = 0; - drive->total_sectors = 0; + //drive->total_sectors = 0; drive->present = f ? 1 : 0; ide_inst[num].state = IDE_STATE_RESET; @@ -145,7 +145,12 @@ void x86_ide_set(uint32_t num, uint32_t baseaddr, fileTYPE *f, int ver, int cd) return; } - if(drive->f) drive->total_sectors = (drive->f->size / 512); + if(drive->f) + { + if (!drive->chd_f) drive->total_sectors = (drive->f->size / 512); + } else { + drive->total_sectors = 0; + } if (!drive->cd) { @@ -355,7 +360,7 @@ void x86_ide_set(uint32_t num, uint32_t baseaddr, fileTYPE *f, int ver, int cd) }; for (int i = 0; i < 256; i++) drive->id[i] = identify[i]; - drive->load_state = drive->f ? 1 : 3; + drive->load_state = (drive->f || drive->chd_f) ? 1 : 3; } if (ide_inst[num].drive[drv].present) diff --git a/support/x86/x86_ide.h b/support/x86/x86_ide.h index 70db020..7a91f4a 100644 --- a/support/x86/x86_ide.h +++ b/support/x86/x86_ide.h @@ -1,6 +1,8 @@ #ifndef X86_IDE_H #define X86_IDE_H +#include "../chd/mister_chd.h" + #define ATA_STATUS_BSY 0x80 // busy #define ATA_STATUS_RDY 0x40 // ready #define ATA_STATUS_DF 0x20 // device fault @@ -66,11 +68,13 @@ typedef struct uint8_t attr; uint8_t mode2; uint8_t number; + int chd_offset; } track_t; typedef struct { fileTYPE *f; + uint8_t present; uint8_t drvnum; @@ -93,6 +97,12 @@ typedef struct uint32_t play_start_lba; uint32_t play_end_lba; + chd_file *chd_f; + int chd_hunknum; + uint8_t *chd_hunkbuf; + uint32_t chd_total_size; + uint32_t chd_last_partial_lba; + uint16_t id[256]; } drive_t;