#include #include #include #include #include "../../file_io.h" #include "../../user_io.h" #include "../../spi.h" #include "../../hardware.h" #include "../../menu.h" #include "pcecd.h" static int need_reset=0; static uint8_t has_command = 0; void pcecd_poll() { static uint32_t poll_timer = 0; static uint8_t last_req = 0; static uint8_t adj = 0; if (!poll_timer) poll_timer = GetTimer(13); if (CheckTimer(poll_timer)) { if ((!pcecdd.latency) && (pcecdd.state == PCECD_STATE_READ)) { poll_timer += 16; // 16.0ms between frames if reading data */ } else { poll_timer += 13 + ((adj == 3) ? 1 : 0); // 13.33ms otherwise (including latency counts) */ if (adj > 3) adj = 3; if (--adj <= 0) adj = 3; } if (pcecdd.has_status && !pcecdd.latency) { pcecdd.SendStatus(pcecdd.GetStatus()); pcecdd.has_status = 0; } else if (pcecdd.data_req && !pcecdd.latency) { pcecdd.SendDataRequest(); pcecdd.data_req = false; } pcecdd.Update(); } uint8_t req = spi_uio_cmd_cont(UIO_CD_GET); if (req != last_req) { last_req = req; uint16_t data_in[7]; data_in[0] = spi_w(0); data_in[1] = spi_w(0); data_in[2] = spi_w(0); data_in[3] = spi_w(0); data_in[4] = spi_w(0); data_in[5] = spi_w(0); data_in[6] = spi_w(0); DisableIO(); switch (data_in[6] & 0xFF) { case 0: pcecdd.SetCommand((uint8_t*)data_in); pcecdd.CommandExec(); has_command = 1; break; case 1: //TODO: process data pcecdd.SendStatus(0); printf("\x1b[32mPCECD: Command MODESELECT6, received data\n\x1b[0m"); break; case 2: pcecdd.can_read_next = true; break; default: need_reset = 1; break; } //printf("\x1b[32mMCD: Get command, command = %04X%04X%04X, has_command = %u\n\x1b[0m", data_in[2], data_in[1], data_in[0], has_command); } else DisableIO(); if (need_reset) { need_reset = 0; pcecdd.Reset(); poll_timer = 0; printf("\x1b[32mPCECD: Reset\n\x1b[0m"); } } void pcecd_reset() { need_reset = 1; } static void notify_mount(int load) { spi_uio_cmd16(UIO_SET_SDINFO, load); spi_uio_cmd8(UIO_SET_SDSTAT, 1); if (!load) { user_io_status_set("[0]", 1); usleep(100000); user_io_status_set("[0]", 0); } } int pcecd_using_cd() { return pcecdd.loaded; } static char buf[1024]; static char us_sig[] = { 0x72, 0xA2, 0xC2, 0x04, 0x12, 0xF6, 0xB6, 0xA6, 0x04, 0xA2, 0x36, 0xA6, 0xC6, 0x2E, 0x4E, 0xF6, 0x76, 0x96, 0xC6, 0xCE, 0x34, 0x32, 0x2E, 0x26, 0x74, 0x00 }; static int load_bios(char *biosname, const char *cuename, int sgx) { fileTYPE f; if (!FileOpen(&f, biosname)) return 0; uint8_t us_cart = 0, swap = 0; uint32_t start = f.size & 0x3FF; uint32_t size = f.size; if (size >= 262144) { size = 262144; FileSeek(&f, start + size - 26, SEEK_SET); memset(buf, 0, sizeof(buf)); FileReadAdv(&f, buf, 26); swap = !memcmp(buf, us_sig, sizeof(us_sig)) ? 1 : 0; } printf("CD SGX mode = %d\n", sgx); user_io_set_index(sgx ? 1 : 0); user_io_set_download(1); FileSeek(&f, start, SEEK_SET); while (size) { int chunk = (size > sizeof(buf)) ? sizeof(buf) : size; size -= chunk; FileReadAdv(&f, buf, chunk); if (swap) { for (int i = 0; i < chunk; i++) { unsigned char c = buf[i]; buf[i] = ((c & 1) << 7) | ((c & 2) << 5) | ((c & 4) << 3) | ((c & 8) << 1) | ((c & 16) >> 1) | ((c & 32) >> 3) | ((c & 64) >> 5) | ((c & 128) >> 7); } } else if (f.size >= 262144) { for (int i = 0; i < chunk - 8; i++) { if (!memcmp(buf + i, "ALL DATA", 8)) us_cart = 1; } } user_io_file_tx_data((uint8_t*)buf, chunk); } FileGenerateSavePath(cuename, buf); user_io_file_mount(buf, 0, 1); user_io_set_download(0); pcecdd.SetRegion(swap | us_cart); return 1; } void pcecd_set_image(int num, const char *filename) { (void)num; pcecdd.Unload(); pcecdd.state = PCECD_STATE_NODISC; if (strlen(filename)) { printf("Load CD: %s\n", filename); if (pcecdd.Load(filename) > 0) { pcecdd.state = pcecdd.loaded ? PCECD_STATE_IDLE : PCECD_STATE_NODISC; pcecdd.latency = 10; pcecdd.SendData = pcecd_send_data; int sgx = 0; // load CD BIOS strcpy(buf, filename); char *p = strrchr(buf, '/'); int loaded = 0; if (p) { p++; strcpy(p, "sgx"); if (FileExists(buf)) sgx = 1; strcpy(p, "cd_bios.rom"); loaded = load_bios(buf, filename, sgx); } if (!loaded) { sprintf(buf, "%s/cd_bios.rom", HomeDir(PCECD_DIR)); loaded = load_bios(buf, filename, sgx); } if (!loaded) Info("CD BIOS not found!", 4000); notify_mount(1); } else { notify_mount(0); pcecdd.state = PCECD_STATE_NODISC; } } else { pcecdd.Unload(); notify_mount(0); pcecdd.state = PCECD_STATE_NODISC; } } int pcecd_send_data(uint8_t* buf, int len, uint8_t index) { user_io_set_index(index); user_io_set_download(1); user_io_file_tx_data(buf, len); user_io_set_download(0); return 1; }