+static int card_buf_io(int is_write, int port, void *buf, u32 size)
+{
+ char *mcdptr = port ? Mcd2Data : Mcd1Data;
+ FileDesc *desc = &FDesc[2 + port];
+ u32 offset = 8192 * desc->mcfile + desc->offset;
+
+ PSXBIOS_LOG("card_%s_buf %d,%d: ofs=%x(%x) sz=%x (%s)\n",
+ is_write ? "write" : "read", port, desc->mcfile,
+ desc->offset, offset, size, mcdptr + 128 * desc->mcfile + 0xa);
+ if (!(loadRam8(A_CARD_STATUS1 + port) & 1)) {
+ PSXBIOS_LOG(" ...busy %x\n", loadRam8(A_CARD_STATUS1 + port));
+ return -1;
+ }
+ UnDeliverEvent(0xf4000001, 0x0004);
+ UnDeliverEvent(0xf4000001, 0x8000);
+ UnDeliverEvent(0xf4000001, 0x2000);
+ UnDeliverEvent(0xf4000001, 0x0100);
+
+ if (offset >= 128*1024u) {
+ log_unhandled("card offs %x(%x)\n", desc->offset, offset);
+ DeliverEvent(0xf4000001, 0x8000); // ?
+ return -1;
+ }
+ if (offset + size >= 128*1024u) {
+ log_unhandled("card offs+size %x+%x\n", offset, size);
+ size = 128*1024 - offset;
+ }
+ if (is_write) {
+ memcpy(mcdptr + offset, buf, size);
+ if (port == 0)
+ SaveMcd(Config.Mcd1, Mcd1Data, offset, size);
+ else
+ SaveMcd(Config.Mcd2, Mcd2Data, offset, size);
+ }
+ else {
+ size_t ram_offset = (s8 *)buf - psxM;
+ memcpy(buf, mcdptr + offset, size);
+ if (ram_offset < 0x200000)
+ psxCpu->Clear(ram_offset, (size + 3) / 4);
+ }
+ desc->offset += size;
+ if (desc->mode & 0x8000) { // async
+ storeRam8(A_CARD_STATUS1 + port, is_write ? 4 : 2); // busy
+ storeRam32(A_CARD_HANDLER,
+ is_write ? CARD_HARDLER_WRITEM : CARD_HARDLER_READM);
+ card_io_delay = 2 + size / 1024; // hack
+ return 0;
+ }
+ return size;
+}
+