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(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; } }