#include #include #include #include #include #include #include #include "config.h" #include "card_reader.h" #define BLOCKSIZE 8 uint8_t cardHeader[] = {0x08, 0x00, 0x00, 0x00, 0x81, 0x00, 0x59, 0xda, 0x00, 0x00, 0x54, 0x4d, 0x50, 0x06, 0x03, 0x23, 0x10, 0x41, 0x62, 0xad, 0x00, 0x2b, 0x0b, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x71, 0x52, 0x70, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xd2}; SerialFD serialFD[2]; WriteCommand writeCmd[2]; ReadCommand readCmd[2]; void initReadCmd(int fdIdx) { readCmd[fdIdx].cmd = 0; readCmd[fdIdx].cmdCompleted = false; readCmd[fdIdx].cmdLen = 0; readCmd[fdIdx].sentBytes = 0; memset(&readCmd[fdIdx].sendBuffer, '\0', 256); } void initWriteCmd(int fdIdx) { writeCmd[fdIdx].cmdCompleted = false; writeCmd[fdIdx].packetLen = 0; writeCmd[fdIdx].recBytes = 0; memset(&writeCmd[fdIdx].recBuffer, '\0', sizeof(uint8_t)); } int initCardReader() { initReadCmd(0); initReadCmd(1); initWriteCmd(0); initWriteCmd(1); uint32_t gId = getConfig()->crc32; if (gId != VIRTUA_TENNIS_3 && gId != VIRTUA_TENNIS_3_TEST && gId != VIRTUA_TENNIS_3_REVA && gId != VIRTUA_TENNIS_3_REVA_TEST && gId != VIRTUA_TENNIS_3_REVB && gId != VIRTUA_TENNIS_3_REVB_TEST && gId != VIRTUA_TENNIS_3_REVC && gId != VIRTUA_TENNIS_3_REVC_TEST && gId != R_TUNED) { printf("Game does not support Card Reader, please disable the card reader emulation in the config file.\n"); return -1; } if (getConfig()->emulateCardreader && getConfig()->emulateDriveboard && gId != R_TUNED) { printf("Game does not support Card Reader and Driver Board emulation enabled at the same time.\n"); printf("Please disable Drive Board emulations in the config file.\n"); return -1; } return 0; } int carReaderGetFdIdx(int fd) { if (fd == serialFD[0].fd) return 0; return 1; } uint8_t cardReaderGenChecksum(int fdIdx) { int checksum = 0; for (int i = 0; i < readCmd[fdIdx].cmdLen - 1; i++) { checksum ^= readCmd[fdIdx].sendBuffer[i]; } return checksum; } void buildOutputBuffer(int fdIdx, uint8_t cmd) { uint16_t packetLen = 0; readCmd[fdIdx].sendBuffer[0] = 0x10; readCmd[fdIdx].sendBuffer[1] = cmd; switch (cmd) { case 0x10: { readCmd[fdIdx].sendBuffer[5] = 0x20; } case 0x11: { if (writeCmd[fdIdx].recBuffer[5] == 0x04) { initWriteCmd(fdIdx); return; } } case 0x14: case 0x15: case 0x20: { if (cmd == 0x20 && writeCmd[fdIdx].recBuffer[5] == 0x00) readCmd[fdIdx].sendBuffer[4] = 0x80; } case 0x26: case 0x27: { packetLen = 0x02; readCmd[fdIdx].sendBuffer[3] = packetLen; } break; case 0x21: { packetLen = 0x0a; readCmd[fdIdx].sendBuffer[3] = packetLen; readCmd[fdIdx].sendBuffer[6] = 0x81; readCmd[fdIdx].sendBuffer[8] = 0x59; readCmd[fdIdx].sendBuffer[9] = 0xda; } break; case 0x22: { packetLen = 0x0a; readCmd[fdIdx].sendBuffer[3] = packetLen; readCmd[fdIdx].sendBuffer[7] = 0x08; } break; case 0x33: { packetLen = 0x0a; readCmd[fdIdx].sendBuffer[3] = packetLen; readCmd[fdIdx].sendBuffer[6] = 0xff; readCmd[fdIdx].sendBuffer[7] = 0xff; } break; case 0x34: { uint16_t blockStart = (writeCmd[fdIdx].recBuffer[6] << 8) | writeCmd[fdIdx].recBuffer[7]; uint16_t blocksToRead = (writeCmd[fdIdx].recBuffer[8] << 8) | writeCmd[fdIdx].recBuffer[9]; packetLen = (BLOCKSIZE * blocksToRead) + 2; readCmd[fdIdx].sendBuffer[3] = packetLen; FILE *crdFile = fopen(serialFD[fdIdx].cardFilename, "rb"); fseek(crdFile, BLOCKSIZE * blockStart, SEEK_SET); fread(readCmd[fdIdx].sendBuffer + 6, 1, packetLen - 2, crdFile); fclose(crdFile); } break; case 0x35: { readCmd[fdIdx].sendBuffer[3] = 0x02; uint16_t blockStart = (writeCmd[fdIdx].recBuffer[6] << 8) | writeCmd[fdIdx].recBuffer[7]; uint16_t blocksToWrite = (writeCmd[fdIdx].recBuffer[8] << 8) | writeCmd[fdIdx].recBuffer[9]; packetLen = BLOCKSIZE * blocksToWrite; FILE *crdFile = fopen(serialFD[fdIdx].cardFilename, "rb+"); fseek(crdFile, BLOCKSIZE * blockStart, SEEK_SET); fwrite(writeCmd[fdIdx].recBuffer + 10, 1, packetLen, crdFile); fclose(crdFile); packetLen = 0x02; } break; default: { printf("Command not supported.\n"); } } readCmd[fdIdx].cmdLen = packetLen + 5; readCmd[fdIdx].sendBuffer[readCmd[fdIdx].cmdLen - 1] = cardReaderGenChecksum(fdIdx); } size_t cardReaderWrite(int fd, const void *buf, size_t count) { int fdIdx = carReaderGetFdIdx(fd); if (writeCmd[fdIdx].cmdCompleted) { printf("Something went wrong, a write command was issued after the command was completed.\n"); } if (writeCmd[fdIdx].recBytes == 4) { writeCmd[fdIdx].packetLen = (writeCmd[fdIdx].recBuffer[2] << 8) | writeCmd[fdIdx].recBuffer[3]; } writeCmd[fdIdx].recBuffer[writeCmd[fdIdx].recBytes] = *((u_int8_t *)buf); writeCmd[fdIdx].recBytes++; if (writeCmd[fdIdx].recBytes == writeCmd[fdIdx].packetLen + 5) { writeCmd[fdIdx].cmdCompleted = true; initReadCmd(fdIdx); buildOutputBuffer(fdIdx, writeCmd[fdIdx].recBuffer[1]); } return count; } size_t cardReaderRead(int fd, void *buf, size_t count) { int fdIdx = carReaderGetFdIdx(fd); if (!writeCmd[fdIdx].cmdCompleted || readCmd[fdIdx].cmdCompleted) return -1; if (readCmd[fdIdx].cmdLen == readCmd[fdIdx].sentBytes) { readCmd[fdIdx].cmdCompleted = true; initWriteCmd(fdIdx); return -1; } memcpy(buf, &readCmd[fdIdx].sendBuffer[readCmd[fdIdx].sentBytes], sizeof(uint8_t)); readCmd[fdIdx].sentBytes++; return 1; } void cardReaderSetFd(int serial, int fd, char *fName) { serialFD[serial].fd = fd; serialFD[serial].cardFilename = fName; if (access(fName, F_OK) != 0) { FILE *crdFile = fopen(fName, "wb+"); if (getConfig()->crc32 == R_TUNED) { cardHeader[0x22] = 0x02; cardHeader[0x23] = 0x60; } fwrite(cardHeader, 1, 56, crdFile); uint8_t z = 0; fseek(crdFile, 0x7c7, SEEK_CUR); fwrite(&z, 1, 1, crdFile); fclose(crdFile); printf("Cardfile %s created.\n", fName); } }