diff --git a/.gitignore b/.gitignore index 6d918f422f3..f84d7ae9a1e 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ blackmagic_upgrade .gdb_history src/artifacts/ +src/ftd2xx.dll diff --git a/3rdparty/ftdi/amd64/ftd2xx.dll b/3rdparty/ftdi/amd64/ftd2xx.dll new file mode 100644 index 00000000000..bd6246a50c0 Binary files /dev/null and b/3rdparty/ftdi/amd64/ftd2xx.dll differ diff --git a/3rdparty/ftdi/amd64/ftd2xx.lib b/3rdparty/ftdi/amd64/ftd2xx.lib new file mode 100644 index 00000000000..7b28fab0dbe Binary files /dev/null and b/3rdparty/ftdi/amd64/ftd2xx.lib differ diff --git a/3rdparty/ftdi/ftd2xx.h b/3rdparty/ftdi/ftd2xx.h new file mode 100644 index 00000000000..e7a0b652beb --- /dev/null +++ b/3rdparty/ftdi/ftd2xx.h @@ -0,0 +1,1295 @@ +/*++ + +Copyright © 2001-2021 Future Technology Devices International Limited + +THIS SOFTWARE IS PROVIDED BY FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +FUTURE TECHNOLOGY DEVICES INTERNATIONAL LIMITED BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES LOSS OF USE, DATA, OR PROFITS OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +FTDI DRIVERS MAY BE USED ONLY IN CONJUNCTION WITH PRODUCTS BASED ON FTDI PARTS. + +FTDI DRIVERS MAY BE DISTRIBUTED IN ANY FORM AS LONG AS LICENSE INFORMATION IS NOT MODIFIED. + +IF A CUSTOM VENDOR ID AND/OR PRODUCT ID OR DESCRIPTION STRING ARE USED, IT IS THE +RESPONSIBILITY OF THE PRODUCT MANUFACTURER TO MAINTAIN ANY CHANGES AND SUBSEQUENT WHQL +RE-CERTIFICATION AS A RESULT OF MAKING THESE CHANGES. + + +Module Name: + +ftd2xx.h + +Abstract: + +Native USB device driver for FTDI FT232x, FT245x, FT2232x, FT4232x, FT2233H and FT4233H devices +FTD2XX library definitions + +Environment: + +kernel & user mode + + +--*/ + +#ifndef FTD2XX_H +#define FTD2XX_H + +#ifdef _WIN32 +// Compiling on Windows +#include + +// The following ifdef block is the standard way of creating macros +// which make exporting from a DLL simpler. All files within this DLL +// are compiled with the FTD2XX_EXPORTS symbol defined on the command line. +// This symbol should not be defined on any project that uses this DLL. +// This way any other project whose source files include this file see +// FTD2XX_API functions as being imported from a DLL, whereas this DLL +// sees symbols defined with this macro as being exported. + +#ifdef FTD2XX_EXPORTS +#define FTD2XX_API __declspec(dllexport) +#elif defined(FTD2XX_STATIC) +// Avoid decorations when linking statically to D2XX. +#define FTD2XX_API +// Static D2XX depends on these Windows libs: +#pragma comment(lib, "setupapi.lib") +#pragma comment(lib, "advapi32.lib") +#pragma comment(lib, "user32.lib") +#else +#define FTD2XX_API __declspec(dllimport) +#endif + +#else // _WIN32 +// Compiling on non-Windows platform. +#include "WinTypes.h" +// No decorations needed. +#define FTD2XX_API + +#endif // _WIN32 + +typedef PVOID FT_HANDLE; +typedef ULONG FT_STATUS; + +// +// Device status +// +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 FT_SUCCESS(status) ((status) == FT_OK) + +// +// FT_OpenEx Flags +// + +#define FT_OPEN_BY_SERIAL_NUMBER 1 +#define FT_OPEN_BY_DESCRIPTION 2 +#define FT_OPEN_BY_LOCATION 4 + +#define FT_OPEN_MASK (FT_OPEN_BY_SERIAL_NUMBER | FT_OPEN_BY_DESCRIPTION | FT_OPEN_BY_LOCATION) + +// +// FT_ListDevices Flags (used in conjunction with FT_OpenEx Flags +// + +#define FT_LIST_NUMBER_ONLY 0x80000000 +#define FT_LIST_BY_INDEX 0x40000000 +#define FT_LIST_ALL 0x20000000 + +#define FT_LIST_MASK (FT_LIST_NUMBER_ONLY | FT_LIST_BY_INDEX | FT_LIST_ALL) + +// +// Baud Rates +// + +#define FT_BAUD_300 300 +#define FT_BAUD_600 600 +#define FT_BAUD_1200 1200 +#define FT_BAUD_2400 2400 +#define FT_BAUD_4800 4800 +#define FT_BAUD_9600 9600 +#define FT_BAUD_14400 14400 +#define FT_BAUD_19200 19200 +#define FT_BAUD_38400 38400 +#define FT_BAUD_57600 57600 +#define FT_BAUD_115200 115200 +#define FT_BAUD_230400 230400 +#define FT_BAUD_460800 460800 +#define FT_BAUD_921600 921600 + +// +// Word Lengths +// + +#define FT_BITS_8 (UCHAR)8 +#define FT_BITS_7 (UCHAR)7 + +// +// Stop Bits +// + +#define FT_STOP_BITS_1 (UCHAR)0 +#define FT_STOP_BITS_2 (UCHAR)2 + +// +// Parity +// + +#define FT_PARITY_NONE (UCHAR)0 +#define FT_PARITY_ODD (UCHAR)1 +#define FT_PARITY_EVEN (UCHAR)2 +#define FT_PARITY_MARK (UCHAR)3 +#define FT_PARITY_SPACE (UCHAR)4 + +// +// Flow Control +// + +#define FT_FLOW_NONE 0x0000 +#define FT_FLOW_RTS_CTS 0x0100 +#define FT_FLOW_DTR_DSR 0x0200 +#define FT_FLOW_XON_XOFF 0x0400 + +// +// Purge rx and tx buffers +// +#define FT_PURGE_RX 1 +#define FT_PURGE_TX 2 + +// +// Events +// + +typedef void (*PFT_EVENT_HANDLER)(DWORD, DWORD); + +#define FT_EVENT_RXCHAR 1 +#define FT_EVENT_MODEM_STATUS 2 +#define FT_EVENT_LINE_STATUS 4 + +// +// Timeouts +// + +#define FT_DEFAULT_RX_TIMEOUT 300 +#define FT_DEFAULT_TX_TIMEOUT 300 + +// +// Device types +// + +typedef ULONG FT_DEVICE; + +enum { + FT_DEVICE_BM, + FT_DEVICE_AM, + FT_DEVICE_100AX, + FT_DEVICE_UNKNOWN, + FT_DEVICE_2232C, + FT_DEVICE_232R, + FT_DEVICE_2232H, + FT_DEVICE_4232H, + FT_DEVICE_232H, + FT_DEVICE_X_SERIES, + FT_DEVICE_4222H_0, + FT_DEVICE_4222H_1_2, + FT_DEVICE_4222H_3, + FT_DEVICE_4222_PROG, + FT_DEVICE_900, + FT_DEVICE_930, + FT_DEVICE_UMFTPD3A, + FT_DEVICE_2233HP, + FT_DEVICE_4233HP, + FT_DEVICE_2232HP, + FT_DEVICE_4232HP, + FT_DEVICE_233HP, + FT_DEVICE_232HP, + FT_DEVICE_2232HA, + FT_DEVICE_4232HA, + FT_DEVICE_232RN, +}; + +// +// Bit Modes +// + +#define FT_BITMODE_RESET 0x00 +#define FT_BITMODE_ASYNC_BITBANG 0x01 +#define FT_BITMODE_MPSSE 0x02 +#define FT_BITMODE_SYNC_BITBANG 0x04 +#define FT_BITMODE_MCU_HOST 0x08 +#define FT_BITMODE_FAST_SERIAL 0x10 +#define FT_BITMODE_CBUS_BITBANG 0x20 +#define FT_BITMODE_SYNC_FIFO 0x40 + +// +// FT232R CBUS Options EEPROM values +// + +#define FT_232R_CBUS_TXDEN 0x00 // Tx Data Enable +#define FT_232R_CBUS_PWRON 0x01 // Power On +#define FT_232R_CBUS_RXLED 0x02 // Rx LED +#define FT_232R_CBUS_TXLED 0x03 // Tx LED +#define FT_232R_CBUS_TXRXLED 0x04 // Tx and Rx LED +#define FT_232R_CBUS_SLEEP 0x05 // Sleep +#define FT_232R_CBUS_CLK48 0x06 // 48MHz clock +#define FT_232R_CBUS_CLK24 0x07 // 24MHz clock +#define FT_232R_CBUS_CLK12 0x08 // 12MHz clock +#define FT_232R_CBUS_CLK6 0x09 // 6MHz clock +#define FT_232R_CBUS_IOMODE 0x0a // IO Mode for CBUS bit-bang +#define FT_232R_CBUS_BITBANG_WR 0x0b // Bit-bang write strobe +#define FT_232R_CBUS_BITBANG_RD 0x0c // Bit-bang read strobe + +// +// FT232H CBUS Options EEPROM values +// + +#define FT_232H_CBUS_TRISTATE 0x00 // Tristate +#define FT_232H_CBUS_TXLED 0x01 // Tx LED +#define FT_232H_CBUS_RXLED 0x02 // Rx LED +#define FT_232H_CBUS_TXRXLED 0x03 // Tx and Rx LED +#define FT_232H_CBUS_PWREN 0x04 // Power Enable +#define FT_232H_CBUS_SLEEP 0x05 // Sleep +#define FT_232H_CBUS_DRIVE_0 0x06 // Drive pin to logic 0 +#define FT_232H_CBUS_DRIVE_1 0x07 // Drive pin to logic 1 +#define FT_232H_CBUS_IOMODE 0x08 // IO Mode for CBUS bit-bang +#define FT_232H_CBUS_TXDEN 0x09 // Tx Data Enable +#define FT_232H_CBUS_CLK30 0x0a // 30MHz clock +#define FT_232H_CBUS_CLK15 0x0b // 15MHz clock +#define FT_232H_CBUS_CLK7_5 0x0c // 7.5MHz clock + +// +// FT X Series CBUS Options EEPROM values +// + +#define FT_X_SERIES_CBUS_TRISTATE 0x00 // Tristate +#define FT_X_SERIES_CBUS_TXLED 0x01 // Tx LED +#define FT_X_SERIES_CBUS_RXLED 0x02 // Rx LED +#define FT_X_SERIES_CBUS_TXRXLED 0x03 // Tx and Rx LED +#define FT_X_SERIES_CBUS_PWREN 0x04 // Power Enable +#define FT_X_SERIES_CBUS_SLEEP 0x05 // Sleep +#define FT_X_SERIES_CBUS_DRIVE_0 0x06 // Drive pin to logic 0 +#define FT_X_SERIES_CBUS_DRIVE_1 0x07 // Drive pin to logic 1 +#define FT_X_SERIES_CBUS_IOMODE 0x08 // IO Mode for CBUS bit-bang +#define FT_X_SERIES_CBUS_TXDEN 0x09 // Tx Data Enable +#define FT_X_SERIES_CBUS_CLK24 0x0a // 24MHz clock +#define FT_X_SERIES_CBUS_CLK12 0x0b // 12MHz clock +#define FT_X_SERIES_CBUS_CLK6 0x0c // 6MHz clock +#define FT_X_SERIES_CBUS_BCD_CHARGER 0x0d // Battery charger detected +#define FT_X_SERIES_CBUS_BCD_CHARGER_N 0x0e // Battery charger detected inverted +#define FT_X_SERIES_CBUS_I2C_TXE 0x0f // I2C Tx empty +#define FT_X_SERIES_CBUS_I2C_RXF 0x10 // I2C Rx full +#define FT_X_SERIES_CBUS_VBUS_SENSE 0x11 // Detect VBUS +#define FT_X_SERIES_CBUS_BITBANG_WR 0x12 // Bit-bang write strobe +#define FT_X_SERIES_CBUS_BITBANG_RD 0x13 // Bit-bang read strobe +#define FT_X_SERIES_CBUS_TIMESTAMP 0x14 // Toggle output when a USB SOF token is received +#define FT_X_SERIES_CBUS_KEEP_AWAKE 0x15 // + +// Driver types +#define FT_DRIVER_TYPE_D2XX 0 +#define FT_DRIVER_TYPE_VCP 1 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef FTD2XX_STATIC +FTD2XX_API +FT_STATUS WINAPI FT_Initialise(void); + +FTD2XX_API +void WINAPI FT_Finalise(void); +#endif // FTD2XX_STATIC + +FTD2XX_API +FT_STATUS WINAPI FT_Open(int deviceNumber, FT_HANDLE *pHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_OpenEx(PVOID pArg1, DWORD Flags, FT_HANDLE *pHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_ListDevices(PVOID pArg1, PVOID pArg2, DWORD Flags); + +FTD2XX_API +FT_STATUS WINAPI FT_Close(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_Read(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesReturned); + +FTD2XX_API +FT_STATUS WINAPI FT_Write(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten); + +FTD2XX_API +FT_STATUS WINAPI FT_IoCtl(FT_HANDLE ftHandle, DWORD dwIoControlCode, LPVOID lpInBuf, DWORD nInBufSize, LPVOID lpOutBuf, + DWORD nOutBufSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); + +FTD2XX_API +FT_STATUS WINAPI FT_SetBaudRate(FT_HANDLE ftHandle, ULONG BaudRate); + +FTD2XX_API +FT_STATUS WINAPI FT_SetDivisor(FT_HANDLE ftHandle, USHORT Divisor); + +FTD2XX_API +FT_STATUS WINAPI FT_SetDataCharacteristics(FT_HANDLE ftHandle, UCHAR WordLength, UCHAR StopBits, UCHAR Parity); + +FTD2XX_API +FT_STATUS WINAPI FT_SetFlowControl(FT_HANDLE ftHandle, USHORT FlowControl, UCHAR XonChar, UCHAR XoffChar); + +FTD2XX_API +FT_STATUS WINAPI FT_ResetDevice(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_SetDtr(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_ClrDtr(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_SetRts(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_ClrRts(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_GetModemStatus(FT_HANDLE ftHandle, ULONG *pModemStatus); + +FTD2XX_API +FT_STATUS WINAPI FT_SetChars( + FT_HANDLE ftHandle, UCHAR EventChar, UCHAR EventCharEnabled, UCHAR ErrorChar, UCHAR ErrorCharEnabled); + +FTD2XX_API +FT_STATUS WINAPI FT_Purge(FT_HANDLE ftHandle, ULONG Mask); + +FTD2XX_API +FT_STATUS WINAPI FT_SetTimeouts(FT_HANDLE ftHandle, ULONG ReadTimeout, ULONG WriteTimeout); + +FTD2XX_API +FT_STATUS WINAPI FT_GetQueueStatus(FT_HANDLE ftHandle, DWORD *dwRxBytes); + +FTD2XX_API +FT_STATUS WINAPI FT_SetEventNotification(FT_HANDLE ftHandle, DWORD Mask, PVOID Param); + +FTD2XX_API +FT_STATUS WINAPI FT_GetStatus(FT_HANDLE ftHandle, DWORD *dwRxBytes, DWORD *dwTxBytes, DWORD *dwEventDWord); + +FTD2XX_API +FT_STATUS WINAPI FT_SetBreakOn(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_SetBreakOff(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_SetWaitMask(FT_HANDLE ftHandle, DWORD Mask); + +FTD2XX_API +FT_STATUS WINAPI FT_WaitOnMask(FT_HANDLE ftHandle, DWORD *Mask); + +FTD2XX_API +FT_STATUS WINAPI FT_GetEventStatus(FT_HANDLE ftHandle, DWORD *dwEventDWord); + +FTD2XX_API +FT_STATUS WINAPI FT_ReadEE(FT_HANDLE ftHandle, DWORD dwWordOffset, LPWORD lpwValue); + +FTD2XX_API +FT_STATUS WINAPI FT_WriteEE(FT_HANDLE ftHandle, DWORD dwWordOffset, WORD wValue); + +FTD2XX_API +FT_STATUS WINAPI FT_EraseEE(FT_HANDLE ftHandle); + +// +// structure to hold program data for FT_EE_Program, FT_EE_ProgramEx, FT_EE_Read +// and FT_EE_ReadEx functions +// +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; + +FTD2XX_API +FT_STATUS WINAPI FT_EE_Program(FT_HANDLE ftHandle, PFT_PROGRAM_DATA pData); + +FTD2XX_API +FT_STATUS WINAPI FT_EE_ProgramEx(FT_HANDLE ftHandle, PFT_PROGRAM_DATA pData, char *Manufacturer, char *ManufacturerId, + char *Description, char *SerialNumber); + +FTD2XX_API +FT_STATUS WINAPI FT_EE_Read(FT_HANDLE ftHandle, PFT_PROGRAM_DATA pData); + +FTD2XX_API +FT_STATUS WINAPI FT_EE_ReadEx(FT_HANDLE ftHandle, PFT_PROGRAM_DATA pData, char *Manufacturer, char *ManufacturerId, + char *Description, char *SerialNumber); + +FTD2XX_API +FT_STATUS WINAPI FT_EE_UASize(FT_HANDLE ftHandle, LPDWORD lpdwSize); + +FTD2XX_API +FT_STATUS WINAPI FT_EE_UAWrite(FT_HANDLE ftHandle, PUCHAR pucData, DWORD dwDataLen); + +FTD2XX_API +FT_STATUS WINAPI FT_EE_UARead(FT_HANDLE ftHandle, PUCHAR pucData, DWORD dwDataLen, LPDWORD lpdwBytesRead); + +typedef struct ft_eeprom_header { + FT_DEVICE deviceType; // FTxxxx device type to be programmed + // Device descriptor options + WORD VendorId; // 0x0403 + WORD ProductId; // 0x6001 + UCHAR SerNumEnable; // non-zero if serial number to be used + // Config descriptor options + WORD MaxPower; // 0 < MaxPower <= 500 + UCHAR SelfPowered; // 0 = bus powered, 1 = self powered + UCHAR RemoteWakeup; // 0 = not capable, 1 = capable + // Hardware options + UCHAR PullDownEnable; // non-zero if pull down in suspend enabled +} FT_EEPROM_HEADER, *PFT_EEPROM_HEADER; + +// FT232B EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +typedef struct ft_eeprom_232b { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs +} FT_EEPROM_232B, *PFT_EEPROM_232B; + +// FT2232 EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +typedef struct ft_eeprom_2232 { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + UCHAR AIsHighCurrent; // non-zero if interface is high current + UCHAR BIsHighCurrent; // non-zero if interface is high current + // Hardware options + UCHAR AIsFifo; // non-zero if interface is 245 FIFO + UCHAR AIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR AIsFastSer; // non-zero if interface is Fast serial + UCHAR BIsFifo; // non-zero if interface is 245 FIFO + UCHAR BIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR BIsFastSer; // non-zero if interface is Fast serial + // Driver option + UCHAR ADriverType; // non-zero if interface is to use VCP drivers + UCHAR BDriverType; // non-zero if interface is to use VCP drivers +} FT_EEPROM_2232, *PFT_EEPROM_2232; + +// FT232R EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +typedef struct ft_eeprom_232r { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + UCHAR IsHighCurrent; // non-zero if interface is high current + // Hardware options + UCHAR UseExtOsc; // Use External Oscillator + 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 + // Driver option + UCHAR DriverType; // non-zero if using D2XX driver +} FT_EEPROM_232R, *PFT_EEPROM_232R; + +// FT2232H EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +typedef struct ft_eeprom_2232h { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + 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 + // Hardware options + UCHAR AIsFifo; // non-zero if interface is 245 FIFO + UCHAR AIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR AIsFastSer; // non-zero if interface is Fast serial + UCHAR BIsFifo; // non-zero if interface is 245 FIFO + UCHAR BIsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR BIsFastSer; // non-zero if interface is Fast serial + UCHAR PowerSaveEnable; // non-zero if using BCBUS7 to save power for self-powered designs + // Driver option + UCHAR ADriverType; // non-zero if interface is to use VCP drivers + UCHAR BDriverType; // non-zero if interface is to use VCP drivers +} FT_EEPROM_2232H, *PFT_EEPROM_2232H; + +// FT4232H EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +typedef struct ft_eeprom_4232h { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + 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 + // Hardware options + 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 + // Driver option + UCHAR ADriverType; // non-zero if interface is to use VCP drivers + UCHAR BDriverType; // non-zero if interface is to use VCP drivers + UCHAR CDriverType; // non-zero if interface is to use VCP drivers + UCHAR DDriverType; // non-zero if interface is to use VCP drivers +} FT_EEPROM_4232H, *PFT_EEPROM_4232H; + +// FT232H EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +typedef struct ft_eeprom_232h { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + UCHAR ACSlowSlew; // non-zero if AC bus pins have slow slew + UCHAR ACSchmittInput; // non-zero if AC bus pins are Schmitt input + UCHAR ACDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR ADSlowSlew; // non-zero if AD bus pins have slow slew + UCHAR ADSchmittInput; // non-zero if AD bus pins are Schmitt input + UCHAR ADDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + // CBUS options + 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 Cbus5; // Cbus Mux control + UCHAR Cbus6; // Cbus Mux control + UCHAR Cbus7; // Cbus Mux control + UCHAR Cbus8; // Cbus Mux control + UCHAR Cbus9; // Cbus Mux control + // FT1248 options + UCHAR FT1248Cpol; // FT1248 clock polarity - clock idle high (1) or clock idle low (0) + UCHAR FT1248Lsb; // FT1248 data is LSB (1) or MSB (0) + UCHAR FT1248FlowControl; // FT1248 flow control enable + // Hardware options + UCHAR IsFifo; // non-zero if interface is 245 FIFO + UCHAR IsFifoTar; // non-zero if interface is 245 FIFO CPU target + UCHAR IsFastSer; // non-zero if interface is Fast serial + UCHAR IsFT1248; // non-zero if interface is FT1248 + UCHAR PowerSaveEnable; // + // Driver option + UCHAR DriverType; // non-zero if interface is to use VCP drivers +} FT_EEPROM_232H, *PFT_EEPROM_232H; + +// FT X Series EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +typedef struct ft_eeprom_x_series { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + // Drive options + UCHAR ACSlowSlew; // non-zero if AC bus pins have slow slew + UCHAR ACSchmittInput; // non-zero if AC bus pins are Schmitt input + UCHAR ACDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR ADSlowSlew; // non-zero if AD bus pins have slow slew + UCHAR ADSchmittInput; // non-zero if AD bus pins are Schmitt input + UCHAR ADDriveCurrent; // valid values are 4mA, 8mA, 12mA, 16mA + // CBUS options + 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 Cbus5; // Cbus Mux control + UCHAR Cbus6; // Cbus Mux control + // UART signal options + 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 + // Battery Charge Detect options + UCHAR BCDEnable; // Enable Battery Charger Detection + UCHAR BCDForceCbusPWREN; // asserts the power enable signal on CBUS when charging port detected + UCHAR BCDDisableSleep; // forces the device never to go into sleep mode + // I2C options + WORD I2CSlaveAddress; // I2C slave device address + DWORD I2CDeviceId; // I2C device ID + UCHAR I2CDisableSchmitt; // Disable I2C Schmitt trigger + // FT1248 options + UCHAR FT1248Cpol; // FT1248 clock polarity - clock idle high (1) or clock idle low (0) + UCHAR FT1248Lsb; // FT1248 data is LSB (1) or MSB (0) + UCHAR FT1248FlowControl; // FT1248 flow control enable + // Hardware options + UCHAR RS485EchoSuppress; // + UCHAR PowerSaveEnable; // + // Driver option + UCHAR DriverType; // non-zero if interface is to use VCP drivers +} FT_EEPROM_X_SERIES, *PFT_EEPROM_X_SERIES; + +// FT4222H EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +typedef struct ft_eeprom_4222h { + // Common header + FT_EEPROM_HEADER common; // common elements for all device EEPROMs + CHAR Revision; // 'A', 'B', 'C', or 'D'. + UCHAR I2C_Slave_Address; + // Suspend + UCHAR SPISuspend; // 0 for "Disable SPI, tristate pins", 2 for "Keep SPI pin status", 3 for "Enable SPI pin control" + UCHAR SuspendOutPol; // 0 for negative, 1 for positive (not implemented on Rev A) + UCHAR EnableSuspendOut; // non-zero to enable (not implemented on Rev A) + // QSPI + UCHAR Clock_SlowSlew; // non-zero if clock pin has slow slew + UCHAR Clock_Drive; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR IO0_SlowSlew; // non-zero if IO0 pin has slow slew + UCHAR IO1_SlowSlew; // non-zero if IO1 pin has slow slew + UCHAR IO2_SlowSlew; // non-zero if IO2 pin has slow slew + UCHAR IO3_SlowSlew; // non-zero if IO3 pin has slow slew + UCHAR IO_Drive; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR SlaveSelect_PullUp; // non-zero to enable pull up + UCHAR SlaveSelect_PullDown; // non-zero to enable pull down + UCHAR SlaveSelect_Drive; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR SlaveSelect_SlowSlew; // non-zero if slave select pin has slow slew + UCHAR MISO_Suspend; // 2 for push-low, 3 for push high, 0 and 1 reserved + UCHAR SIMO_Suspend; // 2 for push-low, 3 for push high, 0 and 1 reserved + UCHAR IO2_IO3_Suspend; // 2 for push-low, 3 for push high, 0 and 1 reserved + UCHAR SlaveSelect_Suspend; // 0 for no-change (not implemented on Rev A), 2 for push-low, 3 for push high, 1 reserved + // GPIO + UCHAR GPIO0_Drive; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR GPIO1_Drive; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR GPIO2_Drive; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR GPIO3_Drive; // valid values are 4mA, 8mA, 12mA, 16mA + UCHAR GPIO0_SlowSlew; // non-zero if IO0 pin has slow slew + UCHAR GPIO1_SlowSlew; // non-zero if IO0 pin has slow slew + UCHAR GPIO2_SlowSlew; // non-zero if IO0 pin has slow slew + UCHAR GPIO3_SlowSlew; // non-zero if IO0 pin has slow slew + UCHAR GPIO0_PullDown; // non-zero to enable pull down + UCHAR GPIO1_PullDown; // non-zero to enable pull down + UCHAR GPIO2_PullDown; // non-zero to enable pull down + UCHAR GPIO3_PullDown; // non-zero to enable pull down + UCHAR GPIO0_PullUp; // non-zero to enable pull up + UCHAR GPIO1_PullUp; // non-zero to enable pull up + UCHAR GPIO2_PullUp; // non-zero to enable pull up + UCHAR GPIO3_PullUp; // non-zero to enable pull up + UCHAR GPIO0_OpenDrain; // non-zero to enable open drain + UCHAR GPIO1_OpenDrain; // non-zero to enable open drain + UCHAR GPIO2_OpenDrain; // non-zero to enable open drain + UCHAR GPIO3_OpenDrain; // non-zero to enable open drain + UCHAR GPIO0_Suspend; // 0 for no-change, 1 for input (not implemented on Rev A), 2 for push-low, 3 for push high + UCHAR GPIO1_Suspend; // 0 for no-change, 1 for input (not implemented on Rev A), 2 for push-low, 3 for push high + UCHAR GPIO2_Suspend; // 0 for no-change, 1 for input (not implemented on Rev A), 2 for push-low, 3 for push high + UCHAR GPIO3_Suspend; // 0 for no-change, 1 for input (not implemented on Rev A), 2 for push-low, 3 for push high + UCHAR FallingEdge; // non-zero to change GPIO on falling edge + // BCD + UCHAR BCD_Disable; // non-zero to disable BCD + UCHAR BCD_OutputActiveLow; // non-zero to set BCD output active low + UCHAR BCD_Drive; // valid values are 4mA, 8mA, 12mA, 16mA +} FT_EEPROM_4222H, *PFT_EEPROM_4222H; + +// Power Delivery structures for use with FT_EEPROM_Read and FT_EEPROM_Program +// PDO Configuration structure, mA supported values 0 to 10230mA, mV supported values 0 to 51100mV +// This is part of the FT_EEPROM_PD structure. +typedef struct ft_eeprom_PD_PDO_mv_ma { + USHORT PDO1ma; // PDO1 mA + USHORT PDO1mv; // PDO1 mV + USHORT PDO2ma; // PDO2 mA + USHORT PDO2mv; // PDO2 mV + USHORT PDO3ma; // PDO3 mA + USHORT PDO3mv; // PDO3 mV + USHORT PDO4ma; // PDO4 mA + USHORT PDO4mv; // PDO4 mV + USHORT PDO5ma; // PDO5 mA (FTx233HP only) + USHORT PDO5mv; // PDO5 mV (FTx233HP only) + USHORT PDO6ma; // PDO6 mA (FTx233HP only) + USHORT PDO6mv; // PDO6 mV (FTx233HP only) + USHORT PDO7ma; // PDO7 mA (FTx233HP only) + USHORT PDO7mv; // PDO7 mV (FTx233HP only) +} FT_EEPROM_PD_PDO_mv_ma; + +// PD EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +// This is appended to the end of the base device structure. e_g. +// struct { +// FT_EEPROM_xxx base; +// FT_EEPROM_PD pd; +// }; +// Device GPIO values are: +// FTx233HP - 0 to 7, 15 for N/A +// FTx232HP - 0 to 3, 15 for N/A +typedef struct ft_eeprom_pd { + // Configuration + UCHAR srprs; // non-zero to enable Sink Request Power Role Swap + UCHAR sraprs; // non-zero to enable Sink Accept PR Swap + UCHAR srrprs; // non-zero to enable Source Request PR SWAP + UCHAR saprs; // non-zero to enable Source Accept PR SWAP + UCHAR vconns; // non-zero to enable vConn Swap + UCHAR passthru; // non-zero to enable Pass Through (FTx233HP only) + UCHAR extmcu; // non-zero to enable External MCU + UCHAR pd2en; // non-zero to enable PD2 (FTx233HP only) + UCHAR pd1autoclk; // non-zero to enable PD1 Auto Clock + UCHAR pd2autoclk; // non-zero to enable PD2 Auto Clock (FTx233HP only) + UCHAR useefuse; // non-zero to Use EFUSE + UCHAR extvconn; // non-zero to enable External vConn + + // GPIO Configuration + UCHAR count; // GPIO Count, supported values are 0 to 7 + UCHAR gpio1; // GPIO Number 1, supports device GPIO values + UCHAR gpio2; // GPIO Number 2, supports device GPIO values + UCHAR gpio3; // GPIO Number 3, supports device GPIO values + UCHAR gpio4; // GPIO Number 4, supports device GPIO values + UCHAR gpio5; // GPIO Number 5, supports device GPIO values (FTx233HP only) + UCHAR gpio6; // GPIO Number 6, supports device GPIO values (FTx233HP only) + UCHAR gpio7; // GPIO Number 7, supports device GPIO values (FTx233HP only) + UCHAR pd1lden; // PD1 Load Enable, supports device GPIO values + UCHAR pd2lden; // PD2 Load Enable, supports device GPIO values (FTx233HP only) + UCHAR dispin; // Discharge Pin, supports device GPIO values + UCHAR disenbm; // Discharge Enable BM, 0 for "Drive Hi", 1 for "Drive Low", 2 for "Input Mode", 3 for "Don't Care" + UCHAR disdisbm; // Discharge Disable BM, 0 for "Drive Hi", 1 for "Drive Low", 2 for "Input Mode", 3 for "Don't Care" + UCHAR ccselect; // CC Select Indicator, supports device GPIO values + + // ISET Configuration + UCHAR iset1; // ISET1, supports device GPIO values + UCHAR iset2; // ISET2, supports device GPIO values + UCHAR iset3; // ISET3, supports device GPIO values + UCHAR extiset; // non-zero to enable EXTEND_ISET + UCHAR isetpd2; // non-zero to enable ISET_PD2 + UCHAR iseten; // non-zero to set ISET_ENABLED + + // BM Configuration, 0 for "Drive Hi", 1 for "Drive Low", 2 for "Input Mode", 3 for "Don't Care" + UCHAR PDO1_GPIO[7]; // PDO1 GPIO1 to GPIO7 + UCHAR PDO2_GPIO[7]; // PDO2 GPIO1 to GPIO7 + UCHAR PDO3_GPIO[7]; // PDO3 GPIO1 to GPIO7 + UCHAR PDO4_GPIO[7]; // PDO4 GPIO1 to GPIO7 + UCHAR PDO5_GPIO[7]; // PDO5 GPIO1 to GPIO7 (FTx233HP only) + UCHAR PDO6_GPIO[7]; // PDO6 GPIO1 to GPIO7 (FTx233HP only) + UCHAR PDO7_GPIO[7]; // PDO7 GPIO1 to GPIO7 (FTx233HP only) + UCHAR VSET0V_GPIO[7]; // PDO7 GPIO1 to GPIO7 + UCHAR VSAFE5V_GPIO[7]; // PDO7 GPIO1 to GPIO7 + + FT_EEPROM_PD_PDO_mv_ma BM_PDO_Sink; + FT_EEPROM_PD_PDO_mv_ma BM_PDO_Source; + FT_EEPROM_PD_PDO_mv_ma BM_PDO_Sink_2; // (FTx233HP only) + + // PD Timers + UCHAR srt; // Sender Response Timer + UCHAR hrt; // Hard Reset Timer + UCHAR sct; // Source Capability Timer + UCHAR dit; // Discover Identity Timer + USHORT srcrt; // Source Recover Timer + USHORT trt; // Transition Timer + USHORT sofft; // Source off timer + USHORT nrt; // No Response Timer + USHORT swct; // Sink Wait Capability Timer + USHORT snkrt; // Sink Request Timer + UCHAR dt; // Discharge Timer + UCHAR cnst; // Chunk not supported timer + USHORT it; // Idle Timer + + // PD Control + UCHAR i2caddr; // I2C Address (hex) + UINT prou; // Power Reserved for OWN use + UINT trim1; // TRIM1 + UINT trim2; // TRIM2 + UCHAR extdc; // non-zero to enable ETERNAL_DC_POWER +} FT_EEPROM_PD, *PFT_EEPROM_PD; + +// FT2233HP EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +// FT2232H with power delivery +typedef struct _ft_eeprom_2233hp { + FT_EEPROM_2232H ft2232h; + FT_EEPROM_PD pd; +} FT_EEPROM_2233HP, *PFT_EEPROM_2233HP; + +// FT4233HP EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +// FT4232H with power delivery +typedef struct _ft_eeprom_4233hp { + FT_EEPROM_4232H ft4232h; + FT_EEPROM_PD pd; +} FT_EEPROM_4233HP, *PFT_EEPROM_4233HP; + +// FT2232HP EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +// FT2232H with power delivery +typedef struct _ft_eeprom_2232hp { + FT_EEPROM_2232H ft2232h; + FT_EEPROM_PD pd; +} FT_EEPROM_2232HP, *PFT_EEPROM_2232HP; + +// FT4232HP EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +// FT4232H with power delivery +typedef struct _ft_eeprom_4232hp { + FT_EEPROM_4232H ft4232h; + FT_EEPROM_PD pd; +} FT_EEPROM_4232HP, *PFT_EEPROM_4232HP; + +// FT233HP EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +// FT233H with power delivery +typedef struct _ft_eeprom_233hp { + FT_EEPROM_232H ft232h; + FT_EEPROM_PD pd; +} FT_EEPROM_233HP, *PFT_EEPROM_233HP; + +// FT232HP EEPROM structure for use with FT_EEPROM_Read and FT_EEPROM_Program +// FT232H with power delivery +typedef struct _ft_eeprom_232hp { + FT_EEPROM_232H ft232h; + FT_EEPROM_PD pd; +} FT_EEPROM_232HP, *PFT_EEPROM_232HP; + +FTD2XX_API +FT_STATUS WINAPI FT_EEPROM_Read(FT_HANDLE ftHandle, void *eepromData, DWORD eepromDataSize, char *Manufacturer, + char *ManufacturerId, char *Description, char *SerialNumber); + +FTD2XX_API +FT_STATUS WINAPI FT_EEPROM_Program(FT_HANDLE ftHandle, void *eepromData, DWORD eepromDataSize, char *Manufacturer, + char *ManufacturerId, char *Description, char *SerialNumber); + +FTD2XX_API +FT_STATUS WINAPI FT_SetLatencyTimer(FT_HANDLE ftHandle, UCHAR ucLatency); + +FTD2XX_API +FT_STATUS WINAPI FT_GetLatencyTimer(FT_HANDLE ftHandle, PUCHAR pucLatency); + +FTD2XX_API +FT_STATUS WINAPI FT_SetBitMode(FT_HANDLE ftHandle, UCHAR ucMask, UCHAR ucEnable); + +FTD2XX_API +FT_STATUS WINAPI FT_GetBitMode(FT_HANDLE ftHandle, PUCHAR pucMode); + +FTD2XX_API +FT_STATUS WINAPI FT_SetUSBParameters(FT_HANDLE ftHandle, ULONG ulInTransferSize, ULONG ulOutTransferSize); + +FTD2XX_API +FT_STATUS WINAPI FT_SetDeadmanTimeout(FT_HANDLE ftHandle, ULONG ulDeadmanTimeout); + +#ifndef _WIN32 +// Extra functions for non-Windows platforms to compensate +// for lack of .INF file to specify Vendor and Product IDs. + +FTD2XX_API +FT_STATUS FT_SetVIDPID(DWORD dwVID, DWORD dwPID); + +FTD2XX_API +FT_STATUS FT_GetVIDPID(DWORD *pdwVID, DWORD *pdwPID); + +FTD2XX_API +FT_STATUS WINAPI FT_GetDeviceLocId(FT_HANDLE ftHandle, LPDWORD lpdwLocId); +#endif // _WIN32 + +FTD2XX_API +FT_STATUS WINAPI FT_GetDeviceInfo( + FT_HANDLE ftHandle, FT_DEVICE *lpftDevice, LPDWORD lpdwID, PCHAR SerialNumber, PCHAR Description, LPVOID Dummy); + +FTD2XX_API +FT_STATUS WINAPI FT_StopInTask(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_RestartInTask(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_SetResetPipeRetryCount(FT_HANDLE ftHandle, DWORD dwCount); + +FTD2XX_API +FT_STATUS WINAPI FT_ResetPort(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_CyclePort(FT_HANDLE ftHandle); + +// +// Win32-type functions +// + +FTD2XX_API +FT_HANDLE WINAPI FT_W32_CreateFile(LPCTSTR lpszName, DWORD dwAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreate, DWORD dwAttrsAndFlags, HANDLE hTemplate); + +FTD2XX_API +BOOL WINAPI FT_W32_CloseHandle(FT_HANDLE ftHandle); + +FTD2XX_API +BOOL WINAPI FT_W32_ReadFile( + FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped); + +FTD2XX_API +BOOL WINAPI FT_W32_WriteFile( + FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD nBufferSize, LPDWORD lpBytesWritten, LPOVERLAPPED lpOverlapped); + +FTD2XX_API +DWORD WINAPI FT_W32_GetLastError(FT_HANDLE ftHandle); + +FTD2XX_API +BOOL WINAPI FT_W32_GetOverlappedResult( + FT_HANDLE ftHandle, LPOVERLAPPED lpOverlapped, LPDWORD lpdwBytesTransferred, BOOL bWait); + +FTD2XX_API +BOOL WINAPI FT_W32_CancelIo(FT_HANDLE ftHandle); + +// +// Win32 COMM API type functions +// +typedef struct _FTCOMSTAT { + DWORD fCtsHold : 1; + DWORD fDsrHold : 1; + DWORD fRlsdHold : 1; + DWORD fXoffHold : 1; + DWORD fXoffSent : 1; + DWORD fEof : 1; + DWORD fTxim : 1; + DWORD fReserved : 25; + DWORD cbInQue; + DWORD cbOutQue; +} FTCOMSTAT, *LPFTCOMSTAT; + +typedef struct _FTDCB { + DWORD DCBlength; /* sizeof(FTDCB) */ + DWORD BaudRate; /* Baudrate at which running */ + DWORD fBinary : 1; /* Binary Mode (skip EOF check) */ + DWORD fParity : 1; /* Enable parity checking */ + DWORD fOutxCtsFlow : 1; /* CTS handshaking on output */ + DWORD fOutxDsrFlow : 1; /* DSR handshaking on output */ + DWORD fDtrControl : 2; /* DTR Flow control */ + DWORD fDsrSensitivity : 1; /* DSR Sensitivity */ + DWORD fTXContinueOnXoff : 1; /* Continue TX when Xoff sent */ + DWORD fOutX : 1; /* Enable output X-ON/X-OFF */ + DWORD fInX : 1; /* Enable input X-ON/X-OFF */ + DWORD fErrorChar : 1; /* Enable Err Replacement */ + DWORD fNull : 1; /* Enable Null stripping */ + DWORD fRtsControl : 2; /* Rts Flow control */ + DWORD fAbortOnError : 1; /* Abort all reads and writes on Error */ + DWORD fDummy2 : 17; /* Reserved */ + WORD wReserved; /* Not currently used */ + WORD XonLim; /* Transmit X-ON threshold */ + WORD XoffLim; /* Transmit X-OFF threshold */ + BYTE ByteSize; /* Number of bits/byte, 4-8 */ + BYTE Parity; /* 0-4=None,Odd,Even,Mark,Space */ + BYTE StopBits; /* FT_STOP_BITS_1 or FT_STOP_BITS_2 */ + char XonChar; /* Tx and Rx X-ON character */ + char XoffChar; /* Tx and Rx X-OFF character */ + char ErrorChar; /* Error replacement char */ + char EofChar; /* End of Input character */ + char EvtChar; /* Received Event character */ + WORD wReserved1; /* Fill for now. */ +} FTDCB, *LPFTDCB; + +typedef struct _FTTIMEOUTS { + DWORD ReadIntervalTimeout; /* Maximum time between read chars. */ + DWORD ReadTotalTimeoutMultiplier; /* Multiplier of characters. */ + DWORD ReadTotalTimeoutConstant; /* Constant in milliseconds. */ + DWORD WriteTotalTimeoutMultiplier; /* Multiplier of characters. */ + DWORD WriteTotalTimeoutConstant; /* Constant in milliseconds. */ +} FTTIMEOUTS, *LPFTTIMEOUTS; + +FTD2XX_API +BOOL WINAPI FT_W32_ClearCommBreak(FT_HANDLE ftHandle); + +FTD2XX_API +BOOL WINAPI FT_W32_ClearCommError(FT_HANDLE ftHandle, LPDWORD lpdwErrors, LPFTCOMSTAT lpftComstat); + +FTD2XX_API +BOOL WINAPI FT_W32_EscapeCommFunction(FT_HANDLE ftHandle, DWORD dwFunc); + +FTD2XX_API +BOOL WINAPI FT_W32_GetCommModemStatus(FT_HANDLE ftHandle, LPDWORD lpdwModemStatus); + +FTD2XX_API +BOOL WINAPI FT_W32_GetCommState(FT_HANDLE ftHandle, LPFTDCB lpftDcb); + +FTD2XX_API +BOOL WINAPI FT_W32_GetCommTimeouts(FT_HANDLE ftHandle, FTTIMEOUTS *pTimeouts); + +FTD2XX_API +BOOL WINAPI FT_W32_PurgeComm(FT_HANDLE ftHandle, DWORD dwMask); + +FTD2XX_API +BOOL WINAPI FT_W32_SetCommBreak(FT_HANDLE ftHandle); + +FTD2XX_API +BOOL WINAPI FT_W32_SetCommMask(FT_HANDLE ftHandle, ULONG ulEventMask); + +FTD2XX_API +BOOL WINAPI FT_W32_GetCommMask(FT_HANDLE ftHandle, LPDWORD lpdwEventMask); + +FTD2XX_API +BOOL WINAPI FT_W32_SetCommState(FT_HANDLE ftHandle, LPFTDCB lpftDcb); + +FTD2XX_API +BOOL WINAPI FT_W32_SetCommTimeouts(FT_HANDLE ftHandle, FTTIMEOUTS *pTimeouts); + +FTD2XX_API +BOOL WINAPI FT_W32_SetupComm(FT_HANDLE ftHandle, DWORD dwReadBufferSize, DWORD dwWriteBufferSize); + +FTD2XX_API +BOOL WINAPI FT_W32_WaitCommEvent(FT_HANDLE ftHandle, PULONG pulEvent, LPOVERLAPPED lpOverlapped); + +// +// Device information +// + +typedef struct _ft_device_list_info_node { + ULONG Flags; + ULONG Type; + ULONG ID; + DWORD LocId; + char SerialNumber[16]; + char Description[64]; + FT_HANDLE ftHandle; +} FT_DEVICE_LIST_INFO_NODE; + +// Device information flags +enum { + FT_FLAGS_OPENED = 1, + FT_FLAGS_HISPEED = 2 +}; + +FTD2XX_API +FT_STATUS WINAPI FT_CreateDeviceInfoList(LPDWORD lpdwNumDevs); + +FTD2XX_API +FT_STATUS WINAPI FT_GetDeviceInfoList(FT_DEVICE_LIST_INFO_NODE *pDest, LPDWORD lpdwNumDevs); + +FTD2XX_API +FT_STATUS WINAPI FT_GetDeviceInfoDetail(DWORD dwIndex, LPDWORD lpdwFlags, LPDWORD lpdwType, LPDWORD lpdwID, + LPDWORD lpdwLocId, LPVOID lpSerialNumber, LPVOID lpDescription, FT_HANDLE *pftHandle); + +// +// Version information +// + +FTD2XX_API +FT_STATUS WINAPI FT_GetDriverVersion(FT_HANDLE ftHandle, LPDWORD lpdwVersion); + +FTD2XX_API +FT_STATUS WINAPI FT_GetLibraryVersion(LPDWORD lpdwVersion); + +FTD2XX_API +FT_STATUS WINAPI FT_Rescan(void); + +FTD2XX_API +FT_STATUS WINAPI FT_Reload(WORD wVid, WORD wPid); + +FTD2XX_API +FT_STATUS WINAPI FT_GetComPortNumber(FT_HANDLE ftHandle, LPLONG lpdwComPortNumber); + +// +// FT232H additional EEPROM functions +// + +FTD2XX_API +FT_STATUS WINAPI FT_EE_ReadConfig(FT_HANDLE ftHandle, UCHAR ucAddress, PUCHAR pucValue); + +FTD2XX_API +FT_STATUS WINAPI FT_EE_WriteConfig(FT_HANDLE ftHandle, UCHAR ucAddress, UCHAR ucValue); + +FTD2XX_API +FT_STATUS WINAPI FT_EE_ReadECC(FT_HANDLE ftHandle, UCHAR ucOption, LPWORD lpwValue); + +FTD2XX_API +FT_STATUS WINAPI FT_GetQueueStatusEx(FT_HANDLE ftHandle, DWORD *dwRxBytes); + +FTD2XX_API +FT_STATUS WINAPI FT_ComPortIdle(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_ComPortCancelIdle(FT_HANDLE ftHandle); + +FTD2XX_API +FT_STATUS WINAPI FT_VendorCmdGet(FT_HANDLE ftHandle, UCHAR Request, UCHAR *Buf, USHORT Len); + +FTD2XX_API +FT_STATUS WINAPI FT_VendorCmdSet(FT_HANDLE ftHandle, UCHAR Request, UCHAR *Buf, USHORT Len); + +FTD2XX_API +FT_STATUS WINAPI FT_VendorCmdGetEx(FT_HANDLE ftHandle, USHORT wValue, UCHAR *Buf, USHORT Len); + +FTD2XX_API +FT_STATUS WINAPI FT_VendorCmdSetEx(FT_HANDLE ftHandle, USHORT wValue, UCHAR *Buf, USHORT Len); + +#ifdef __cplusplus +} +#endif + +#endif /* FTD2XX_H */ diff --git a/3rdparty/ftdi/i386/ftd2xx.dll b/3rdparty/ftdi/i386/ftd2xx.dll new file mode 100644 index 00000000000..1ae4df40f3b Binary files /dev/null and b/3rdparty/ftdi/i386/ftd2xx.dll differ diff --git a/3rdparty/ftdi/i386/ftd2xx.lib b/3rdparty/ftdi/i386/ftd2xx.lib new file mode 100644 index 00000000000..5dc71ee5b31 Binary files /dev/null and b/3rdparty/ftdi/i386/ftd2xx.lib differ diff --git a/src/Makefile b/src/Makefile index 983ebc74dcf..55e0107533f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -154,7 +154,7 @@ GIT_VERSION := $(shell if [ -e "../.git" ]; then git describe --always --dirty - clean: host_clean $(Q)echo " CLEAN" -$(Q)$(RM) *.o *.d *.elf *~ $(TARGET) $(HOSTFILES) - -$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile + -$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile ftd2xx.dll ifeq ($(GIT_VERSION),) @echo Git not found, not deleting include/version.h else diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc index 27488958e39..4042807fc9f 100644 --- a/src/platforms/hosted/Makefile.inc +++ b/src/platforms/hosted/Makefile.inc @@ -69,15 +69,34 @@ else ifneq (filter, macosx darwin, $(SYS)) CFLAGS += -I /opt/homebrew/include -I /opt/homebrew/include/libusb-1.0 endif +# If we're on Windows, pick the correct FTD2xx implementation +ifeq ($(OS), Windows_NT) + ifneq ($(HOSTED_BMP_ONLY), 1) + VPATH += platforms/hosted/windows + CFLAGS += -I../3rdparty/ftdi -Iplatforms/hosted/windows + ifeq ($(PROCESSOR_ARCHITECTURE), AMD64) + LDFLAGS += ../3rdparty/ftdi/amd64/ftd2xx.lib + FTDI_DLL = ../3rdparty/ftdi/amd64/ftd2xx.dll + else + LDFLAGS += ../3rdparty/ftdi/i386/ftd2xx.lib + FTDI_DLL = ../3rdparty/ftdi/i386/ftd2xx.dll + endif + endif +endif + ifneq ($(HOSTED_BMP_ONLY), 1) ifneq ($(shell pkg-config --exists libusb-1.0; echo $$?), 0) $(error Please install libusb-1.0 dependency or set HOSTED_BMP_ONLY to 1) endif - ifneq ($(shell pkg-config --exists libftdi1; echo $$?), 0) - $(error Please install libftdi1 dependency or set HOSTED_BMP_ONLY to 1) + ifneq ($(OS), Windows_NT) + ifneq ($(shell pkg-config --exists libftdi1; echo $$?), 0) + $(error Please install libftdi1 dependency or set HOSTED_BMP_ONLY to 1) + endif + CFLAGS += $(shell pkg-config --cflags libftdi1) + LDFLAGS += $(shell pkg-config --libs libftdi1) endif - CFLAGS += $(shell pkg-config --cflags libusb-1.0) $(shell pkg-config --cflags libftdi1) - LDFLAGS += $(shell pkg-config --libs libusb-1.0) $(shell pkg-config --libs libftdi1) + CFLAGS += $(shell pkg-config --cflags libusb-1.0) + LDFLAGS += $(shell pkg-config --libs libusb-1.0) CFLAGS += -Wno-missing-field-initializers endif @@ -100,6 +119,9 @@ SRC += protocol_v1.c protocol_v1_adiv5.c protocol_v2.c SRC += protocol_v3.c protocol_v3_adiv5.c SRC += bmp_remote.c ifneq ($(HOSTED_BMP_ONLY), 1) + ifeq ($(OS), Windows_NT) + SRC += ftd2xx.dll ftdi.c + endif SRC += bmp_libusb.c stlinkv2.c stlinkv2_jtag.c stlinkv2_swd.c SRC += ftdi_bmp.c ftdi_jtag.c ftdi_swd.c SRC += jlink.c jlink_jtag.c jlink_swd.c @@ -110,5 +132,11 @@ PC_HOSTED = 1 all: blackmagic +ifeq ($(OS), Windows_NT) +.PHONY: ftd2xx.dll + +ftd2xx.dll: + cp $(FTDI_DLL) ../src +endif host_clean: -$(Q)$(RM) blackmagic diff --git a/src/platforms/hosted/bmp_hosted.h b/src/platforms/hosted/bmp_hosted.h index d2131f060c1..3075d650df4 100644 --- a/src/platforms/hosted/bmp_hosted.h +++ b/src/platforms/hosted/bmp_hosted.h @@ -49,6 +49,7 @@ typedef struct transfer_ctx { volatile size_t flags; } transfer_ctx_s; +typedef struct libusb_device_descriptor libusb_device_descriptor_s; typedef struct libusb_config_descriptor libusb_config_descriptor_s; typedef struct libusb_interface_descriptor libusb_interface_descriptor_s; typedef struct libusb_endpoint_descriptor libusb_endpoint_descriptor_s; diff --git a/src/platforms/hosted/bmp_libusb.c b/src/platforms/hosted/bmp_libusb.c index 6d67f2b0ee0..f3a7ee89f69 100644 --- a/src/platforms/hosted/bmp_libusb.c +++ b/src/platforms/hosted/bmp_libusb.c @@ -19,13 +19,67 @@ /* Find all known usb connected debuggers */ #include "general.h" +#if defined(_WIN32) || defined(__CYGWIN__) +#define NOMINMAX +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include "ftd2xx.h" +#else #include +#include +#endif #include "cli.h" #include "ftdi_bmp.h" #include "version.h" +#include "probe_info.h" +#include "utils.h" #define NO_SERIAL_NUMBER "" +void bmp_read_product_version(libusb_device_descriptor_s *device_descriptor, libusb_device *device, + libusb_device_handle *handle, char **product, char **manufacturer, char **serial, char **version); + +typedef struct debugger_device { + uint16_t vendor; + uint16_t product; + bmp_type_t type; + void (*function)( + libusb_device_descriptor_s *, libusb_device *, libusb_device_handle *, char **, char **, char **, char **); + char *type_string; +} debugger_device_s; + +/* Create the list of debuggers BMDA works with */ +debugger_device_s debugger_devices[] = { + {VENDOR_ID_BMP, PRODUCT_ID_BMP, BMP_TYPE_BMP, bmp_read_product_version, "Black Magic Probe"}, + {VENDOR_ID_STLINK, PRODUCT_ID_STLINKV2, BMP_TYPE_STLINK_V2, NULL, "ST-Link v2"}, + {VENDOR_ID_STLINK, PRODUCT_ID_STLINKV21, BMP_TYPE_STLINK_V2, NULL, "ST-Link v2.1"}, + {VENDOR_ID_STLINK, PRODUCT_ID_STLINKV21_MSD, BMP_TYPE_STLINK_V2, NULL, "ST-Link v2.1 MSD"}, + {VENDOR_ID_STLINK, PRODUCT_ID_STLINKV3_NO_MSD, BMP_TYPE_STLINK_V2, NULL, "ST-Link v2.1 No MSD"}, + {VENDOR_ID_STLINK, PRODUCT_ID_STLINKV3, BMP_TYPE_STLINK_V2, NULL, "ST-Link v3"}, + {VENDOR_ID_STLINK, PRODUCT_ID_STLINKV3E, BMP_TYPE_STLINK_V2, NULL, "ST-Link v3E"}, + {VENDOR_ID_SEGGER, PRODUCT_ID_UNKNOWN, BMP_TYPE_JLINK, NULL, "Segger JLink"}, + {VENDOR_ID_FTDI, PRODUCT_ID_FTDI_FT2232, BMP_TYPE_FTDI, NULL, "FTDI FT2232"}, + {VENDOR_ID_FTDI, PRODUCT_ID_FTDI_FT4232, BMP_TYPE_FTDI, NULL, "FTDI FT4232"}, + {VENDOR_ID_FTDI, PRODUCT_ID_FTDI_FT232, BMP_TYPE_FTDI, NULL, "FTDI FT232"}, + {0, 0, BMP_TYPE_NONE, NULL, ""}, +}; + +bmp_type_t get_type_from_vid_pid(const uint16_t probe_vid, const uint16_t probe_pid) +{ + bmp_type_t probe_type = BMP_TYPE_NONE; + /* Segger probe PIDs are unknown, if we have a Segger probe force the type to JLink */ + if (probe_vid == VENDOR_ID_SEGGER) + return BMP_TYPE_JLINK; + + for (size_t index = 0; debugger_devices[index].type != BMP_TYPE_NONE; index++) { + if (debugger_devices[index].vendor == probe_vid && debugger_devices[index].product == probe_pid) + return debugger_devices[index].type; + } + return probe_type; +} + void bmp_ident(bmp_info_s *info) { DEBUG_INFO("Black Magic Debug App %s\n for Black Magic Probe, ST-Link v2 and v3, CMSIS-DAP, " @@ -47,291 +101,360 @@ void libusb_exit_function(bmp_info_s *info) } } -static bmp_type_t find_cmsis_dap_interface(libusb_device *dev, bmp_info_s *info) +static char *get_device_descriptor_string(libusb_device_handle *handle, uint16_t string_index) +{ + char read_string[128] = {0}; + if (string_index != 0) + libusb_get_string_descriptor_ascii(handle, string_index, (uint8_t *)read_string, sizeof(read_string)); + return strdup(read_string); +} + +/* + * BMP Probes have their version information in the product string. + * + * Extract the product and version, skip the manufacturer string + */ +void bmp_read_product_version(libusb_device_descriptor_s *device_descriptor, libusb_device *device, + libusb_device_handle *handle, char **product, char **manufacturer, char **serial, char **version) { - bmp_type_t type = BMP_TYPE_NONE; + (void)device; + (void)serial; + (void)manufacturer; + char *start_of_version; + *product = get_device_descriptor_string(handle, device_descriptor->iProduct); + start_of_version = strrchr(*product, ' '); + if (start_of_version == NULL) { + version = NULL; + } else { + while (start_of_version[0] == ' ' && start_of_version != *product) + --start_of_version; + start_of_version[1] = '\0'; + start_of_version += 2; + while (start_of_version[0] == ' ' && start_of_version[0] != '\0') + ++start_of_version; + *version = strdup(start_of_version); + } +} - libusb_config_descriptor_s *conf; - char interface_string[128]; +#if defined(_WIN32) || defined(__CYGWIN__) +static probe_info_s *process_ftdi_probe(void) +{ + DWORD ftdi_dev_count = 0; + if (FT_CreateDeviceInfoList(&ftdi_dev_count) != FT_OK) + return NULL; - int res = libusb_get_active_config_descriptor(dev, &conf); - if (res < 0) { - DEBUG_ERROR("libusb_get_active_config_descriptor() failed: %s", libusb_strerror(res)); - return type; + FT_DEVICE_LIST_INFO_NODE *dev_info = + (FT_DEVICE_LIST_INFO_NODE *)malloc(sizeof(FT_DEVICE_LIST_INFO_NODE) * ftdi_dev_count); + if (dev_info == NULL) { + DEBUG_ERROR("%s: Memory allocation failed\n", __func__); + return NULL; } - libusb_device_handle *handle; - res = libusb_open(dev, &handle); - if (res != LIBUSB_SUCCESS) { - DEBUG_INFO("libusb_open() failed: %s\n", libusb_strerror(res)); - libusb_free_config_descriptor(conf); - return type; + if (FT_GetDeviceInfoList(dev_info, &ftdi_dev_count) != FT_OK) { + free(dev_info); + return NULL; } - for (uint8_t i = 0; i < conf->bNumInterfaces; ++i) { - const libusb_interface_descriptor_s *interface = &conf->interface[i].altsetting[0]; + probe_info_s *probe_list = NULL; + const char *probe_skip = NULL; + bool use_serial = true; + /* Device list is loaded, iterate over the found probes */ + for (size_t index = 0; index < ftdi_dev_count; ++index) { + const uint16_t vid = (dev_info[index].ID >> 16U) & 0xffffU; + const uint16_t pid = dev_info[index].ID & 0xffffU; + bool add_probe = true; - if (!interface->iInterface) - continue; + char *serial = strdup(dev_info[index].SerialNumber); + char *const product = strdup(dev_info[index].Description); + size_t serial_len = strlen(serial); + if (!serial_len) { + free(serial); + serial = strdup("---"); // Unknown serial number + } else { + --serial_len; + if (serial[serial_len] == 'A') { + serial[serial_len] = '\0'; // Remove the trailing "A" - res = libusb_get_string_descriptor_ascii( - handle, interface->iInterface, (uint8_t *)interface_string, sizeof(interface_string)); - if (res < 0) { - DEBUG_ERROR("libusb_get_string_descriptor_ascii() failed: %s\n", libusb_strerror(res)); - continue; - } + if (probe_skip) { // Clean up any previous serial number to skip + use_serial = true; + free((void *)probe_skip); + probe_skip = NULL; + } - if (!strstr(interface_string, "CMSIS")) - continue; - type = BMP_TYPE_CMSIS_DAP; + // If the serial number is valid, save it for later interface skip testing + if (serial_len) + probe_skip = strdup(serial); // Save the fixed serial number so we can skip over other interfaces - if (interface->bInterfaceClass == 0xffU && interface->bNumEndpoints == 2U) { - info->interface_num = interface->bInterfaceNumber; + size_t product_len = strlen(product); // Product has " A" appended + product_len -= 2; + product[product_len] = '\0'; // Remove it - for (uint8_t j = 0; j < interface->bNumEndpoints; ++j) { - const uint8_t n = interface->endpoint[j].bEndpointAddress; - if (n & 0x80U) - info->in_ep = n; - else - info->out_ep = n; + // If we don't have a saved serial number, use the truncated product for the probe skip test + if (!probe_skip) { + use_serial = false; + probe_skip = strdup(product); + } + } else { + if (probe_skip) { + if (use_serial) + // Skip this interface if the serial matches + add_probe = strstr(serial, probe_skip) == NULL; + else + // Skip this interface if the product name matches + add_probe = strstr(product, probe_skip) == NULL; + } } - - /* V2 is preferred, return early. */ - break; + } + if (add_probe) { + const char *const manufacturer = strdup("FTDI"); + probe_list = probe_info_add_by_id( + probe_list, BMP_TYPE_FTDI, NULL, vid, pid, manufacturer, product, serial, strdup("---")); + } else { + free(serial); + free(product); } } - libusb_free_config_descriptor(conf); - return type; + if (probe_skip) + free((void *)probe_skip); + free(dev_info); + return probe_list; } +#endif -int find_debuggers(bmda_cli_options_s *cl_opts, bmp_info_s *info) +void orbtrace_read_version(libusb_device *device, libusb_device_handle *handle, char *version, size_t buffer_size) { - libusb_device **devs; - int res = libusb_init(&info->libusb_ctx); - if (res) { - DEBUG_ERROR("Failed to get USB context: %s\n", libusb_strerror(res)); - exit(-1); - } - if (cl_opts->opt_cable) { - if (!strcmp(cl_opts->opt_cable, "list") || !strcmp(cl_opts->opt_cable, "l")) { - const cable_desc_s *cable = cable_desc; - DEBUG_WARN("Available cables:\n"); - for (; cable->name; ++cable) - DEBUG_WARN("\t%s%c\n", cable->name, cable->description ? ' ' : '*'); - - DEBUG_WARN("*: No auto-detection possible! Give cable name as argument!\n"); - exit(0); + libusb_config_descriptor_s *config; + if (libusb_get_active_config_descriptor(device, &config) != 0) + return; + for (size_t iface = 0; iface < config->bNumInterfaces; ++iface) { + const libusb_interface_s *interface = &config->interface[iface]; + for (int altmode = 0; altmode < interface->num_altsetting; ++altmode) { + const libusb_interface_descriptor_s *descriptor = &interface->altsetting[altmode]; + uint8_t string_index = descriptor->iInterface; + if (string_index == 0) + continue; + if (libusb_get_string_descriptor_ascii(handle, string_index, (uint8_t *)version, (int)buffer_size) < 0) + continue; /* We failed but that's a soft error at this point. */ + + const size_t version_len = strlen(version); + if (begins_with(version, version_len, "Version")) { + /* Chop off the "Version: " prefix */ + memmove(version, version + 9, version_len - 8); + break; + } } - info->bmp_type = BMP_TYPE_FTDI; } - ssize_t n_devs = libusb_get_device_list(info->libusb_ctx, &devs); - if (n_devs < 0) { - DEBUG_ERROR("libusb_get_device_list() failed"); - return -1; + libusb_free_config_descriptor(config); +} + +static bool process_cmsis_interface_probe( + libusb_device_descriptor_s *device_descriptor, libusb_device *device, probe_info_s **probe_list, bmp_info_s *info) +{ + (void)info; + /* Try to get the active configuration descriptor for the device */ + libusb_config_descriptor_s *config; + if (libusb_get_active_config_descriptor(device, &config) != 0) + return false; + + /* Try to open the device */ + libusb_device_handle *handle; + if (libusb_open(device, &handle) != 0) { + libusb_free_config_descriptor(config); + return false; } - bool report = false; - size_t found_debuggers; - struct libusb_device_descriptor desc; - char serial[64]; - char manufacturer[128]; - char product[128]; - bool access_problems = false; - char *active_cable = NULL; - bool ftdi_unknown = false; -rescan: - found_debuggers = 0; - serial[0] = 0; - manufacturer[0] = 0; - product[0] = 0; - access_problems = false; - active_cable = NULL; - ftdi_unknown = false; - for (size_t i = 0; devs[i]; ++i) { - libusb_device *dev = devs[i]; - int res = libusb_get_device_descriptor(dev, &desc); - if (res < 0) { - DEBUG_ERROR("libusb_get_device_descriptor() failed: %s", libusb_strerror(res)); - libusb_free_device_list(devs, 1); - continue; - } - /* Exclude hubs from testing. Probably more classes could be excluded here!*/ - switch (desc.bDeviceClass) { - case LIBUSB_CLASS_HUB: - case LIBUSB_CLASS_WIRELESS: - continue; - } - libusb_device_handle *handle = NULL; - res = libusb_open(dev, &handle); - if (res != LIBUSB_SUCCESS) { - if (!access_problems) { - DEBUG_INFO("Open USB %04x:%04x class %2x failed\n", desc.idVendor, desc.idProduct, desc.bDeviceClass); - access_problems = true; - } - continue; - } - /* If the device even has a serial number string, fetch it */ - if (desc.iSerialNumber) { - res = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, (uint8_t *)serial, sizeof(serial)); - /* If the call fails and it's not because the device gave us STALL, continue to the next one */ - if (res < 0 && res != LIBUSB_ERROR_PIPE) { - libusb_close(handle); + char read_string[128]; + + bool cmsis_dap = false; + for (size_t iface = 0; iface < config->bNumInterfaces && !cmsis_dap; ++iface) { + const libusb_interface_s *interface = &config->interface[iface]; + for (int descriptorIndex = 0; descriptorIndex < interface->num_altsetting; ++descriptorIndex) { + const libusb_interface_descriptor_s *descriptor = &interface->altsetting[0]; + uint8_t string_index = descriptor->iInterface; + if (string_index == 0) continue; + if (libusb_get_string_descriptor_ascii( + handle, string_index, (unsigned char *)read_string, sizeof(read_string)) < 0) + continue; /* We failed but that's a soft error at this point. */ + + if (strstr(read_string, "CMSIS") != NULL) { + char *version; + if (device_descriptor->idVendor == VENDOR_ID_ORBCODE && + device_descriptor->idProduct == PRODUCT_ID_ORBTRACE) { + orbtrace_read_version(device, handle, read_string, sizeof(read_string)); + version = strdup(read_string); + } else + version = strdup("---"); + char *serial; + if (device_descriptor->iSerialNumber == 0) + serial = strdup("Unknown serial number"); + else + serial = get_device_descriptor_string(handle, device_descriptor->iSerialNumber); + char *manufacturer; + if (device_descriptor->iManufacturer == 0) + manufacturer = strdup("Unknown manufacturer"); + else + manufacturer = get_device_descriptor_string(handle, device_descriptor->iManufacturer); + char *product; + if (device_descriptor->iProduct == 0) + product = strdup("Unknown product"); + else + product = get_device_descriptor_string(handle, device_descriptor->iProduct); + + *probe_list = probe_info_add_by_id(*probe_list, BMP_TYPE_CMSIS_DAP, device, device_descriptor->idVendor, + device_descriptor->idProduct, manufacturer, product, serial, version); + cmsis_dap = true; } - /* Device has no serial and that's ok. */ - if (res <= 0) - serial[0] = '\0'; - } else - serial[0] = '\0'; - if (cl_opts->opt_serial && !strstr(serial, cl_opts->opt_serial)) { - libusb_close(handle); + } + } + libusb_close(handle); + libusb_free_config_descriptor(config); + return cmsis_dap; +} + +static bool process_vid_pid_table_probe( + libusb_device_descriptor_s *device_descriptor, libusb_device *device, probe_info_s **probe_list) +{ + bool probe_added = false; + for (size_t index = 0; debugger_devices[index].type != BMP_TYPE_NONE; ++index) { + /* Check for a match, skip the entry if we don't get one */ + if (device_descriptor->idVendor != debugger_devices[index].vendor || + (device_descriptor->idProduct != debugger_devices[index].product && + debugger_devices[index].product != PRODUCT_ID_UNKNOWN)) continue; + + libusb_device_handle *handle = NULL; + /* Try to open the device */ + if (libusb_open(device, &handle) != LIBUSB_SUCCESS) + break; + + const bmp_type_t probe_type = get_type_from_vid_pid(device_descriptor->idVendor, device_descriptor->idProduct); + char *product = NULL; + char *manufacturer = NULL; + char *serial = NULL; + char *version = NULL; + /* + * If the probe has a custom string reader available, use it first. + * + * This will read and process any strings that need special work, e.g., extracting + * a version string from a product string (BMP native) + */ + if (debugger_devices[index].function != NULL) + debugger_devices[index].function( + device_descriptor, device, handle, &product, &manufacturer, &serial, &version); + + /* Now read any strings that have not been set by a custom reader function */ + if (product == NULL) + product = get_device_descriptor_string(handle, device_descriptor->iProduct); + if (manufacturer == NULL) + manufacturer = get_device_descriptor_string(handle, device_descriptor->iManufacturer); + if (serial == NULL) { + /* + * If this is a ST-Link v2, it does not report its serial number correctly, + * bypass trying to read it. + */ + if (device_descriptor->idVendor == VENDOR_ID_STLINK && device_descriptor->idProduct == PRODUCT_ID_STLINKV2) + serial = strdup("---"); + else + serial = get_device_descriptor_string(handle, device_descriptor->iSerialNumber); } - /* Attempt to get the manufacturer string */ - if (desc.iManufacturer) { - res = libusb_get_string_descriptor_ascii( - handle, desc.iManufacturer, (uint8_t *)manufacturer, sizeof(manufacturer)); - /* If the call fails and it's not because the device gave us STALL, continue to the next one */ - if (res < 0 && res != LIBUSB_ERROR_PIPE) { - DEBUG_ERROR("libusb_get_string_descriptor_ascii() call to fetch manufacturer string failed: %s\n", - libusb_strerror(res)); - libusb_close(handle); - continue; - } - /* Device has no manufacturer string and that's ok. */ - if (res <= 0) - manufacturer[0] = '\0'; - } else - manufacturer[0] = '\0'; - /* Attempt to get the product string */ - if (desc.iProduct) { - res = libusb_get_string_descriptor_ascii(handle, desc.iProduct, (uint8_t *)product, sizeof(product)); - /* If the call fails and it's not because the device gave us STALL, continue to the next one */ - if (res < 0 && res != LIBUSB_ERROR_PIPE) { - DEBUG_ERROR("libusb_get_string_descriptor_ascii() call to fetch product string failed: %s\n", - libusb_strerror(res)); - libusb_close(handle); - continue; - } - /* Device has no product string and that's ok. */ - if (res <= 0) - product[0] = '\0'; - } else - product[0] = '\0'; + + if (version == NULL) + version = strdup("---"); + + *probe_list = probe_info_add_by_id(*probe_list, probe_type, device, device_descriptor->idVendor, + device_descriptor->idProduct, manufacturer, product, serial, version); + probe_added = true; libusb_close(handle); - if (cl_opts->opt_ident_string) { - char *match_manu = NULL; - char *match_product = NULL; - match_manu = strstr(manufacturer, cl_opts->opt_ident_string); - match_product = strstr(product, cl_opts->opt_ident_string); - if (!match_manu && !match_product) - continue; + } + return probe_added; +} + +static const probe_info_s *scan_for_devices(bmp_info_s *info) +{ + /* + * If we are running on Windows the proprietary FTD2XX library is used + * to collect debugger information. + */ +#if defined(_WIN32) || defined(__CYGWIN__) + probe_info_s *probe_list = process_ftdi_probe(); + const bool skip_ftdi = probe_list != NULL; +#else + probe_info_s *probe_list = NULL; + const bool skip_ftdi = false; +#endif + + libusb_device **device_list; + const ssize_t cnt = libusb_get_device_list(info->libusb_ctx, &device_list); + if (cnt <= 0) + return probe_info_correct_order(probe_list); + /* Parse the list of USB devices found */ + for (size_t device_index = 0; device_list[device_index]; ++device_index) { + libusb_device *const device = device_list[device_index]; + libusb_device_descriptor_s device_descriptor; + const int result = libusb_get_device_descriptor(device, &device_descriptor); + if (result < 0) { + DEBUG_ERROR("Failed to get device descriptor (%d): %s\n", result, libusb_error_name(result)); + return NULL; } - /* Either serial and/or ident_string match or are not given. - * Check type.*/ - bmp_type_t type = BMP_TYPE_NONE; - if (desc.idVendor == VENDOR_ID_BMP) { - if (desc.idProduct == PRODUCT_ID_BMP) - type = BMP_TYPE_BMP; - else { - if (desc.idProduct == PRODUCT_ID_BMP_BL) - DEBUG_WARN("BMP in bootloader mode found. Restart or reflash!\n"); - continue; - } - } else if (find_cmsis_dap_interface(dev, info) == BMP_TYPE_CMSIS_DAP || strstr(manufacturer, "CMSIS") || - strstr(product, "CMSIS")) - type = BMP_TYPE_CMSIS_DAP; - else if (desc.idVendor == VENDOR_ID_STLINK) { - switch (desc.idProduct) { - case PRODUCT_ID_STLINKV2: - case PRODUCT_ID_STLINKV21: - case PRODUCT_ID_STLINKV21_MSD: - case PRODUCT_ID_STLINKV3_NO_MSD: - case PRODUCT_ID_STLINKV3_BL: - case PRODUCT_ID_STLINKV3: - case PRODUCT_ID_STLINKV3E: - type = BMP_TYPE_STLINK_V2; - break; - case PRODUCT_ID_STLINKV1: - DEBUG_WARN("STLINKV1 not supported\n"); - default: - continue; - } - } else if (desc.idVendor == VENDOR_ID_SEGGER) - type = BMP_TYPE_JLINK; - else { - const cable_desc_s *cable = cable_desc; - for (; cable->name; ++cable) { - bool found = false; - if (cable->vendor != desc.idVendor || cable->product != desc.idProduct) - continue; /* VID/PID do not match*/ - if (cl_opts->opt_cable) { - if (strncmp(cable->name, cl_opts->opt_cable, strlen(cable->name)) != 0) - continue; /* cable names do not match*/ - found = true; - } - if (cable->description) { - if (strncmp(cable->description, product, strlen(cable->description)) != 0) - continue; /* descriptions do not match*/ - found = true; - } else { /* VID/PID fits, but no cl_opts->opt_cable and no description*/ - if (cable->vendor == 0x0403 && /* FTDI*/ - (cable->product == 0x6010 || /* FT2232C/D/H*/ - cable->product == 0x6011 || /* FT4232H Quad HS USB-UART/FIFO IC */ - cable->product == 0x6014)) { /* FT232H Single HS USB-UART/FIFO IC */ - ftdi_unknown = true; - continue; /* Cable name is needed */ - } - } - if (found) { - active_cable = cable->name; - type = BMP_TYPE_FTDI; - break; - } - } - if (!cable->name) - continue; + if (device_descriptor.idVendor != VENDOR_ID_FTDI || !skip_ftdi) { + if (!process_vid_pid_table_probe(&device_descriptor, device, &probe_list)) + process_cmsis_interface_probe(&device_descriptor, device, &probe_list, info); } + } + libusb_free_device_list(device_list, (int)cnt); + return probe_info_correct_order(probe_list); +} - if (report) - DEBUG_WARN("%2zu: %s, %s, %s\n", found_debuggers + 1U, serial[0] ? serial : NO_SERIAL_NUMBER, manufacturer, - product); - - info->libusb_dev = dev; - info->vid = desc.idVendor; - info->pid = desc.idProduct; - info->bmp_type = type; - strncpy(info->serial, serial, sizeof(info->serial)); - strncpy(info->product, product, sizeof(info->product)); - strncpy(info->manufacturer, manufacturer, sizeof(info->manufacturer)); - if (cl_opts->opt_position && cl_opts->opt_position == found_debuggers + 1U) { - found_debuggers = 1; - break; - } - ++found_debuggers; +int find_debuggers(bmda_cli_options_s *cl_opts, bmp_info_s *info) +{ + if (cl_opts->opt_device) + return 1; + + const int result = libusb_init(&info->libusb_ctx); + if (result != LIBUSB_SUCCESS) { + DEBUG_ERROR("Failed to initialise libusb (%d): %s\n", result, libusb_error_name(result)); + return -1; } - if (found_debuggers == 0 && ftdi_unknown && !cl_opts->opt_cable) - DEBUG_WARN("Generic FTDI MPSSE VID/PID found. Please specify exact type with \"-c \" !\n"); - if (found_debuggers == 1U && !cl_opts->opt_cable && info->bmp_type == BMP_TYPE_FTDI) - cl_opts->opt_cable = active_cable; - if (!found_debuggers && cl_opts->opt_list_only) - DEBUG_ERROR("No usable debugger found\n"); - if (found_debuggers > 1U || (found_debuggers == 1U && cl_opts->opt_list_only)) { - if (!report) { - if (found_debuggers > 1U) - DEBUG_WARN("%zu debuggers found!\nSelect with -P or -s <(partial)serial no.>\n", found_debuggers); - report = true; - goto rescan; - } - if (found_debuggers > 0) - access_problems = false; - found_debuggers = 0; + + /* Scan for all possible probes on the system */ + const probe_info_s *probe_list = scan_for_devices(info); + if (!probe_list) { + DEBUG_WARN("No probes found\n"); + return -1; + } + /* Count up how many were found and filter the list for a match to the program options request */ + const size_t probes = probe_info_count(probe_list); + const probe_info_s *probe = NULL; + /* If there's just one probe and we didn't get match critera, pick it */ + if (probes == 1 && !cl_opts->opt_serial && !cl_opts->opt_position) + probe = probe_list; + else /* Otherwise filter the list */ + probe = probe_info_filter(probe_list, cl_opts->opt_serial, cl_opts->opt_position); + + /* If we found no matching probes, or we're in list-only mode */ + if (!probe || cl_opts->opt_list_only) { + DEBUG_WARN("Available Probes:\n"); + probe = probe_list; + DEBUG_WARN(" %-20s %-25s %-25s %s\n", "Name", "Serial #", "Manufacturer", "Version"); + for (size_t position = 1; probe; probe = probe->next, ++position) + DEBUG_WARN(" %2zu. %-20s %-25s %-25s %s\n", position, probe->product, probe->serial, probe->manufacturer, + probe->version); + probe_info_list_free(probe_list); + return 1; // false; + } + + /* We found a matching probe, populate bmp_info_s and signal success */ + DEBUG_WARN("Using: %-20s %-20s %-25s %s\n", probe->product, probe->serial, probe->manufacturer, probe->version); + probe_info_to_bmp_info(probe, info); + /* If the selected probe is an FTDI adapter try to resolve the adaptor type */ + if (probe->vid == VENDOR_ID_FTDI && !ftdi_lookup_adaptor_descriptor(cl_opts, probe)) { + // Don't know the cable type, ask user to specify with "-c" + DEBUG_WARN("Multiple FTDI adapters match Vendor and Product ID.\n"); + DEBUG_WARN("Please specify adapter type on command line using \"-c\" option.\n"); + return -1; //false } - if (!found_debuggers && access_problems) - DEBUG_ERROR("No debugger found. Please check access rights to USB devices!\n"); - if (info->libusb_dev) - libusb_ref_device(info->libusb_dev); - libusb_free_device_list(devs, 1); - return found_debuggers == 1U ? 0 : -1; + probe_info_list_free(probe_list); + return 0; // true; } /* diff --git a/src/platforms/hosted/cli.c b/src/platforms/hosted/cli.c index 78b1c63e703..dabb279f2c5 100644 --- a/src/platforms/hosted/cli.c +++ b/src/platforms/hosted/cli.c @@ -243,8 +243,12 @@ void cl_init(bmda_cli_options_s *opt, int argc, char **argv) switch (option) { case 'c': - if (optarg) - opt->opt_cable = optarg; + if (optarg) { + char *opt_pointer = optarg; + while (opt_pointer && *opt_pointer == ' ') + opt_pointer++; + opt->opt_cable = opt_pointer; + } break; case 'h': bmda_debug_flags |= BMD_DEBUG_INFO; diff --git a/src/platforms/hosted/ftdi_bmp.c b/src/platforms/hosted/ftdi_bmp.c index 5ec70761fce..e12c1375ce8 100644 --- a/src/platforms/hosted/ftdi_bmp.c +++ b/src/platforms/hosted/ftdi_bmp.c @@ -379,6 +379,55 @@ const cable_desc_s cable_desc[] = { {}, }; +/* + * Search the adapter descriptor table for probes matching the VID/PID for the given probe. + * If a single match is found, place the adapter descriptor pointer into the cl_opts structure + * and return true. Otherwise return false. + */ +bool ftdi_lookup_adapter_from_vid_pid(bmda_cli_options_s *const cl_opts, const probe_info_s *const probe) +{ + /* If the user entered a serial number, check if the attached probe is the right one */ + if (cl_opts->opt_serial && strstr(cl_opts->opt_serial, probe->serial)) + return true; + + /* If the user entered an adapter name use it */ + if (cl_opts->opt_cable) + return true; + + size_t adapter_count = 0; + const cable_desc_s *selection = NULL; + + for (const cable_desc_s *cable = &cable_desc[0]; cable->vendor; ++cable) { + if (cable->vendor == probe->vid && cable->product == probe->pid) { + ++adapter_count; + selection = cable; + } + } + /* If we've found only one adaptor, place the adapter name into cl_opts */ + if (adapter_count == 1) + cl_opts->opt_cable = selection->name; + return adapter_count == 1; +} + +bool ftdi_lookup_cable_by_product(bmda_cli_options_s *cl_opts, const char *product) +{ + if (cl_opts->opt_cable) + return false; + + for (const cable_desc_s *cable = &cable_desc[0]; cable->vendor; ++cable) { + if (cable->description && strstr(product, cable->description) != 0) { + cl_opts->opt_cable = cable->name; + return true; + } + } + return false; +} + +bool ftdi_lookup_adaptor_descriptor(bmda_cli_options_s *cl_opts, const probe_info_s *probe) +{ + return ftdi_lookup_cable_by_product(cl_opts, probe->product); +} + bool ftdi_bmp_init(bmda_cli_options_s *const cl_opts) { int err; @@ -396,7 +445,7 @@ bool ftdi_bmp_init(bmda_cli_options_s *const cl_opts) active_cable = *cable; memcpy(&active_state, &active_cable.init, sizeof(data_desc_s)); /* If the adaptor being used is Tigard, NULL the description out as libftdi can't deal with the partial match. */ - if (memcmp(active_cable.description, "Tigard", 7) == 0) + if (active_cable.description && memcmp(active_cable.description, "Tigard", 7) == 0) active_cable.description = NULL; /* * If swd_(read|write) is not given for the selected cable and diff --git a/src/platforms/hosted/ftdi_bmp.h b/src/platforms/hosted/ftdi_bmp.h index 05bb976bc99..693f37a04b3 100644 --- a/src/platforms/hosted/ftdi_bmp.h +++ b/src/platforms/hosted/ftdi_bmp.h @@ -31,6 +31,8 @@ #include "bmp_hosted.h" +#include "probe_info.h" + typedef struct data_desc { uint16_t data_low; uint16_t ddr_low; @@ -123,6 +125,8 @@ extern data_desc_s active_state; #define ftdi_buffer_read_val(value) ftdi_buffer_read(&(value), sizeof(value)) bool ftdi_bmp_init(bmda_cli_options_s *cl_opts); +bool ftdi_lookup_adapter_from_vid_pid(bmda_cli_options_s *cl_opts, const probe_info_s *probe); +bool ftdi_lookup_adaptor_descriptor(bmda_cli_options_s *cl_opts, const probe_info_s *probe); bool ftdi_swd_init(void); bool ftdi_jtag_init(void); void ftdi_buffer_flush(void); diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c index c446dfaa640..20e64299919 100644 --- a/src/platforms/hosted/platform.c +++ b/src/platforms/hosted/platform.c @@ -82,6 +82,10 @@ static void exit_function(void) #ifdef ENABLE_RTT rtt_if_exit(); +#endif +#if HOSTED_BMP_ONLY == 0 + if (info.libusb_ctx) + libusb_exit(info.libusb_ctx); #endif fflush(stdout); } diff --git a/src/platforms/hosted/platform.h b/src/platforms/hosted/platform.h index 58308b7e077..dde876bbbdb 100644 --- a/src/platforms/hosted/platform.h +++ b/src/platforms/hosted/platform.h @@ -65,7 +65,16 @@ void platform_buffer_flush(void); #define PRODUCT_ID_STLINKV3 0x374fU #define PRODUCT_ID_STLINKV3E 0x374eU -#define VENDOR_ID_SEGGER 0x1366U +#define VENDOR_ID_SEGGER 0x1366U +#define PRODUCT_ID_UNKNOWN 0xffffU + +#define VENDOR_ID_FTDI 0x0403U +#define PRODUCT_ID_FTDI_FT2232 0x6010U +#define PRODUCT_ID_FTDI_FT4232 0x6011U +#define PRODUCT_ID_FTDI_FT232 0x6014U + +#define VENDOR_ID_ORBCODE 0x1209U +#define PRODUCT_ID_ORBTRACE 0x3443U typedef enum bmp_type_e { BMP_TYPE_NONE = 0, diff --git a/src/platforms/hosted/probe_info.c b/src/platforms/hosted/probe_info.c index 8ab734d3cf5..ae18654ef5e 100644 --- a/src/platforms/hosted/probe_info.c +++ b/src/platforms/hosted/probe_info.c @@ -38,12 +38,15 @@ probe_info_s *probe_info_add_by_serial(probe_info_s *const list, const bmp_type_t type, const char *const mfr, const char *const product, const char *const serial, const char *const version) { - return probe_info_add_by_id(list, type, 0, 0, mfr, product, serial, version); + return probe_info_add_by_id(list, type, NULL, 0, 0, mfr, product, serial, version); } -probe_info_s *probe_info_add_by_id(probe_info_s *const list, const bmp_type_t type, uint16_t vid, uint16_t pid, - const char *const mfr, const char *const product, const char *const serial, const char *const version) +probe_info_s *probe_info_add_by_id(probe_info_s *const list, const bmp_type_t type, libusb_device *device, uint16_t vid, + uint16_t pid, const char *const mfr, const char *const product, const char *const serial, const char *const version) { +#if HOSTED_BMP_ONLY == 1 + (void)device; +#endif probe_info_s *probe_info = malloc(sizeof(*probe_info)); if (!probe_info) { DEBUG_INFO("Fatal: Failed to allocate memory for a probe info structure\n"); @@ -53,6 +56,12 @@ probe_info_s *probe_info_add_by_id(probe_info_s *const list, const bmp_type_t ty probe_info->type = type; probe_info->vid = vid; probe_info->pid = pid; +#if HOSTED_BMP_ONLY == 0 + if (device != NULL) + probe_info->device = libusb_ref_device(device); + else + probe_info->device = NULL; +#endif probe_info->manufacturer = mfr; probe_info->product = product; probe_info->serial = serial; @@ -72,6 +81,10 @@ size_t probe_info_count(const probe_info_s *const list) void probe_info_free(probe_info_s *const probe_info) { +#if HOSTED_BMP_ONLY == 0 + if (probe_info->device) + libusb_unref_device(probe_info->device); +#endif free((void *)probe_info->manufacturer); free((void *)probe_info->product); free((void *)probe_info->serial); @@ -135,4 +148,8 @@ void probe_info_to_bmp_info(const probe_info_s *const probe, bmp_info_s *info) DEBUG_ERROR("Probe descriptor string '%s (%s)' exceeds allowable manufacturer description length\n", probe->product, probe->manufacturer); } +#if HOSTED_BMP_ONLY == 0 + if (probe->device) + info->libusb_dev = libusb_ref_device(probe->device); +#endif } diff --git a/src/platforms/hosted/probe_info.h b/src/platforms/hosted/probe_info.h index 5a84376dfea..08aa4f312f3 100644 --- a/src/platforms/hosted/probe_info.h +++ b/src/platforms/hosted/probe_info.h @@ -38,10 +38,17 @@ #include "platform.h" #include "bmp_hosted.h" +#if HOSTED_BMP_ONLY == 1 +typedef struct usb_device libusb_device; +#endif + typedef struct probe_info { bmp_type_t type; uint16_t vid; uint16_t pid; +#if HOSTED_BMP_ONLY == 0 + libusb_device *device; +#endif const char *manufacturer; const char *product; const char *serial; @@ -52,8 +59,8 @@ typedef struct probe_info { probe_info_s *probe_info_add_by_serial( probe_info_s *list, bmp_type_t type, const char *mfr, const char *product, const char *serial, const char *version); -probe_info_s *probe_info_add_by_id(probe_info_s *const list, const bmp_type_t type, uint16_t vid, uint16_t pid, - const char *const mfr, const char *const product, const char *const serial, const char *const version); +probe_info_s *probe_info_add_by_id(probe_info_s *list, bmp_type_t type, libusb_device *device, uint16_t vid, + uint16_t pid, const char *mfr, const char *product, const char *serial, const char *version); size_t probe_info_count(const probe_info_s *list); void probe_info_list_free(const probe_info_s *list); diff --git a/src/platforms/hosted/windows/ftdi.c b/src/platforms/hosted/windows/ftdi.c new file mode 100644 index 00000000000..aa7f36b3cb5 --- /dev/null +++ b/src/platforms/hosted/windows/ftdi.c @@ -0,0 +1,170 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2022-2023 1BitSquared + * Copyright (C) 2023 Sid Price + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "general.h" +#include "ftdi.h" +#include "ftd2xx.h" +#include "bmp_hosted.h" + +FT_HANDLE ftdi_handle; + +/* + * The following structure is mocked by this module. FTD2XX + * does not provide a similar structure. + * + * Values mocked: + * ftdi_ctx.type - The type of FTDI chip in the adapter + */ + +/* Used to fake the libusb context and pass required parameters back to the caller */ +static ftdi_context_s ftdi_ctx = {0}; + +/* + * This array is used to map FTD2XX device type identifiers + * to libftdi identifiers. The array is ordered by the FTD2XX + * values, with the array entries being the libftdi values + */ +static const int ftdi_chip_types[] = { + TYPE_AM, + TYPE_BM, + -1, // FT_DEVICE_100AX not supported + -2, // Unknown type + TYPE_2232C, + TYPE_R, + TYPE_2232H, + TYPE_4232H, + TYPE_232H, + TYPE_230X, +}; + +static const size_t number_of_ftdi_chip_types = ARRAY_LENGTH(ftdi_chip_types); + +#define READ_TIMEOUT 500 // Expressed in milliseconds +#define WRITE_TIMEOUT 500 + +struct ftdi_context *ftdi_new(void) +{ + return &ftdi_ctx; // Just need to fake the structure being created +} + +int ftdi_set_interface(ftdi_context_s *ftdi, enum ftdi_interface interface) +{ + (void)ftdi; + /* + * FTD2XX needs a qualified serial number to open the correct device. Append + * an interface letter to the serial number by adding the number to 'A' + */ + char serial_number[16] = {0}; + strcpy(serial_number, info.serial); + serial_number[strlen(serial_number)] = 'A' + (interface - 1); + + if (FT_OpenEx(serial_number, FT_OPEN_BY_SERIAL_NUMBER, &ftdi_handle) != FT_OK || + FT_SetTimeouts(ftdi_handle, READ_TIMEOUT, WRITE_TIMEOUT) != FT_OK) + return 0; + + FT_DEVICE device; + DWORD device_id = 0; + char description[64] = {'\0'}; + if (FT_GetDeviceInfo(ftdi_handle, &device, &device_id, serial_number, description, NULL) != FT_OK) + return 0; + + const size_t device_type_index = device; + if (device_type_index < number_of_ftdi_chip_types) + ftdi_ctx.type = ftdi_chip_types[device_type_index]; + return 0; +} + +int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product, const char *description, const char *serial) +{ + (void)ftdi; + (void)vendor; + (void)product; + (void)description; + (void)serial; + return 0; +} + +int ftdi_usb_close(struct ftdi_context *ftdi) +{ + (void)ftdi; + if (FT_Close(ftdi_handle) != FT_OK) + return -1; + return 0; +} + +void ftdi_free(struct ftdi_context *ftdi) +{ + (void)ftdi; +} + +int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate) +{ + (void)ftdi; + return FT_SetBaudRate(ftdi_handle, baudrate) != FT_OK; +} + +int ftdi_set_latency_timer(struct ftdi_context *ftdi, unsigned char latency) +{ + (void)ftdi; + return FT_SetLatencyTimer(ftdi_handle, latency) != FT_OK; +} + +int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode) +{ + (void)ftdi; + return FT_SetBitMode(ftdi_handle, bitmask, mode) != FT_OK; +} + +int ftdi_usb_purge_buffers(struct ftdi_context *ftdi) +{ + (void)ftdi; + return FT_Purge(ftdi_handle, FT_PURGE_RX | FT_PURGE_TX) != FT_OK; +} + +int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, const int size) +{ + (void)ftdi; + DWORD bytes_read = 0; + if (FT_Read(ftdi_handle, buf, (DWORD)size, &bytes_read) == FT_OK && bytes_read != (DWORD)size) + return 0; // Signal read timeout + return bytes_read; +} + +int ftdi_write_data(struct ftdi_context *ftdi, const unsigned char *buf, int size) +{ + (void)ftdi; + DWORD bytes_written; + if (FT_Write(ftdi_handle, (unsigned char *)buf, size, &bytes_written) != FT_OK) + return 0; + return bytes_written; +} + +int ftdi_write_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize) +{ + (void)ftdi; + (void)chunksize; + return 0; +} + +const char *ftdi_get_error_string(struct ftdi_context *ftdi) +{ + (void)ftdi; + return "Error in ftdi.c (Windows)"; +} diff --git a/src/platforms/hosted/windows/ftdi.h b/src/platforms/hosted/windows/ftdi.h new file mode 100644 index 00000000000..fa20f8fc1b8 --- /dev/null +++ b/src/platforms/hosted/windows/ftdi.h @@ -0,0 +1,205 @@ +/* + * This file is part of the Black Magic Debug project. + * + * Copyright (C) 2011 Black Sphere Technologies Ltd. + * Copyright (C) 2018 Uwe Bonnes(bon@elektron.ikp.physik.tu-darmstadt.de) + * Written by Gareth McMullin + * Copyright (C) 2022-2023 1BitSquared + * Originated by Sid Price + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef PLATFORMS_HOSTED_WINDOWS_FTDI +#define PLATFORMS_HOSTED_WINDOWS_FTDI + +/** Port interface for chips with multiple interfaces */ +enum ftdi_interface { + INTERFACE_ANY = 0, + INTERFACE_A = 1, + INTERFACE_B = 2, + INTERFACE_C = 3, + INTERFACE_D = 4 +}; + +/** Automatic loading / unloading of kernel modules */ +enum ftdi_module_detach_mode { + AUTO_DETACH_SIO_MODULE = 0, + DONT_DETACH_SIO_MODULE = 1, + AUTO_DETACH_REATACH_SIO_MODULE = 2 +}; + +/* FTDI MPSSE commands */ +#define SET_BITS_LOW 0x80U +/*BYTE DATA*/ +/*BYTE Direction*/ +#define SET_BITS_HIGH 0x82U +/*BYTE DATA*/ +/*BYTE Direction*/ +#define GET_BITS_LOW 0x81U +#define GET_BITS_HIGH 0x83U +#define LOOPBACK_START 0x84U +#define LOOPBACK_END 0x85U +#define TCK_DIVISOR 0x86U +/* H Type specific commands */ +#define DIS_DIV_5 0x8aU +#define EN_DIV_5 0x8bU +#define EN_3_PHASE 0x8cU +#define DIS_3_PHASE 0x8dU +#define CLK_BITS 0x8eU +#define CLK_BYTES 0x8fU +#define CLK_WAIT_HIGH 0x94U +#define CLK_WAIT_LOW 0x95U +#define EN_ADAPTIVE 0x96U +#define DIS_ADAPTIVE 0x97U +#define CLK_BYTES_OR_HIGH 0x9cU +#define CLK_BYTES_OR_LOW 0x9dU +/*FT232H specific commands */ +#define DRIVE_OPEN_COLLECTOR 0x9eU +/* Value Low */ +/* Value HIGH */ /*rate is 12000000/((1+value)*2) */ +#define DIV_VALUE(rate) ((rate) > 6000000U) ? 0U : ((6000000U / (rate)-1U) > 0xffffU) ? 0xffffU : (6000000U / (rate)-1U) + +/* Commands in MPSSE and Host Emulation Mode */ +#define SEND_IMMEDIATE 0x87U +#define WAIT_ON_HIGH 0x88U +#define WAIT_ON_LOW 0x89U + +/* Commands in Host Emulation Mode */ +#define READ_SHORT 0x90U +/* Address_Low */ +#define READ_EXTENDED 0x91U +/* Address High */ +/* Address Low */ +#define WRITE_SHORT 0x92U +/* Address_Low */ +#define WRITE_EXTENDED 0x93U + +/* Address High */ +/* Address Low */ + +/* Shifting commands IN MPSSE Mode*/ +#define MPSSE_WRITE_NEG 0x01U /* Write TDI/DO on negative TCK/SK edge*/ +#define MPSSE_BITMODE 0x02U /* Write bits, not bytes */ +#define MPSSE_READ_NEG 0x04U /* Sample TDO/DI on negative TCK/SK edge */ +#define MPSSE_LSB 0x08U /* LSB first */ +#define MPSSE_DO_WRITE 0x10U /* Write TDI/DO */ +#define MPSSE_DO_READ 0x20U /* Read TDO/DI */ +#define MPSSE_WRITE_TMS 0x40U /* Write TMS/CS */ + +/** MPSSE bitbang modes */ +enum ftdi_mpsse_mode { + BITMODE_RESET = 0x00, /**< switch off bitbang mode, back to regular serial/FIFO */ + BITMODE_BITBANG = 0x01, /**< classical asynchronous bitbang mode, introduced with B-type chips */ + BITMODE_MPSSE = 0x02, /**< MPSSE mode, available on 2232x chips */ + BITMODE_SYNCBB = 0x04, /**< synchronous bitbang mode, available on 2232x and R-type chips */ + BITMODE_MCU = 0x08, /**< MCU Host Bus Emulation mode, available on 2232x chips */ + /* CPU-style fifo mode gets set via EEPROM */ + BITMODE_OPTO = 0x10, /**< Fast Opto-Isolated Serial Interface Mode, available on 2232x chips */ + BITMODE_CBUS = 0x20, /**< Bitbang on CBUS pins of R-type chips, configure in EEPROM before */ + BITMODE_SYNCFF = 0x40, /**< Single Channel Synchronous FIFO mode, available on 2232H chips */ + BITMODE_FT1284 = 0x80, /**< FT1284 mode, available on 232H chips */ +}; + +/** FTDI chip type */ +enum ftdi_chip_type { + TYPE_AM = 0, + TYPE_BM = 1, + TYPE_2232C = 2, + TYPE_R = 3, + TYPE_2232H = 4, + TYPE_4232H = 5, + TYPE_232H = 6, + TYPE_230X = 7, +}; + +/* + * Main context structure for all FTD2xx functions. + * Do not access directly if possible. +*/ +struct ftdi_context { + /* USB specific */ + /** libusb's context */ + struct libusb_context *usb_ctx; + /** libusb's usb_dev_handle */ + struct libusb_device_handle *usb_dev; + /** usb read timeout */ + int usb_read_timeout; + /** usb write timeout */ + int usb_write_timeout; + + /* FTDI specific */ + /** FTDI chip type */ + enum ftdi_chip_type type; + /** baudrate */ + int baudrate; + /** bitbang mode state */ + unsigned char bitbang_enabled; + /** pointer to read buffer for ftdi_read_data */ + unsigned char *readbuffer; + /** read buffer offset */ + unsigned int readbuffer_offset; + /** number of remaining data in internal read buffer */ + unsigned int readbuffer_remaining; + /** read buffer chunk size */ + unsigned int readbuffer_chunksize; + /** write buffer chunk size */ + unsigned int writebuffer_chunksize; + /** maximum packet size. Needed for filtering modem status bytes every n packets. */ + unsigned int max_packet_size; + + /* FTDI FT2232C requirecments */ + /** FT2232C interface number: 0 or 1 */ + int interface; /* 0 or 1 */ + /** FT2232C index number: 1 or 2 */ + int index; /* 1 or 2 */ + /* Endpoints */ + /** FT2232C end points: 1 or 2 */ + int in_ep; + int out_ep; /* 1 or 2 */ + + /** Bitbang mode. 1: (default) Normal bitbang mode, 2: FT2232C SPI bitbang mode */ + unsigned char bitbang_mode; + + /** Decoded eeprom structure */ + struct ftdi_eeprom *eeprom; + + /** String representation of last error */ + const char *error_str; + + /** Defines behavior in case a kernel module is already attached to the device */ + enum ftdi_module_detach_mode module_detach_mode; +}; + +struct ftdi_context *ftdi_new(void); +int ftdi_set_interface(struct ftdi_context *ftdi, enum ftdi_interface interface); +int ftdi_set_baudrate(struct ftdi_context *ftdi, int baudrate); + +int ftdi_usb_open_desc(struct ftdi_context *ftdi, int vendor, int product, const char *description, const char *serial); +int ftdi_usb_close(struct ftdi_context *ftdi); +void ftdi_free(struct ftdi_context *ftdi); + +int ftdi_usb_purge_buffers(struct ftdi_context *ftdi); + +int ftdi_set_latency_timer(struct ftdi_context *ftdi, unsigned char latency); +int ftdi_set_bitmode(struct ftdi_context *ftdi, unsigned char bitmask, unsigned char mode); + +int ftdi_read_data(struct ftdi_context *ftdi, unsigned char *buf, int size); + +int ftdi_write_data(struct ftdi_context *ftdi, const unsigned char *buf, int size); +int ftdi_write_data_set_chunksize(struct ftdi_context *ftdi, unsigned int chunksize); + +const char *ftdi_get_error_string(struct ftdi_context *ftdi); + +#endif // PLATFORMS_HOSTED_WINDOWS_FTDI