diff --git a/Makefile b/Makefile index 93e05a3..a6c4655 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,7 @@ -all: libftfake.so dumpee +all: libftfake.so dumpee libsqfake.so + +libsqfake.so: libsqfake.c + $(CC) -shared -fPIC -Wall -Wextra -std=gnu11 -pipe -o $@ $< libftfake.so: libftfake.c gcc -shared -fPIC -o "$@" "$<" -I. -ldl -Wall diff --git a/libsqfake.c b/libsqfake.c new file mode 100644 index 0000000..9d7b8e0 --- /dev/null +++ b/libsqfake.c @@ -0,0 +1,479 @@ +#include +#include +#include +#include +#include + +typedef unsigned int FT_STATUS; +typedef void* FT_HANDLE; +typedef unsigned char* PUCHAR; +typedef unsigned int DWORD; +typedef unsigned short WORD; +typedef unsigned char UCHAR; +typedef void* PVOID; +typedef void* LPVOID; +typedef unsigned int* LPDWORD; +typedef unsigned short* LPWORD; +typedef unsigned int ULONG; + +typedef struct ft_program_data { + DWORD Signature1; // Header - must be 0x00000000 + DWORD Signature2; // Header - must be 0xffffffff + DWORD Version; // Header - FT_PROGRAM_DATA version + // 0 = original + // 1 = FT2232 extensions + // 2 = FT232R extensions + // 3 = FT2232H extensions + // 4 = FT4232H extensions + // 5 = FT232H extensions + + WORD VendorId; // 0x0403 + WORD ProductId; // 0x6001 + char *Manufacturer; // "FTDI" + char *ManufacturerId; // "FT" + char *Description; // "USB HS Serial Converter" + char *SerialNumber; // "FT000001" if fixed, or NULL + WORD MaxPower; // 0 < MaxPower <= 500 + WORD PnP; // 0 = disabled, 1 = enabled + WORD SelfPowered; // 0 = bus powered, 1 = self powered + WORD RemoteWakeup; // 0 = not capable, 1 = capable + // + // Rev4 (FT232B) extensions + // + UCHAR Rev4; // non-zero if Rev4 chip, zero otherwise + UCHAR IsoIn; // non-zero if in endpoint is isochronous + UCHAR IsoOut; // non-zero if out endpoint is isochronous + UCHAR PullDownEnable; // non-zero if pull down enabled + UCHAR SerNumEnable; // non-zero if serial number to be used + UCHAR USBVersionEnable; // non-zero if chip uses USBVersion + WORD USBVersion; // BCD (0x0200 => USB2) + // + // Rev 5 (FT2232) extensions + // + UCHAR Rev5; // non-zero if Rev5 chip, zero otherwise + UCHAR IsoInA; // non-zero if in endpoint is isochronous + UCHAR IsoInB; // non-zero if in endpoint is isochronous + UCHAR IsoOutA; // non-zero if out endpoint is isochronous + UCHAR IsoOutB; // non-zero if out endpoint is isochronous + UCHAR PullDownEnable5; // non-zero if pull down enabled + UCHAR SerNumEnable5; // non-zero if serial number to be used + UCHAR USBVersionEnable5; // non-zero if chip uses USBVersion + WORD USBVersion5; // BCD (0x0200 => USB2) + UCHAR AIsHighCurrent; // non-zero if interface is high current + UCHAR BIsHighCurrent; // non-zero if interface is high current + UCHAR IFAIsFifo; // non-zero if interface is 245 FIFO + UCHAR IFAIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR IFAIsFastSer; // non-zero if interface is Fast serial + UCHAR AIsVCP; // non-zero if interface is to use VCP drivers + UCHAR IFBIsFifo; // non-zero if interface is 245 FIFO + UCHAR IFBIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR IFBIsFastSer; // non-zero if interface is Fast serial + UCHAR BIsVCP; // non-zero if interface is to use VCP drivers + // + // Rev 6 (FT232R) extensions + // + UCHAR UseExtOsc; // Use External Oscillator + UCHAR HighDriveIOs; // High Drive I/Os + UCHAR EndpointSize; // Endpoint size + UCHAR PullDownEnableR; // non-zero if pull down enabled + UCHAR SerNumEnableR; // non-zero if serial number to be used + UCHAR InvertTXD; // non-zero if invert TXD + UCHAR InvertRXD; // non-zero if invert RXD + UCHAR InvertRTS; // non-zero if invert RTS + UCHAR InvertCTS; // non-zero if invert CTS + UCHAR InvertDTR; // non-zero if invert DTR + UCHAR InvertDSR; // non-zero if invert DSR + UCHAR InvertDCD; // non-zero if invert DCD + UCHAR InvertRI; // non-zero if invert RI + UCHAR Cbus0; // Cbus Mux control + UCHAR Cbus1; // Cbus Mux control + UCHAR Cbus2; // Cbus Mux control + UCHAR Cbus3; // Cbus Mux control + UCHAR Cbus4; // Cbus Mux control + UCHAR RIsD2XX; // non-zero if using D2XX driver + // + // Rev 7 (FT2232H) Extensions + // + UCHAR PullDownEnable7; // non-zero if pull down enabled + UCHAR SerNumEnable7; // non-zero if serial number to be used + UCHAR ALSlowSlew; // non-zero if AL pins have slow slew + UCHAR ALSchmittInput; // non-zero if AL pins are Schmitt input + UCHAR ALDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR AHSlowSlew; // non-zero if AH pins have slow slew + UCHAR AHSchmittInput; // non-zero if AH pins are Schmitt input + UCHAR AHDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BLSlowSlew; // non-zero if BL pins have slow slew + UCHAR BLSchmittInput; // non-zero if BL pins are Schmitt input + UCHAR BLDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BHSlowSlew; // non-zero if BH pins have slow slew + UCHAR BHSchmittInput; // non-zero if BH pins are Schmitt input + UCHAR BHDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR IFAIsFifo7; // non-zero if interface is 245 FIFO + UCHAR IFAIsFifoTar7; // non-zero if interface is 245 FIFO CPU target + UCHAR IFAIsFastSer7; // non-zero if interface is Fast serial + UCHAR AIsVCP7; // non-zero if interface is to use VCP drivers + UCHAR IFBIsFifo7; // non-zero if interface is 245 FIFO + UCHAR IFBIsFifoTar7; // non-zero if interface is 245 FIFO CPU target + UCHAR IFBIsFastSer7; // non-zero if interface is Fast serial + UCHAR BIsVCP7; // non-zero if interface is to use VCP drivers + UCHAR PowerSaveEnable; // non-zero if using BCBUS7 to save power for self-powered designs + // + // Rev 8 (FT4232H) Extensions + // + UCHAR PullDownEnable8; // non-zero if pull down enabled + UCHAR SerNumEnable8; // non-zero if serial number to be used + UCHAR ASlowSlew; // non-zero if A pins have slow slew + UCHAR ASchmittInput; // non-zero if A pins are Schmitt input + UCHAR ADriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR BSlowSlew; // non-zero if B pins have slow slew + UCHAR BSchmittInput; // non-zero if B pins are Schmitt input + UCHAR BDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR CSlowSlew; // non-zero if C pins have slow slew + UCHAR CSchmittInput; // non-zero if C pins are Schmitt input + UCHAR CDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR DSlowSlew; // non-zero if D pins have slow slew + UCHAR DSchmittInput; // non-zero if D pins are Schmitt input + UCHAR DDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR ARIIsTXDEN; // non-zero if port A uses RI as RS485 TXDEN + UCHAR BRIIsTXDEN; // non-zero if port B uses RI as RS485 TXDEN + UCHAR CRIIsTXDEN; // non-zero if port C uses RI as RS485 TXDEN + UCHAR DRIIsTXDEN; // non-zero if port D uses RI as RS485 TXDEN + UCHAR AIsVCP8; // non-zero if interface is to use VCP drivers + UCHAR BIsVCP8; // non-zero if interface is to use VCP drivers + UCHAR CIsVCP8; // non-zero if interface is to use VCP drivers + UCHAR DIsVCP8; // non-zero if interface is to use VCP drivers + // + // Rev 9 (FT232H) Extensions + // + UCHAR PullDownEnableH; // non-zero if pull down enabled + UCHAR SerNumEnableH; // non-zero if serial number to be used + UCHAR ACSlowSlewH; // non-zero if AC pins have slow slew + UCHAR ACSchmittInputH; // non-zero if AC pins are Schmitt input + UCHAR ACDriveCurrentH; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR ADSlowSlewH; // non-zero if AD pins have slow slew + UCHAR ADSchmittInputH; // non-zero if AD pins are Schmitt input + UCHAR ADDriveCurrentH; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR Cbus0H; // Cbus Mux control + UCHAR Cbus1H; // Cbus Mux control + UCHAR Cbus2H; // Cbus Mux control + UCHAR Cbus3H; // Cbus Mux control + UCHAR Cbus4H; // Cbus Mux control + UCHAR Cbus5H; // Cbus Mux control + UCHAR Cbus6H; // Cbus Mux control + UCHAR Cbus7H; // Cbus Mux control + UCHAR Cbus8H; // Cbus Mux control + UCHAR Cbus9H; // Cbus Mux control + UCHAR IsFifoH; // non-zero if interface is 245 FIFO + UCHAR IsFifoTarH; // non-zero if interface is 245 FIFO CPU target + UCHAR IsFastSerH; // non-zero if interface is Fast serial + UCHAR IsFT1248H; // non-zero if interface is FT1248 + UCHAR FT1248CpolH; // FT1248 clock polarity - clock idle high (1) or clock idle low (0) + UCHAR FT1248LsbH; // FT1248 data is LSB (1) or MSB (0) + UCHAR FT1248FlowControlH; // FT1248 flow control enable + UCHAR IsVCPH; // non-zero if interface is to use VCP drivers + UCHAR PowerSaveEnableH; // non-zero if using ACBUS7 to save power for self-powered designs +} FT_PROGRAM_DATA, *PFT_PROGRAM_DATA; + +enum { + FT_OK, + FT_INVALID_HANDLE, + FT_DEVICE_NOT_FOUND, + FT_DEVICE_NOT_OPENED, + FT_IO_ERROR, + FT_INSUFFICIENT_RESOURCES, + FT_INVALID_PARAMETER, + FT_INVALID_BAUD_RATE, + + FT_DEVICE_NOT_OPENED_FOR_ERASE, + FT_DEVICE_NOT_OPENED_FOR_WRITE, + FT_FAILED_TO_WRITE_DEVICE, + FT_EEPROM_READ_FAILED, + FT_EEPROM_WRITE_FAILED, + FT_EEPROM_ERASE_FAILED, + FT_EEPROM_NOT_PRESENT, + FT_EEPROM_NOT_PROGRAMMED, + FT_INVALID_ARGS, + FT_NOT_SUPPORTED, + FT_OTHER_ERROR, + FT_DEVICE_LIST_NOT_READY, +}; + + +#define ABORT(msg) \ + printf("ERR: unsupported function called!: %s\n", msg); \ + return FT_IO_ERROR; + +#define TRACE(func) \ + printf("TRACE: %s\n", func) + + +typedef struct { + size_t pos; + size_t len; + unsigned char data[16384]; +} sq_read_state; + +sq_read_state read_state = {0, 0, {0}}; + +void init_read_state(unsigned char* data, size_t len) { + memcpy(read_state.data, data, len); + read_state.pos = 0; + read_state.len = len; +} + +enum { + BOOT_INIT, + APP_INIT, + CAP_READY, + CAP_TRIGGERED, + CAP_READING +} sq_state = APP_INIT; + + +FT_STATUS FT_Close(FT_HANDLE ftHandle) { + /* TRACE("FT_Close"); */ + free(ftHandle); + return FT_OK; +} + +FT_STATUS FT_GetBitMode(FT_HANDLE ftHandle, PUCHAR pucMode) { + ABORT("FT_GetBitMode"); +} + +FT_STATUS FT_GetQueueStatus(FT_HANDLE ftHandle, DWORD* dwRxBytes) { + *dwRxBytes = read_state.len - read_state.pos; + return FT_OK; +} + + +#define FT_OPEN_BY_SERIAL_NUMBER 1 +#define FT_OPEN_BY_DESCRIPTION 2 +#define FT_OPEN_BY_LOCATION 4 +#define FT_LIST_NUMBER_ONLY 0x80000000 +#define FT_LIST_BY_INDEX 0x40000000 +#define FT_LIST_ALL 0x20000000 +FT_STATUS FT_ListDevices(PVOID pArg1, PVOID pArg2, DWORD flags) { + /* TRACE("FT_ListDevices"); */ + if (flags & FT_LIST_NUMBER_ONLY) { + *((unsigned int*) pArg1) = 1; + return FT_OK; + } else if (flags & FT_LIST_ALL) { + char** pa1 = (char**) pArg1; + if (flags & FT_OPEN_BY_SERIAL_NUMBER) { + pa1[0] = strdup("1003050005482"); + pa1[1] = NULL; + *((unsigned int*) pArg2) = 1; + return FT_OK; + } else if (flags & FT_OPEN_BY_DESCRIPTION) { + pa1[0] = strdup("ScanaQuad SQ50"); + pa1[1] = NULL; + *((unsigned int*) pArg2) = 1; + return FT_OK; + } + } + printf("unknown list device mode: %x\n", flags); + ABORT("FT_ListDevice list mode"); +} + +FT_STATUS FT_Open(int devno, FT_HANDLE* pHandle) { + /* TRACE("FT_Open"); */ + *pHandle = malloc(20); + return FT_OK; +} + +FT_STATUS FT_OpenEx(PVOID pArg1, DWORD flags, FT_HANDLE* pHandle) { + TRACE("FT_OpenEx"); + *pHandle = malloc(20); + return FT_OK; +} + +FT_STATUS FT_Read(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesReturned) { + TRACE("FT_Read"); + + size_t max_bytes = dwBytesToRead; + if (read_state.len - read_state.pos > max_bytes) { + max_bytes = read_state.len - read_state.pos; + } + printf("req size: %lu | state pos %lu state len %lu\n", max_bytes, + read_state.pos, read_state.len); + memcpy(lpBuffer, &read_state.data[read_state.pos], max_bytes); + read_state.pos += max_bytes; + *lpBytesReturned = max_bytes; + return FT_OK; +} + +FT_STATUS FT_SetBitMode(FT_HANDLE ftHandle, UCHAR ucMask, UCHAR ucEnable) { + ABORT("FT_SetBitMode"); +} + +FT_STATUS FT_SetLatencyTimer(FT_HANDLE ftHandle, UCHAR ucLatency) { + ABORT("FT_SetLatencyTimer"); +} + +FT_STATUS FT_SetTimeouts(FT_HANDLE ftHandle, ULONG rto, ULONG wto) { + /* TRACE("FT_SetTimeouts"); */ + /* printf("rto=%u, wto=%u\n", rto, wto); */ + return FT_OK; +} + +FT_STATUS FT_SetUSBParameters(FT_HANDLE ftHandle, ULONG inxfersz, ULONG outxfersz) { + /* TRACE("FT_SetUSBParameters"); */ + return FT_OK; +} + +FT_STATUS FT_SetVIDPID(DWORD dwVid, DWORD dwPid) { + /* TRACE("FT_SetVIDPID"); */ + return FT_OK; +} + +void dump(unsigned char* buffer, size_t len) { + for (size_t i = 0; i < len; i++) { + printf("%02x ", buffer[i]); + if (i % 32 == 31) { + printf("\n"); + } + } + printf("\n"); +} + +void print_bin(unsigned char b) { + for (int i = 7; i >= 0; i--) { + if ((b>>i)&0x1) { + printf("1"); + } else { + printf("0"); + } + } +} + +FT_STATUS FT_Write(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD len, LPDWORD written) { + TRACE("FT_Write"); + unsigned char* buffer = (unsigned char*) lpBuffer; + switch (buffer[0]) { + case 0x94: + TRACE("bootloader reset"); + sq_state = BOOT_INIT; + break; + case 0x93: + TRACE("app reset"); + sq_state = APP_INIT; + break; + case 0xf1: + if (sq_state == BOOT_INIT) { + printf("boot code: %02x %02x %02x\n", buffer[1], buffer[2], buffer[3]); + if (buffer[1] != 0x62 || buffer[2] != 0xa7 || buffer[3] != 0x7e) { + ABORT("wrong code!"); + } + } else { + printf("settings buffer:\n"); + dump(buffer, len); + } + break; + case 0xfd: + if (buffer[1] != 0x00 || buffer[2] != 0x01 || buffer[3] != 0x02 || buffer[4] != 0xfe) { + ABORT("wrong 0xfd command"); + } + if (sq_state == BOOT_INIT) { + printf("boot echo\n"); + init_read_state("\x01\x01\x01\x01", 4); + dump(read_state.data, read_state.len); + } else { + printf("app echo\n"); + init_read_state("\x22\x22\x22\x22", 4); + dump(read_state.data, read_state.len); + } + break; + case 0xf4: + TRACE("got trigger settings"); + dump(buffer, len); + for (size_t i = 1; i < len; i += 4) { + unsigned char cfg0 = buffer[i+0]; + unsigned char cfg1 = buffer[i+1]; + unsigned char cfg2 = buffer[i+2]; + unsigned char cfg3 = buffer[i+3]; + printf("SLOT: "); + print_bin(cfg0); + printf(" "); + print_bin(cfg1); + printf(" "); + print_bin(cfg2); + printf(" "); + print_bin(cfg3); + printf("\n"); + } + break; + case 0xf0: + switch (buffer[1]) { + case 0x00: + printf("state -> ready\n"); + sq_state = CAP_READY; + break; + case 0x01: + printf("wait for trigger command\n"); + init_read_state("\x11\x00\x00\xdd", 4); + break; + case 0x06: + printf("start read"); + read_state.len = 16384; + read_state.pos = 0; + for (size_t i = 0; i < 16384; i++) { + read_state.data[i] = (i & 0x1) ? 0xf0 : 0xa5; + } + printf("sending to app"); + break; + default: + printf("unknown capture cmd code\n"); + dump(buffer, len); + ABORT("FT_Write"); + } + break; + default: + printf("UNKNOWN write sequence!\n"); + dump(buffer, len); + ABORT("FT_Write"); + } + *written = len; + return FT_OK; +} + +unsigned char eeprom[] = {0x62, 0xa7, 0x7e, 0x03, 0x9f, 0xf5, 0xf6, 0x74, 0xf4, 0x01}; + +FT_STATUS FT_ReadEE(FT_HANDLE ftHandle, DWORD off, LPWORD val) { + TRACE("FT_ReadEE"); + if (off == 0x12) { + printf("0x12 -> 0xa762\n"); + *val = 0xa762; + return FT_OK; + } else if (off == 0x13) { + printf("0x13 -> 0x037e\n"); + *val = 0x037e; + return FT_OK; + } else if (off == 0x20) { + printf("0x20 -> 0x8888\n"); + *val = 0x8888; + return FT_OK; + } else { + printf("unknown ReadEE req: %x\n", off); + ABORT("FT_ReadEE"); + } +} + +FT_STATUS FT_WriteEE(FT_HANDLE ftHandle, DWORD off, WORD val) { + ABORT("FT_WriteEE"); +} + +FT_STATUS FT_EE_Program(FT_HANDLE ftHandle, PFT_PROGRAM_DATA pData) { + ABORT("FT_EE_Program"); +} + +FT_STATUS FT_EE_Read(FT_HANDLE ftHandle, PFT_PROGRAM_DATA pData) { + ABORT("FT_EE_Read"); +} + +FT_STATUS FT_EE_UARead(FT_HANDLE ftHandle, PUCHAR pucData, DWORD len, LPDWORD read) { + ABORT("FT_EE_UARead"); +} + +FT_STATUS FT_EE_UAWrite(FT_HANDLE ftHandle, PUCHAR pucData, DWORD len) { + ABORT("FT_EE_UAWrite"); +}