void sioWrite8(unsigned char value) { #ifdef PAD_LOG PAD_LOG("sio write8 %x\n", value); #endif switch (padst) { case 1: SIO_INT(); if ((value&0x40) == 0x40) { padst = 2; parp = 1; if (!Config.UseNet) { switch (CtrlReg&0x2002) { case 0x0002: buf[parp] = PAD1_poll(value); break; case 0x2002: buf[parp] = PAD2_poll(value); break; } }/* else { // SysPrintf("%x: %x, %x, %x, %x\n", CtrlReg&0x2002, buf[2], buf[3], buf[4], buf[5]); }*/ if (!(buf[parp] & 0x0f)) { bufcount = 2 + 32; } else { bufcount = 2 + (buf[parp] & 0x0f) * 2; } if (buf[parp] == 0x41) { switch (value) { case 0x43: buf[1] = 0x43; break; case 0x45: buf[1] = 0xf3; break; } } } else padst = 0; return; case 2: parp++; /* if (buf[1] == 0x45) { buf[parp] = 0; SIO_INT(); return; }*/ if (!Config.UseNet) { switch (CtrlReg&0x2002) { case 0x0002: buf[parp] = PAD1_poll(value); break; case 0x2002: buf[parp] = PAD2_poll(value); break; } } if (parp == bufcount) { padst = 0; return; } SIO_INT(); return; } switch (mcdst) { case 1: SIO_INT(); if (rdwr) { parp++; return; } parp = 1; switch (value) { case 0x52: rdwr = 1; break; case 0x57: rdwr = 2; break; default: mcdst = 0; } return; case 2: // address H SIO_INT(); adrH = value; *buf = 0; parp = 0; bufcount = 1; mcdst = 3; return; case 3: // address L SIO_INT(); adrL = value; *buf = adrH; parp = 0; bufcount = 1; mcdst = 4; return; case 4: SIO_INT(); parp = 0; switch (rdwr) { case 1: // read buf[0] = 0x5c; buf[1] = 0x5d; buf[2] = adrH; buf[3] = adrL; switch (CtrlReg&0x2002) { case 0x0002: memcpy(&buf[4], Mcd1Data + (adrL | (adrH << 8)) * 128, 128); break; case 0x2002: memcpy(&buf[4], Mcd2Data + (adrL | (adrH << 8)) * 128, 128); break; } { char xor = 0; int i; for (i=2;i<128+4;i++) xor^=buf[i]; buf[132] = xor; } buf[133] = 0x47; bufcount = 133; break; case 2: // write buf[0] = adrL; buf[1] = value; buf[129] = 0x5c; buf[130] = 0x5d; buf[131] = 0x47; bufcount = 131; break; } mcdst = 5; return; case 5: parp++; if (rdwr == 2) { if (parp < 128) buf[parp+1] = value; } SIO_INT(); return; } switch (value) { case 0x01: // start pad StatReg |= RX_RDY; // Transfer is Ready if (!Config.UseNet) { switch (CtrlReg&0x2002) { case 0x0002: buf[0] = PAD1_startPoll(1); break; case 0x2002: buf[0] = PAD2_startPoll(2); break; } } else { if ((CtrlReg & 0x2002) == 0x0002) { int i, j; PAD1_startPoll(1); buf[0] = 0; buf[1] = PAD1_poll(0x42); if (!(buf[1] & 0x0f)) { bufcount = 32; } else { bufcount = (buf[1] & 0x0f) * 2; } buf[2] = PAD1_poll(0); i = 3; j = bufcount; while (j--) { buf[i++] = PAD1_poll(0); } bufcount+= 3; if (NET_sendPadData(buf, bufcount) == -1) netError(); if (NET_recvPadData(buf, 1) == -1) netError(); if (NET_recvPadData(buf+128, 2) == -1) netError(); } else { memcpy(buf, buf+128, 32); } } bufcount = 2; parp = 0; padst = 1; SIO_INT(); return; case 0x81: // start memcard StatReg |= RX_RDY; memcpy(buf, cardh, 4); parp = 0; bufcount = 3; mcdst = 1; rdwr = 0; SIO_INT(); return; } }
void sioWrite8(u8 data) { #ifdef PAD_LOG PAD_LOG("sio write8 %x\n", value); #endif switch (padst) { case 1: SIO_INT(SIO_CYCLES); if ((data & 0x40) == 0x40) { padst = 2; parp = 1; switch (CtrlReg & 0x2002) { case 0x0002: buf[parp] = pad1Poll(data); break; case 0x2002: buf[parp] = pad2Poll(data); break; } if (!(buf[parp] & 0x0f)) { bufcount = 2 + 32; } else { bufcount = 2 + (buf[parp] & 0x0f) * 2; } if (buf[parp] == 0x41) { switch (data) { case 0x43: buf[1] = 0x43; break; case 0x45: buf[1] = 0xf3; break; } } } else padst = 0; return; case 2: parp++; /* if (buf[1] == 0x45) { buf[parp] = 0; SIO_INT(SIO_CYCLES); return; }*/ switch (CtrlReg & 0x2002) { case 0x0002: buf[parp] = pad1Poll(data); break; case 0x2002: buf[parp] = pad2Poll(data); break; } if (parp == bufcount) { padst = 0; return; } SIO_INT(SIO_CYCLES); return; } switch (mcdst) { case 1: SIO_INT(SIO_CYCLES); if (rdwr) { parp++; return; } parp = 1; switch (data) { case 0x52: rdwr = 1; break; case 0x57: rdwr = 2; break; default: mcdst = 0; } return; case 2: // address H SIO_INT(SIO_CYCLES); adrH = data; *buf = 0; parp = 0; bufcount = 1; mcdst = 3; return; case 3: // address L SIO_INT(SIO_CYCLES); adrL = data; *buf = adrH; parp = 0; bufcount = 1; mcdst = 4; return; case 4: SIO_INT(SIO_CYCLES); parp = 0; switch (rdwr) { case 1: // read buf[0] = 0x5c; buf[1] = 0x5d; buf[2] = adrH; buf[3] = adrL; switch (CtrlReg & 0x2002) { case 0x0002: memcpy(&buf[4], psxMcd1.memory + (adrL | (adrH << 8)) * 128, 128); break; case 0x2002: memcpy(&buf[4], psxMcd2.memory + (adrL | (adrH << 8)) * 128, 128); break; } { char xorVal = 0; int i; for (i = 2; i < 128 + 4; i++) xorVal ^= buf[i]; buf[132] = xorVal; } buf[133] = 0x47; bufcount = 133; break; case 2: // write buf[0] = adrL; buf[1] = data; buf[129] = 0x5c; buf[130] = 0x5d; buf[131] = 0x47; bufcount = 131; break; } mcdst = 5; return; case 5: parp++; if ((rdwr == 1 && parp == 132) || (rdwr == 2 && parp == 129)) { // clear "new card" flags if (CtrlReg & 0x2000) cardh2[1] &= ~8; else cardh1[1] &= ~8; } if (rdwr == 2) { if (parp < 128) buf[parp + 1] = data; } SIO_INT(SIO_CYCLES); return; } switch (data) { case 0x01: // start pad StatReg |= RX_RDY; // Transfer is Ready switch (CtrlReg & 0x2002) { case 0x0002: buf[0] = pad1StartPoll(1); break; case 0x2002: buf[0] = pad2StartPoll(2); break; } bufcount = 2; parp = 0; padst = 1; SIO_INT(SIO_CYCLES); return; case 0x81: // start memcard if (CtrlReg & 0x2000) { if (!psxMcd2.isEnabled()) goto no_device; memcpy(buf, cardh2, 4); } else { if (!psxMcd1.isEnabled()) goto no_device; memcpy(buf, cardh1, 4); } StatReg |= RX_RDY; parp = 0; bufcount = 3; mcdst = 1; rdwr = 0; SIO_INT(SIO_CYCLES); return; default: no_device: StatReg |= RX_RDY; buf[0] = 0xff; parp = 0; bufcount = 0; return; } }
void SIO_CommandWrite(u8 value,int way) { PAD_LOG("sio write8 %x", value); // PAD COMMANDS switch (sio.padst) { case 1: SIO_INT(); if ((value&0x40) == 0x40) { sio.padst = 2; sio.parp = 1; switch (sio.CtrlReg&0x2002) { case 0x0002: sio.packetsize ++; // Total packet size sent sio.buf[sio.parp] = PADpoll(value); break; case 0x2002: sio.packetsize ++; // Total packet size sent sio.buf[sio.parp] = PADpoll(value); break; } if (!(sio.buf[sio.parp] & 0x0f)) { sio.bufcount = 2 + 32; } else { sio.bufcount = 2 + (sio.buf[sio.parp] & 0x0f) * 2; } } else sio.padst = 0; return; case 2: sio.parp++; switch (sio.CtrlReg&0x2002) { case 0x0002: sio.packetsize ++; sio.buf[sio.parp] = PADpoll(value); break; case 0x2002: sio.packetsize ++; sio.buf[sio.parp] = PADpoll(value); break; } if (sio.parp == sio.bufcount) { sio.padst = 0; return; } SIO_INT(); return; case 3: // No pad connected. sio.parp++; if (sio.parp == sio.bufcount) { sio.padst = 0; return; } SIO_INT(); return; } // MEMORY CARD COMMANDS switch (sio.mcdst) { case 1: { sio.packetsize++; SIO_INT(); if (sio.rdwr) { sio.parp++; return; } sio.parp = 1; const char* log_cmdname = ""; switch (value) { case 0x11: // RESET log_cmdname = "Reset1"; sio.bufcount = 8; memset8<0xff>(sio.buf); sio.buf[3] = sio.terminator; sio.buf[2] = '+'; sio.mcdst = 99; sio2.packet.recvVal3 = 0x8c; break; // FIXME : Why are there two identical cases for resetting the // memorycard(s)? there doesn't appear to be anything dealing with // card slots here. --air case 0x12: // RESET log_cmdname = "Reset2"; sio.bufcount = 8; memset8<0xff>(sio.buf); sio.buf[3] = sio.terminator; sio.buf[2] = '+'; sio.mcdst = 99; sio2.packet.recvVal3 = 0x8c; break; case 0x81: // COMMIT log_cmdname = "Commit"; sio.bufcount = 8; memset8<0xff>(sio.buf); sio.mcdst = 99; sio.buf[3] = sio.terminator; sio.buf[2] = '+'; sio2.packet.recvVal3 = 0x8c; if(value == 0x81) { if(sio.mc_command==0x42) sio2.packet.recvVal1 = 0x1600; // Writing else if(sio.mc_command==0x43) sio2.packet.recvVal1 = 0x1700; // Reading } break; case 0x21: case 0x22: case 0x23: // SECTOR SET log_cmdname = "SetSector"; sio.bufcount = 8; sio.mcdst = 99; sio.sector=0; sio.k=0; memset8<0xff>(sio.buf); sio2.packet.recvVal3 = 0x8c; sio.buf[8]=sio.terminator; sio.buf[7]='+'; break; case 0x24: break; case 0x25: break; case 0x26: { log_cmdname = "GetInfo"; const uint port = sio.GetMemcardIndex(); const uint slot = sio.activeMemcardSlot[port]; mc_command_0x26_tag cmd = mc_sizeinfo_8mb; PS2E_McdSizeInfo info; info.SectorSize = cmd.sectorSize; info.EraseBlockSizeInSectors = cmd.eraseBlocks; info.McdSizeInSectors = cmd.mcdSizeInSectors; SysPlugins.McdGetSizeInfo( port, slot, info ); pxAssumeDev( cmd.mcdSizeInSectors >= mc_sizeinfo_8mb.mcdSizeInSectors, "Mcd plugin returned an invalid memorycard size: Cards smaller than 8MB are not supported." ); cmd.sectorSize = info.SectorSize; cmd.eraseBlocks = info.EraseBlockSizeInSectors; cmd.mcdSizeInSectors = info.McdSizeInSectors; // Recalculate the xor summation // This uses a trick of removing the known xor values for a default 8mb memorycard (for which the XOR // was calculated), and replacing it with our new values. apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.sectorSize ); apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.eraseBlocks ); apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.mcdSizeInSectors ); apply_xor( cmd.mc_xor, cmd.sectorSize ); apply_xor( cmd.mc_xor, cmd.eraseBlocks ); apply_xor( cmd.mc_xor, cmd.mcdSizeInSectors ); sio.bufcount = 12; sio.mcdst = 99; sio2.packet.recvVal3 = 0x83; memset8<0xff>(sio.buf); memcpy_fast(&sio.buf[2], &cmd, sizeof(cmd)); sio.buf[12]=sio.terminator; } break; case 0x27: case 0x28: case 0xBF: log_cmdname = "NotSure"; // FIXME !! sio.bufcount = 4; sio.mcdst = 99; sio2.packet.recvVal3 = 0x8b; memset8<0xff>(sio.buf); sio.buf[4]=sio.terminator; sio.buf[3]='+'; break; // FIXME ? // sio.lastsector and sio.mode are unused. case 0x42: // WRITE log_cmdname = "Write"; //sio.mode = 0; goto __doReadWrite; case 0x43: // READ log_cmdname = "Read"; //sio.lastsector = sio.sector; // Reading goto __doReadWrite; case 0x82: log_cmdname = "Read(?)"; // FIXME !! //if(sio.lastsector==sio.sector) sio.mode = 2; __doReadWrite: sio.bufcount =133; sio.mcdst = 99; memset8<0xff>(sio.buf); sio.buf[133]=sio.terminator; sio.buf[132]='+'; break; case 0xf0: case 0xf1: case 0xf2: log_cmdname = "NoClue"; // FIXME !! sio.mcdst = 99; break; case 0xf3: case 0xf7: log_cmdname = "NoClueHereEither"; // FIXME !! sio.bufcount = 4; sio.mcdst = 99; memset8<0xff>(sio.buf); sio.buf[4]=sio.terminator; sio.buf[3]='+'; break; case 0x52: log_cmdname = "FixMe"; // FIXME !! sio.rdwr = 1; memset8<0xff>(sio.buf); sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; break; case 0x57: log_cmdname = "FixMe"; // FIXME !! sio.rdwr = 2; memset8<0xff>(sio.buf); sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; break; default: log_cmdname = "Unknown"; sio.mcdst = 0; memset8<0xff>(sio.buf); sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+'; } MEMCARDS_LOG("MC(%d) command 0x%02X [%s]", sio.GetMemcardIndex()+1, value, log_cmdname); sio.mc_command = value; } return; // END CASE 1. // FURTHER PROCESSING OF THE MEMORY CARD COMMANDS case 99: { sio.packetsize++; sio.parp++; switch(sio.mc_command) { // SET_ERASE_PAGE; the next erase commands will *clear* data starting with the page set here case 0x21: // SET_WRITE_PAGE; the next write commands will commit data starting with the page set here case 0x22: // SET_READ_PAGE; the next read commands will return data starting with the page set here case 0x23: if (sio.parp==2)sio.sector|=(value & 0xFF)<< 0; if (sio.parp==3)sio.sector|=(value & 0xFF)<< 8; if (sio.parp==4)sio.sector|=(value & 0xFF)<<16; if (sio.parp==5)sio.sector|=(value & 0xFF)<<24; if (sio.parp==6) { if (sio_xor((u8 *)&sio.sector, 4) == value) MEMCARDS_LOG("MC(%d) SET PAGE sio.sector, sector=0x%04X", sio.GetMemcardIndex()+1, sio.sector); else MEMCARDS_LOG("MC(%d) SET PAGE XOR value ERROR 0x%02X != ^0x%02X", sio.GetMemcardIndex()+1, value, sio_xor((u8 *)&sio.sector, 4)); } break; // SET_TERMINATOR; reads the new terminator code case 0x27: if(sio.parp==2) { sio.terminator = value; sio.buf[4] = value; MEMCARDS_LOG("MC(%d) SET TERMINATOR command, value=0x%02X", sio.GetMemcardIndex()+1, value); } break; // GET_TERMINATOR; puts in position 3 the current terminator code and in 4 the default one // depending on the param case 0x28: if(sio.parp == 2) { sio.buf[2] = '+'; sio.buf[3] = sio.terminator; //if(value == 0) sio.buf[4] = 0xFF; sio.buf[4] = 0x55; MEMCARDS_LOG("MC(%d) GET TERMINATOR command, value=0x%02X", sio.GetMemcardIndex()+1, value); } break; // WRITE DATA case 0x42: if (sio.parp==2) { sio.bufcount=5+value; memset8<0xff>(sio.buf); sio.buf[sio.bufcount-1]='+'; sio.buf[sio.bufcount]=sio.terminator; MEMCARDS_LOG("MC(%d) WRITE command, size=0x%02X", sio.GetMemcardIndex()+1, value); } else if ((sio.parp>2) && (sio.parp<sio.bufcount-2)) { sio.buf[sio.parp]=value; //MEMCARDS_LOG("MC(%d) WRITING 0x%02X", sio.GetMemcardIndex()+1, value); } else if (sio.parp==sio.bufcount-2) { if (sio_xor(&sio.buf[3], sio.bufcount-5)==value) { _SaveMcd(&sio.buf[3], (512+16)*sio.sector+sio.k, sio.bufcount-5); sio.buf[sio.bufcount-1]=value; sio.k+=sio.bufcount-5; } else { MEMCARDS_LOG("MC(%d) write XOR value error 0x%02X != ^0x%02X", sio.GetMemcardIndex()+1, value, sio_xor(&sio.buf[3], sio.bufcount-5)); } } break; // READ DATA case 0x43: if (sio.parp==2) { //int i; sio.bufcount=value+5; sio.buf[3]='+'; MEMCARDS_LOG("MC(%d) READ command, size=0x%02X", sio.GetMemcardIndex()+1, value); _ReadMcd(&sio.buf[4], (512+16)*sio.sector+sio.k, value); /*if(sio.mode==2) { int j; for(j=0; j < value; j++) sio.buf[4+j] = ~sio.buf[4+j]; }*/ sio.k+=value; sio.buf[sio.bufcount-1]=sio_xor(&sio.buf[4], value); sio.buf[sio.bufcount]=sio.terminator; } break; // INTERNAL ERASE case 0x82: if(sio.parp==2) { sio.buf[2]='+'; sio.buf[3]=sio.terminator; //if (sio.k != 0 || (sio.sector & 0xf) != 0) // Console.Warning("saving : odd position for erase."); _EraseMCDBlock((512+16)*(sio.sector&~0xf)); /* memset(sio.buf, -1, 256); _SaveMcd(sio.buf, (512+16)*sio.sector, 256); _SaveMcd(sio.buf, (512+16)*sio.sector+256, 256); _SaveMcd(sio.buf, (512+16)*sio.sector+512, 16); sio.buf[2]='+'; sio.buf[3]=sio.terminator;*/ //sio.buf[sio.bufcount] = sio.terminator; MEMCARDS_LOG("MC(%d) INTERNAL ERASE command 0x%02X", sio.GetMemcardIndex()+1, value); } break; // CARD AUTHENTICATION CHECKS case 0xF0: if (sio.parp==2) { MEMCARDS_LOG("MC(%d) CARD AUTH :0x%02X", sio.GetMemcardIndex()+1, value); switch(value){ case 1: case 2: case 4: case 15: case 17: case 19: sio.bufcount=13; memset8<0xff>(sio.buf); sio.buf[12] = 0; // Xor value of data from index 4 to 11 sio.buf[3]='+'; sio.buf[13] = sio.terminator; break; case 6: case 7: case 11: sio.bufcount=13; memset8<0xff>(sio.buf); sio.buf[12]='+'; sio.buf[13] = sio.terminator; break; default: sio.bufcount=4; memset8<0xff>(sio.buf); sio.buf[3]='+'; sio.buf[4] = sio.terminator; } } break; } if (sio.bufcount<=sio.parp) sio.mcdst = 0; } return; // END CASE 99. } switch (sio.mtapst) { case 0x1: sio.packetsize++; sio.parp = 1; SIO_INT(); switch(value) { case 0x12: // Query number of pads supported. sio.buf[3] = 4; sio.mtapst = 2; sio.bufcount = 5; break; case 0x13: // Query number of memcards supported. sio.buf[3] = 4; sio.mtapst = 2; sio.bufcount = 5; break; case 0x21: // Set pad slot. sio.mtapst = value; sio.bufcount = 6; // No idea why this is 6, saved from old code. break; case 0x22: // Set memcard slot. sio.mtapst = value; sio.bufcount = 6; // No idea why this is 6, saved from old code. break; } // Commented out values are from original code. They break multitap in bios. sio.buf[sio.bufcount-1]=0;//'+'; sio.buf[sio.bufcount]=0;//'Z'; return; case 0x2: sio.packetsize++; sio.parp++; if (sio.bufcount<=sio.parp) sio.mcdst = 0; SIO_INT(); return; case 0x21: // Set pad slot. sio.packetsize++; sio.parp++; sio.mtapst = 2; if (sio.CtrlReg & 2) { int port = sio.GetMultitapPort(); if (IsMtapPresent(port)) sio.activePadSlot[port] = value; } SIO_INT(); return; case 0x22: // Set memcard slot. sio.packetsize++; sio.parp++; sio.mtapst = 2; if (sio.CtrlReg & 2) { int port = sio.GetMultitapPort(); if (IsMtapPresent(port)) sio.activeMemcardSlot[port] = value; } SIO_INT(); return; } if(sio.count == 1 || way == 0) InitializeSIO(value); }
void sioWrite8(unsigned char value) { #ifdef PAD_LOG PAD_LOG("sio write8 %x (PAR:%x PAD:%x MCDL%x)\n", value, parp, padst, mcdst); #endif switch (padst) { case 1: SIO_INT(SIO_CYCLES); /* $41-4F $41 = Find bits in poll respones $42 = Polling command $43 = Config mode (Dual shock?) $44 = Digital / Analog (after $F3) $45 = Get status info (Dual shock?) ID: $41 = Digital $73 = Analogue Red LED $53 = Analogue Green LED $23 = NegCon $12 = Mouse */ if ((value & 0x40) == 0x40) { padst = 2; parp = 1; if (!Config.UseNet) { switch (CtrlReg & 0x2002) { case 0x0002: buf[parp] = PAD1_poll(value); break; case 0x2002: buf[parp] = PAD2_poll(value); break; } }/* else { // SysPrintf("%x: %x, %x, %x, %x\n", CtrlReg&0x2002, buf[2], buf[3], buf[4], buf[5]); }*/ if (!(buf[parp] & 0x0f)) { bufcount = 2 + 32; } else { bufcount = 2 + (buf[parp] & 0x0f) * 2; } // Digital / Dual Shock Controller if (buf[parp] == 0x41) { switch (value) { // enter config mode case 0x43: buf[1] = 0x43; break; // get status case 0x45: buf[1] = 0xf3; break; } } // NegCon - Wipeout 3 if( buf[parp] == 0x23 ) { switch (value) { // enter config mode case 0x43: buf[1] = 0x79; break; // get status case 0x45: buf[1] = 0xf3; break; } } } else padst = 0; return; case 2: parp++; /* if (buf[1] == 0x45) { buf[parp] = 0; SIO_INT(SIO_CYCLES); return; }*/ if (!Config.UseNet) { switch (CtrlReg & 0x2002) { case 0x0002: buf[parp] = PAD1_poll(value); break; case 0x2002: buf[parp] = PAD2_poll(value); break; } } if (parp == bufcount) { padst = 0; return; } SIO_INT(SIO_CYCLES); return; } switch (mcdst) { case 1: SIO_INT(SIO_CYCLES); if (rdwr) { parp++; return; } parp = 1; switch (value) { case 0x52: rdwr = 1; break; case 0x57: rdwr = 2; break; default: mcdst = 0; } return; case 2: // address H SIO_INT(SIO_CYCLES); adrH = value; *buf = 0; parp = 0; bufcount = 1; mcdst = 3; return; case 3: // address L SIO_INT(SIO_CYCLES); adrL = value; *buf = adrH; parp = 0; bufcount = 1; mcdst = 4; return; case 4: SIO_INT(SIO_CYCLES); parp = 0; switch (rdwr) { case 1: // read buf[0] = 0x5c; buf[1] = 0x5d; buf[2] = adrH; buf[3] = adrL; switch (CtrlReg & 0x2002) { case 0x0002: memcpy(&buf[4], Mcd1Data + (adrL | (adrH << 8)) * 128, 128); break; case 0x2002: memcpy(&buf[4], Mcd2Data + (adrL | (adrH << 8)) * 128, 128); break; } { char xorsum = 0; int i; for (i = 2; i < 128 + 4; i++) xorsum ^= buf[i]; buf[132] = xorsum; } buf[133] = 0x47; bufcount = 133; break; case 2: // write buf[0] = adrL; buf[1] = value; buf[129] = 0x5c; buf[130] = 0x5d; buf[131] = 0x47; bufcount = 131; cardh[1] &= ~MCDST_CHANGED; break; } mcdst = 5; return; case 5: parp++; if (rdwr == 2) { if (parp < 128) buf[parp + 1] = value; } SIO_INT(SIO_CYCLES); return; } /* GameShark CDX ae - be - ef - 04 + [00] ae - be - ef - 01 + 00 + [00] * $1000 ae - be - ef - 01 + 42 + [00] * $1000 ae - be - ef - 03 + 01,01,1f,e3,85,ae,d1,28 + [00] * 4 */ switch (gsdonglest) { // main command loop case 1: SIO_INT( SIO_CYCLES ); // GS CDX // - unknown output // reset device when fail? if( value == 0xae ) { StatReg |= RX_RDY; parp = 0; bufcount = parp; } // GS CDX else if( value == 0xbe ) { StatReg |= RX_RDY; parp = 0; bufcount = parp; buf[0] = reverse_8( 0xde ); } // GS CDX else if( value == 0xef ) { StatReg |= RX_RDY; parp = 0; bufcount = parp; buf[0] = reverse_8( 0xad ); } // GS CDX [1 in + $1000 out + $1 out] else if( value == 0x01 ) { StatReg |= RX_RDY; parp = 0; bufcount = parp; // $00 = 0000 0000 // - (reverse) 0000 0000 buf[0] = 0x00; gsdonglest = 2; } // GS CDX [1 in + $1000 in + $1 out] else if( value == 0x02 ) { StatReg |= RX_RDY; parp = 0; bufcount = parp; // $00 = 0000 0000 // - (reverse) 0000 0000 buf[0] = 0x00; gsdonglest = 3; } // GS CDX [8 in, 4 out] else if( value == 0x03 ) { StatReg |= RX_RDY; parp = 0; bufcount = parp; // $00 = 0000 0000 // - (reverse) 0000 0000 buf[0] = 0x00; gsdonglest = 4; } // GS CDX [out 1] else if( value == 0x04 ) { StatReg |= RX_RDY; parp = 0; bufcount = parp; // $00 = 0000 0000 // - (reverse) 0000 0000 buf[0] = 0x00; gsdonglest = 5; } else { // ERROR!! StatReg |= RX_RDY; parp = 0; bufcount = parp; buf[0] = 0xff; gsdonglest = 0; } return; // be - ef - 01 case 2: { unsigned char checksum; unsigned int lcv; SIO_INT( SIO_CYCLES ); StatReg |= RX_RDY; // read 1 byte DongleBank = buf[ 0 ]; // write data + checksum checksum = 0; for( lcv = 0; lcv < 0x1000; lcv++ ) { unsigned char data; data = DongleData[ DongleBank * 0x1000 + lcv ]; buf[ lcv+1 ] = reverse_8( data ); checksum += data; } parp = 0; bufcount = 0x1001; buf[ 0x1001 ] = reverse_8( checksum ); gsdonglest = 255; return; } // be - ef - 02 case 3: SIO_INT( SIO_CYCLES ); StatReg |= RX_RDY; // command start if( parp < 0x1000+1 ) { // read 1 byte buf[ parp ] = value; parp++; } if( parp == 0x1001 ) { unsigned char checksum; unsigned int lcv; DongleBank = buf[0]; memcpy( DongleData + DongleBank * 0x1000, buf+1, 0x1000 ); // save to file SaveDongle( "memcards/CDX_Dongle.bin" ); // write 8-bit checksum checksum = 0; for( lcv = 1; lcv < 0x1001; lcv++ ) { checksum += buf[ lcv ]; } parp = 0; bufcount = 1; buf[1] = reverse_8( checksum ); // flush result gsdonglest = 255; } return; // be - ef - 03 case 4: SIO_INT( SIO_CYCLES ); StatReg |= RX_RDY; // command start if( parp < 8 ) { // read 2 (?,?) + 4 (DATA?) + 2 (CRC?) buf[ parp ] = value; parp++; } if( parp == 8 ) { // now write 4 bytes via -FOUR- $00 writes parp = 8; bufcount = 12; // TODO: Solve CDX algorithm // GS CDX [magic key] if( buf[2] == 0x12 && buf[3] == 0x34 && buf[4] == 0x56 && buf[5] == 0x78 ) { buf[9] = reverse_8( 0x3e ); buf[10] = reverse_8( 0xa0 ); buf[11] = reverse_8( 0x40 ); buf[12] = reverse_8( 0x29 ); } // GS CDX [address key #2 = 6ec] else if( buf[2] == 0x1f && buf[3] == 0xe3 && buf[4] == 0x45 && buf[5] == 0x60 ) { buf[9] = reverse_8( 0xee ); buf[10] = reverse_8( 0xdd ); buf[11] = reverse_8( 0x71 ); buf[12] = reverse_8( 0xa8 ); } // GS CDX [address key #3 = ???] else if( buf[2] == 0x1f && buf[3] == 0xe3 && buf[4] == 0x72 && buf[5] == 0xe3 ) { // unsolved!! // Used here: 80090348 / 80090498 // dummy value - MSB buf[9] = reverse_8( 0xfa ); buf[10] = reverse_8( 0xde ); buf[11] = reverse_8( 0x21 ); buf[12] = reverse_8( 0x97 ); } // GS CDX [address key #4 = a00] else if( buf[2] == 0x1f && buf[3] == 0xe3 && buf[4] == 0x85 && buf[5] == 0xae ) { buf[9] = reverse_8( 0xee ); buf[10] = reverse_8( 0xdd ); buf[11] = reverse_8( 0x7d ); buf[12] = reverse_8( 0x44 ); } // GS CDX [address key #5 = 9ec] else if( buf[2] == 0x17 && buf[3] == 0xe3 && buf[4] == 0xb5 && buf[5] == 0x60 ) { buf[9] = reverse_8( 0xee ); buf[10] = reverse_8( 0xdd ); buf[11] = reverse_8( 0x7e ); buf[12] = reverse_8( 0xa8 ); } else { // dummy value - MSB buf[9] = reverse_8( 0xfa ); buf[10] = reverse_8( 0xde ); buf[11] = reverse_8( 0x21 ); buf[12] = reverse_8( 0x97 ); } // flush bytes -> done gsdonglest = 255; } return; // be - ef - 04 case 5: if( value == 0x00 ) { SIO_INT( SIO_CYCLES ); StatReg |= RX_RDY; // read 1 byte parp = 0; bufcount = parp; // size of dongle card? buf[ 0 ] = reverse_8( DONGLE_SIZE / 0x1000 ); // done already gsdonglest = 0; } return; // flush bytes -> done case 255: if( value == 0x00 ) { //SIO_INT( SIO_CYCLES ); SIO_INT(1); StatReg |= RX_RDY; parp++; if( parp == bufcount ) { gsdonglest = 0; #ifdef GSDONGLE_LOG PAD_LOG("(gameshark dongle) DONE!!\n" ); #endif } } else { // ERROR!! StatReg |= RX_RDY; parp = 0; bufcount = parp; buf[0] = 0xff; gsdonglest = 0; } return; } switch (value) { case 0x01: // start pad StatReg |= RX_RDY; // Transfer is Ready if (!Config.UseNet) { switch (CtrlReg & 0x2002) { case 0x0002: buf[0] = PAD1_startPoll(1); break; case 0x2002: buf[0] = PAD2_startPoll(2); break; } } else { if ((CtrlReg & 0x2002) == 0x0002) { int i, j; PAD1_startPoll(1); buf[0] = 0; buf[1] = PAD1_poll(0x42); if (!(buf[1] & 0x0f)) { bufcount = 32; } else { bufcount = (buf[1] & 0x0f) * 2; } buf[2] = PAD1_poll(0); i = 3; j = bufcount; while (j--) { buf[i++] = PAD1_poll(0); } bufcount+= 3; if (NET_sendPadData(buf, bufcount) == -1) netError(); if (NET_recvPadData(buf, 1) == -1) netError(); if (NET_recvPadData(buf + 128, 2) == -1) netError(); } else { memcpy(buf, buf + 128, 32); } } bufcount = 2; parp = 0; padst = 1; SIO_INT(SIO_CYCLES); return; case 0x81: // start memcard //case 0x82: case 0x83: case 0x84: // Multitap memcard access StatReg |= RX_RDY; // Chronicles of the Sword - no memcard = password options if( Config.NoMemcard || ((strlen(Config.Mcd1) <=0) && (strlen(Config.Mcd2) <=0)) ) { memset(buf, 0x00, 4); } else { memcpy(buf, cardh, 4); } parp = 0; bufcount = 3; mcdst = 1; rdwr = 0; SIO_INT(SIO_CYCLES); return; case 0xae: // GameShark CDX - start dongle StatReg |= RX_RDY; gsdonglest = 1; parp = 0; bufcount = parp; if( !DongleInit ) { LoadDongle( "memcards/CDX_Dongle.bin" ); DongleInit = 1; } SIO_INT( SIO_CYCLES ); return; default: // no hardware found StatReg |= RX_RDY; return; } }