This is an automated email from Gerrit.

"reito <cnschwar...@qq.com>" just uploaded a new patch set to Gerrit, which you 
can find at https://review.openocd.org/c/openocd/+/7692

-- gerrit

commit 27a29109b68907a7158160b60e6ae8a9c62a6f3a
Author: reito <cnschwar...@qq.com>
Date:   Thu May 18 12:47:23 2023 +0800

    target: Add support for CH347 JTAG chip
    
    CH347 is a USB-JTAG chip
    https://www.wch.cn/products/CH347.html
    This patch use the official OpenOCD implementation from
    https://github.com/WCHSoftGroup/ch347
    
    Change-Id: I90b2574919e7c007bea3cf0a22ac23bc15938874
    Signed-off-by: cnSchwarzer <cnschwar...@qq.com>

diff --git a/configure.ac b/configure.ac
index eee42d4240..c31b216211 100644
--- a/configure.ac
+++ b/configure.ac
@@ -115,6 +115,7 @@ m4_define([ADAPTER_OPT], [m4_translit(ADAPTER_ARG($1), [_], 
[-])])
 
 m4_define([USB1_ADAPTERS],
        [[[ftdi], [MPSSE mode of FTDI based devices], [FTDI]],
+  [[ch347], [Mode 3 of the CH347 devices], [CH347]],
        [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]],
        [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]],
        [[ulink], [Keil ULINK JTAG Programmer], [ULINK]],
@@ -178,6 +179,16 @@ AC_SUBST([doxygen_as_pdf])
 AC_MSG_CHECKING([whether to build Doxygen as PDF])
 AC_MSG_RESULT([$doxygen_as_pdf])
 
+AC_ARG_ENABLE([ch347],
+     AS_HELP_STRING([--enable-ch347], [Enable building support for CH347]),
+     [build_ch347=$enableval], [build_ch347=no])
+AS_IF([test "x$build_ch347" = "xyes"], [
+      AC_DEFINE([BUILD_CH347], [1], [1 if you want CH347.])
+     ], [
+       AC_DEFINE([BUILD_CH347], [0], [0 if you don't want CH347.])
+     ])
+AM_CONDITIONAL([CH347], [test "x$build_ch347" = "xyes"])
+
 AC_ARG_ENABLE([gccwarnings],
   AS_HELP_STRING([--disable-gccwarnings], [Disable compiler warnings]),
   [gcc_warnings=$enableval], [gcc_warnings=yes])
diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am
index 6410f37545..3f02735c27 100644
--- a/src/jtag/drivers/Makefile.am
+++ b/src/jtag/drivers/Makefile.am
@@ -70,6 +70,9 @@ DRIVERFILES += %D%/dummy.c
 endif
 if FTDI
 DRIVERFILES += %D%/ftdi.c %D%/mpsse.c
+endif 
+if CH347
+DRIVERFILES += %D%/ch347_jtag.c
 endif
 if LINUXGPIOD
 DRIVERFILES += %D%/linuxgpiod.c
diff --git a/src/jtag/drivers/ch347.c b/src/jtag/drivers/ch347.c
new file mode 100644
index 0000000000..5bbe69e306
--- /dev/null
+++ b/src/jtag/drivers/ch347.c
@@ -0,0 +1,844 @@
+/***************************************************************************   
                                                                  *
+ *   Driver for CH347-JTAG interface V1.0                                  *
+ *                                                                         *
+ *   Copyright (C) 2022 Nanjing Qinheng Microelectronics Co., Ltd.         *
+ *   Web: http://wch.cn                                                    *
+ *   Author: WCH@TECH53 <t...@wch.cn>                                      *
+ *                                                                         *
+ *   CH347 is a high-speed USB bus converter chip that provides UART, I2C  *
+ *   and SPI synchronous serial ports and JTAG interface through USB bus.  * 
+ *                                                                         *
+ *   The USB2.0 to JTAG scheme based on CH347 can be used to build         *
+ *   customized USB high-speed JTAG debugger and other products.           *   
                                                       
+ *                                                                         *
+ *   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 2 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 <http://www.gnu.org/licenses/>. *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if IS_CYGWIN == 1
+#include "windows.h"
+#undef LOG_ERROR
+#endif
+
+/* project specific includes */
+#include <jtag/interface.h>
+#include <jtag/commands.h>
+#include <helper/time_support.h>
+#include <helper/replacements.h>
+
+/* system includes */
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#define JTAGIO_STA_OUT_TDI (0x10)
+#define JTAGIO_STA_OUT_TMS (0x02)
+#define JTAGIO_STA_OUT_TCK (0x01)
+
+#define TDI_H JTAGIO_STA_OUT_TDI
+#define TDI_L 0
+#define TMS_H JTAGIO_STA_OUT_TMS
+#define TMS_L 0
+#define TCK_H JTAGIO_STA_OUT_TCK
+#define TCK_L 0
+
+#define KHZ(n) ((n)*UINT64_C(1000))
+#define MHZ(n) ((n)*UINT64_C(1000000))
+#define GHZ(n) ((n)*UINT64_C(1000000000))
+
+#define HW_TDO_BUF_SIZE              4096
+#define SF_PACKET_BUF_SIZE           51200 //命令包长度
+#define UCMDPKT_DATA_MAX_BYTES_USBHS 507   // USB高速时每个命令包内包含数据长度
+#define USBC_PACKET_USBHS            512   // USB高速时单包最大数据长度
+
+#define CH347_CMD_HEADER 3 //协议包头长度
+
+// 协议传输格式:CMD(1字节)+ Length(2字节)+ Data
+#define CH347_CMD_INFO_RD            0xCA //参数获取,用于获取固件版本、JTAG接口相关参数等
+#define CH347_CMD_JTAG_INIT          0xD0 // JTAG接口初始化命令
+#define CH347_CMD_JTAG_BIT_OP        0xD1 // JTAG接口引脚位控制命令
+#define CH347_CMD_JTAG_BIT_OP_RD     0xD2 // JTAG接口引脚位控制并读取命令
+#define CH347_CMD_JTAG_DATA_SHIFT    0xD3 // JTAG接口数据移位命令
+#define CH347_CMD_JTAG_DATA_SHIFT_RD 0xD4 // JTAG接口数据移位并读取命令
+
+#pragma pack(1)
+
+typedef struct _CH347_info { // 记录CH347引脚状态
+    int TMS;
+    int TDI;
+    int TCK;
+
+    int buffer_idx;
+    UCHAR buffer[HW_TDO_BUF_SIZE];
+} _CH347_Info;
+
+#pragma pack()
+
+#ifdef _WIN32
+#include <windows.h>
+typedef int(__stdcall *pCH347OpenDevice)(unsigned long iIndex);
+typedef void(__stdcall *pCH347CloseDevice)(unsigned long iIndex);
+typedef unsigned long(__stdcall *pCH347SetTimeout)(unsigned long iIndex,       
 // 指定设备序号
+                                                   unsigned long 
iWriteTimeout, // 指定USB写出数据块的超时时间,以毫秒mS为单位,0xFFFFFFFF指定不超时(默认值)
+                                                   unsigned long 
iReadTimeout); // 指定USB读取数据块的超时时间,以毫秒mS为单位,0xFFFFFFFF指定不超时(默认值)
+typedef unsigned long(__stdcall *pCH347WriteData)(unsigned long iIndex,        
 // 指定设备序号
+                                                  void *oBuffer,               
 // 指向一个足够大的缓冲区,用于保存描述符
+                                                  unsigned long *ioLength);    
 // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
+typedef unsigned long(__stdcall *pCH347ReadData)(unsigned long iIndex,         
 // 指定设备序号
+                                                 void *oBuffer,                
 // 指向一个足够大的缓冲区,用于保存描述符
+                                                 unsigned long *ioLength);     
 // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
+typedef unsigned long(__stdcall *pCH347Jtag_INIT)(unsigned long iIndex,        
 // 指定设备序号
+                                                  unsigned char iClockRate);   
 // 指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
+HMODULE uhModule;
+BOOL ugOpen;
+unsigned long ugIndex;
+pCH347OpenDevice upOpenDev;
+pCH347CloseDevice upCloseDev;
+pCH347SetTimeout upSetTimeout;
+pCH347ReadData upReadData;
+pCH347WriteData upWriteData;
+pCH347Jtag_INIT upJtagInit;
+#endif
+
+bool DevIsOpened; // 设备是否打开
+bool UsbHighDev = true;
+unsigned long USBC_PACKET;
+
+_CH347_Info ch347 = {0, 0, 0, 0, ""}; // 初始化设备结构状态
+
+/**
+ *  HexToString - Hex转换字符串函数
+ *  @param buf    指向一个缓冲区,放置准备转换的Hex数据
+ *  @param size   指向需要转换数据的长度单元
+ *
+ *  @return      返回转换后字符串
+ */
+static char *HexToString(uint8_t *buf, unsigned int size)
+{
+    unsigned int i;
+    char *str = calloc(size * 2 + 1, 1);
+
+    for (i = 0; i < size; i++)
+        sprintf(str + 2 * i, "%02x ", buf[i]);
+    return str;
+}
+
+/**
+ *  CH347_Write - CH347 写方法
+ *  @param oBuffer    指向一个缓冲区,放置准备写出的数据
+ *  @param ioLength   指向长度单元,输入时为准备写出的长度,返回后为实际写出的长度
+ *
+ *  @return              写成功返回1,失败返回0
+ */
+static int CH347_Write(void *oBuffer, unsigned long *ioLength)
+{
+    int ret = -1;
+    unsigned long wlength = *ioLength, WI;
+
+    if (*ioLength >= HW_TDO_BUF_SIZE)
+        wlength = HW_TDO_BUF_SIZE;
+    WI = 0;
+    while (1) {
+        ret = upWriteData(ugIndex, oBuffer + WI, &wlength);
+        LOG_DEBUG_IO("(size=%d, buf=[%s]) -> %" PRIu32, wlength, 
HexToString((uint8_t *)oBuffer, wlength), wlength);
+        WI += wlength;
+        if (WI >= *ioLength)
+            break;
+        if ((*ioLength - WI) > HW_TDO_BUF_SIZE)
+            wlength = HW_TDO_BUF_SIZE;
+        else
+            wlength = *ioLength - WI;
+    }
+
+    *ioLength = WI;
+    return ret;
+}
+
+/**
+ * CH347_Read - CH347 读方法
+ * @param oBuffer      指向一个足够大的缓冲区,用于保存读取的数据
+ * @param ioLength     指向长度单元,输入时为准备读取的长度,返回后为实际读取的长度
+ *
+ * @return                     读成功返回1,失败返回0
+ */
+static int CH347_Read(void *oBuffer, unsigned long *ioLength)
+{
+    unsigned long rlength = *ioLength;
+    // 单次读取最大允许读取4096B数据,超过则按4096B进行计算
+    if (rlength > HW_TDO_BUF_SIZE)
+        rlength = HW_TDO_BUF_SIZE;
+
+    if (!upReadData(ugIndex, oBuffer, &rlength)) {
+        LOG_ERROR("CH347_Read read data failure.");
+        return false;
+    }
+
+    LOG_DEBUG_IO("(size=%d, buf=[%s]) -> %" PRIu32, rlength, 
HexToString((uint8_t *)oBuffer, rlength), rlength);
+    *ioLength = rlength;
+    return true;
+}
+
+/**
+ * CH347_ClockTms - 功能函数,用于在TCK的上升沿改变TMS值,使其Tap状态切换
+ * @param BitBangPkt   协议包
+ * @param tms                  需要改变的TMS值
+ * @param BI                   协议包长度
+ *
+ * @return                             返回协议包长度
+ */
+static unsigned long CH347_ClockTms(unsigned char *BitBangPkt, int tms, 
unsigned long BI)
+{
+    unsigned char cmd = 0;
+
+    if (tms == 1)
+        cmd = TMS_H;
+    else
+        cmd = TMS_L;
+
+    BitBangPkt[BI++] = cmd | TDI_H | TCK_L;
+    BitBangPkt[BI++] = cmd | TDI_H | TCK_H;
+
+    ch347.TMS = cmd;
+    ch347.TDI = TDI_H;
+    ch347.TCK = TCK_H;
+
+    return BI;
+}
+
+/**
+ * CH347_IdleClock - 功能函数,确保时钟处于拉低状态
+ * @param BitBangPkt    协议包
+ * @param BI                    协议包长度
+ *
+ * @return                              返回协议包长度
+ */
+static unsigned long CH347_IdleClock(unsigned char *BitBangPkt, unsigned long 
BI)
+{
+    unsigned char byte = 0;
+    byte |= ch347.TMS ? TMS_H : TMS_L;
+    byte |= ch347.TDI ? TDI_H : TDI_L;
+    BitBangPkt[BI++] = byte;
+
+    return BI;
+}
+
+/**
+ * CH347_TmsChange - 功能函数,通过改变TMS的值来进行状态切换
+ * @param tmsValue              需要进行切换的TMS值按切换顺序组成一字节数据
+ * @param step                          需要读取tmsValue值的位值数
+ * @param skip                          从tmsValue的skip位处开始计数到step
+ *
+ */
+static void CH347_TmsChange(const unsigned char *tmsValue, int step, int skip)
+{
+    int i;
+    unsigned long BI, retlen, TxLen;
+    unsigned char BitBangPkt[4096] = "";
+
+    BI = CH347_CMD_HEADER;
+    retlen = CH347_CMD_HEADER;
+    LOG_DEBUG_IO("(TMS Value: %02x..., step = %d, skip = %d)", tmsValue[0], 
step, skip);
+
+    for (i = skip; i < step; i++) {
+        retlen = CH347_ClockTms(BitBangPkt, (tmsValue[i / 8] >> (i % 8)) & 
0x01, BI);
+        BI = retlen;
+    }
+    BI = CH347_IdleClock(BitBangPkt, BI);
+    BitBangPkt[0] = CH347_CMD_JTAG_BIT_OP;
+    BitBangPkt[1] = (unsigned char)BI - CH347_CMD_HEADER;
+    BitBangPkt[2] = 0;
+
+    TxLen = BI;
+
+    if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) {
+        LOG_ERROR("JTAG Write send usb data failure.");
+        return NULL;
+    }
+}
+
+/**
+ * CH347_TMS - 由ch347_execute_queue调用
+ * @param cmd     上层传递命令参数
+ *
+ */
+static void CH347_TMS(struct tms_command *cmd)
+{
+    LOG_DEBUG_IO("(step: %d)", cmd->num_bits);
+    CH347_TmsChange(cmd->bits, cmd->num_bits, 0);
+}
+
+/**
+ * CH347_Reset - CH347 复位Tap状态函数
+ * @brief      连续六个以上TCK且TMS为高将可将状态机置为Test-Logic Reset状态
+ *
+ */
+static int CH347_Reset()
+{
+    unsigned char BitBang[512] = "", BI, i;
+    unsigned long TxLen;
+
+    BI = CH347_CMD_HEADER;
+    for (i = 0; i < 7; i++) {
+        BitBang[BI++] = TMS_H | TDI_H | TCK_L;
+        BitBang[BI++] = TMS_H | TDI_H | TCK_H;
+    }
+    BitBang[BI++] = TMS_H | TDI_H | TCK_L;
+
+    BitBang[0] = CH347_CMD_JTAG_BIT_OP;
+    BitBang[1] = BI - CH347_CMD_HEADER;
+    BitBang[2] = 0;
+
+    TxLen = BI;
+
+    if (!CH347_Write(BitBang, &TxLen) && (TxLen != BI)) {
+        LOG_ERROR("JTAG_Init send usb data failure.");
+        return false;
+    }
+    return true;
+}
+
+/**
+ * CH347_MovePath - 获取当前Tap状态并切换至cmd传递下去的状态TMS值
+ * @param cmd 上层传递命令参数
+ *
+ */
+static void CH347_MovePath(struct pathmove_command *cmd)
+{
+    int i;
+    unsigned long BI, retlen, TxLen;
+    unsigned char BitBangPkt[4096] = "";
+
+    BI = CH347_CMD_HEADER;
+
+    LOG_DEBUG_IO("(num_states=%d, last_state=%d)",
+                 cmd->num_states, cmd->path[cmd->num_states - 1]);
+
+    for (i = 0; i < cmd->num_states; i++) {
+        if (tap_state_transition(tap_get_state(), false) == cmd->path[i])
+            retlen = CH347_ClockTms(BitBangPkt, 0, BI);
+        BI = retlen;
+        if (tap_state_transition(tap_get_state(), true) == cmd->path[i])
+            retlen = CH347_ClockTms(BitBangPkt, 1, BI);
+        BI = retlen;
+        tap_set_state(cmd->path[i]);
+    }
+
+    BI = CH347_IdleClock(BitBangPkt, BI);
+    BitBangPkt[0] = CH347_CMD_JTAG_BIT_OP;
+    BitBangPkt[1] = (unsigned char)BI - CH347_CMD_HEADER;
+    BitBangPkt[2] = 0;
+
+    TxLen = BI;
+    if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) {
+        LOG_ERROR("JTAG Write send usb data failure.");
+        return NULL;
+    }
+}
+
+/**
+ * CH347_MoveState - 切换Tap状态至目标状态stat
+ * @param stat 预切换目标路径
+ * @param skip 需跳过的位数
+ *
+ */
+static void CH347_MoveState(tap_state_t state, int skip)
+{
+    uint8_t tms_scan;
+    int tms_len;
+
+    LOG_DEBUG_IO("(from %s to %s)", tap_state_name(tap_get_state()),
+                 tap_state_name(state));
+    if (tap_get_state() == state)
+        return;
+    tms_scan = tap_get_tms_path(tap_get_state(), state);
+    tms_len = tap_get_tms_path_len(tap_get_state(), state);
+    CH347_TmsChange(&tms_scan, tms_len, skip);
+    tap_set_state(state);
+}
+
+/**
+ * CH347_WriteRead - CH347 批量读写函数
+ * @param bits                          此次进行读写数据
+ * @param nb_bits               传入数据长度
+ * @param scan                  传入数据的传输方式来确定是否执行数据读取
+ *
+ */
+static void CH347_WriteRead(uint8_t *bits, int nb_bits, enum scan_type scan)
+{
+    // unsigned int delay = 1000000;
+    int nb8 = nb_bits / 8;
+    int nb1 = nb_bits % 8;
+    int nbfree_in_packet, i, trans = 0;
+    bool IsRead = false;
+    uint8_t TMS_Bit, TDI_Bit;
+    uint8_t *tdos = calloc(1, nb_bits / 8 + 32);
+    static uint8_t BitBangPkt[SF_PACKET_BUF_SIZE];
+    static uint8_t byte0[SF_PACKET_BUF_SIZE];
+    unsigned char temp[512] = "";
+    unsigned char temp_a[512] = "";
+    unsigned long BI = 0, TxLen, RxLen, DI, DII, PktDataLen, DLen;
+    uint32_t retlen;
+    int ret = ERROR_OK;
+
+    // 最后一个TDI位将会按照位带模式输出,其nb1确保不为0,使其能在TMS变化时输出最后1bit数据
+    if (nb8 > 0 && nb1 == 0) {
+        nb8--;
+        nb1 = 8;
+    }
+
+    IsRead = (scan == SCAN_IN || scan == SCAN_IO);
+    DI = BI = 0;
+    while (DI < nb8) {
+        // 构建数据包
+        if ((nb8 - DI) > UCMDPKT_DATA_MAX_BYTES_USBHS)
+            PktDataLen = UCMDPKT_DATA_MAX_BYTES_USBHS;
+        else
+            PktDataLen = nb8 - DI;
+
+        DII = PktDataLen;
+
+        if (IsRead)
+            BitBangPkt[BI++] = CH347_CMD_JTAG_DATA_SHIFT_RD;
+        else
+            BitBangPkt[BI++] = CH347_CMD_JTAG_DATA_SHIFT;
+
+        BitBangPkt[BI++] = (uint8_t)(PktDataLen >> 0) & 0xFF;
+        BitBangPkt[BI++] = (uint8_t)(PktDataLen >> 8) & 0xFF;
+
+        if (bits)
+            memcpy(&BitBangPkt[BI], &bits[DI], PktDataLen);
+        else
+            memcpy(&BitBangPkt[BI], byte0, PktDataLen);
+        BI += PktDataLen;
+
+        // 若需回读数据则判断当前BI值进行命令下发
+        if (IsRead) {
+            TxLen = BI;
+
+            if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) {
+                LOG_ERROR("CH347_WriteRead write usb data failure.");
+                return NULL;
+            }
+            BI = 0;
+
+            ret = ERROR_OK;
+            while (ret == ERROR_OK && PktDataLen > 0) {
+                RxLen = PktDataLen + CH347_CMD_HEADER;
+                if (!(ret = CH347_Read(temp, &RxLen))) {
+                    LOG_ERROR("CH347_WriteRead read usb data failure.\n");
+                    return NULL;
+                }
+
+                if (RxLen != TxLen) {
+                    if (!(ret = CH347_Read(temp_a, &TxLen))) {
+                        LOG_ERROR("CH347_WriteRead read usb data failure.\n");
+                        return NULL;
+                    }
+                    memcpy(&temp[RxLen], temp_a, TxLen);
+                    RxLen += TxLen;
+                }
+
+                if (RxLen != 0)
+                    memcpy(&tdos[DI], &temp[CH347_CMD_HEADER], (RxLen - 
CH347_CMD_HEADER));
+                PktDataLen -= RxLen;
+            }
+        }
+
+        DI += DII;
+
+        // 在传输过程中,若不回读则根据命令包长度将要达到饱和时将命令下发
+        if (((SF_PACKET_BUF_SIZE - BI) < USBC_PACKET || (SF_PACKET_BUF_SIZE - 
BI) == USBC_PACKET)) {
+            TxLen = BI;
+
+            if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) {
+                LOG_ERROR("CH347_WriteRead send usb data failure.");
+                return NULL;
+            }
+            BI = 0;
+        }
+    }
+
+    // 清空while循环中剩余的命令
+    if (BI > 0) {
+        TxLen = BI;
+        if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) {
+            LOG_ERROR("CH347_WriteRead send usb data failure.");
+            return NULL;
+        }
+        BI = 0;
+    }
+
+    // 构建输出最后1位TDI数据的命令包
+    if (bits) {
+        BitBangPkt[BI++] = IsRead ? CH347_CMD_JTAG_BIT_OP_RD : 
CH347_CMD_JTAG_BIT_OP;
+        DLen = (nb1 * 2) + 1;
+        BitBangPkt[BI++] = (uint8_t)(DLen >> 0) & 0xFF;
+        BitBangPkt[BI++] = (uint8_t)(DLen >> 8) & 0xFF; 
+        TMS_Bit = TMS_L;
+
+        for (i = 0; i < nb1; i++) {
+            if ((bits[nb8] >> i) & 1)
+                TDI_Bit = TDI_H;
+            else
+                TDI_Bit = TDI_L;
+
+            if ((i + 1) == nb1) //最后一位在Exit1-DR状态输出
+                TMS_Bit = TMS_H;
+            BitBangPkt[BI++] = TMS_Bit | TDI_Bit | TCK_L;
+            BitBangPkt[BI++] = TMS_Bit | TDI_Bit | TCK_H;
+        }
+        BitBangPkt[BI++] = TMS_Bit | TDI_Bit | TCK_L;
+    }
+
+    // 读取Bit-Bang模式下的最后一字节数据
+    if (nb1 && IsRead) {
+        TxLen = BI;
+
+        if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) {
+            LOG_ERROR("CH347_WriteRead send usb data failure.");
+            return NULL;
+        }
+        BI = 0;
+
+        RxLen = TxLen + CH347_CMD_HEADER;
+        if (!(ret = CH347_Read(temp, &RxLen))) {
+            LOG_ERROR("CH347_WriteRead read usb data failure.");
+        }
+
+        for (i = 0; ret == true && i < nb1; i++) {
+            if (temp[CH347_CMD_HEADER + i] & 1)
+                tdos[nb8] |= (1 << i);
+            else
+                tdos[nb8] &= ~(1 << i);
+        }
+    }
+
+    // 清空此次批量读写函数中未处理命令
+    if (BI > 0) {
+        TxLen = BI;
+        if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) {
+            LOG_ERROR("CH347_WriteRead send usb data failure.");
+            return NULL;
+        }
+        BI = 0;
+    }
+
+    if (bits) {
+        memcpy(bits, tdos, DIV_ROUND_UP(nb_bits, 8));
+    }
+
+    free(tdos);
+    LOG_DEBUG_IO("bits %d str value: [%s].\n", DIV_ROUND_UP(nb_bits, 8), 
HexToString(bits, DIV_ROUND_UP(nb_bits, 8)));
+
+    // 将TCK、TDI拉低为低电平,因TDI采样在TCK上升沿,若状态未改变,则TDI采样将可能发生在TCK下降沿
+    BI = CH347_CMD_HEADER;
+    BI = CH347_IdleClock(BitBangPkt, BI);
+
+    BitBangPkt[0] = CH347_CMD_JTAG_BIT_OP;
+    BitBangPkt[1] = (unsigned char)BI - CH347_CMD_HEADER;
+    BitBangPkt[2] = 0;
+
+    TxLen = BI;
+
+    if (!CH347_Write(BitBangPkt, &TxLen) && (TxLen != BI)) {
+        LOG_ERROR("JTAG Write send usb data failure.");
+        return NULL;
+    }
+}
+
+static void CH347_RunTest(int cycles, tap_state_t state)
+{
+    LOG_DEBUG_IO("%s(cycles=%i, end_state=%d)", __func__, cycles, state);
+    CH347_MoveState(TAP_IDLE, 0);
+
+    CH347_WriteRead(NULL, cycles, SCAN_OUT);
+    CH347_MoveState(state, 0);
+}
+
+static void CH347_TableClocks(int cycles)
+{
+    LOG_DEBUG_IO("%s(cycles=%i)", __func__, cycles);
+    CH347_WriteRead(NULL, cycles, SCAN_OUT);
+}
+
+/**
+ * CH347_Scan - 切换至SHIFT-DR或者SHIFT-IR状态进行扫描
+ * @param cmd      上层传递命令参数
+ *
+ * @return             成功返回ERROR_OK
+ */
+static int CH347_Scan(struct scan_command *cmd)
+{
+    int scan_bits;
+    uint8_t *buf = NULL;
+    enum scan_type type;
+    int ret = ERROR_OK;
+    static const char *const type2str[] = {"", "SCAN_IN", "SCAN_OUT", 
"SCAN_IO"};
+    char *log_buf = NULL;
+
+    type = jtag_scan_type(cmd);
+    scan_bits = jtag_build_buffer(cmd, &buf);
+
+    if (cmd->ir_scan)
+        CH347_MoveState(TAP_IRSHIFT, 0);
+    else
+        CH347_MoveState(TAP_DRSHIFT, 0);
+
+    log_buf = HexToString(buf, DIV_ROUND_UP(scan_bits, 8));
+    LOG_DEBUG_IO("Scan");
+    LOG_DEBUG_IO("%s(scan=%s, type=%s, bits=%d, buf=[%s], end_state=%d)", 
__func__,
+                 cmd->ir_scan ? "IRSCAN" : "DRSCAN",
+                 type2str[type],
+                 scan_bits, log_buf, cmd->end_state);
+
+    free(log_buf);
+
+    CH347_WriteRead(buf, scan_bits, type);
+
+    ret = jtag_read_buffer(buf, cmd);
+    free(buf);
+
+    CH347_MoveState(cmd->end_state, 1);
+
+    return ret;
+}
+
+static void CH347_Sleep(int us)
+{
+    LOG_DEBUG_IO("%s(us=%d)", __func__, us);
+    jtag_sleep(us);
+}
+
+static int ch347_execute_queue(void)
+{
+    struct jtag_command *cmd;
+    static int first_call = 1;
+    int ret = ERROR_OK;
+    unsigned long TxLen = 8192;
+    unsigned char clearBuffer[8192] = "";
+
+    if (first_call) {
+        first_call--;
+        CH347_Reset();
+    }
+
+    for (cmd = jtag_command_queue; ret == ERROR_OK && cmd;
+         cmd = cmd->next) {
+        switch (cmd->type) {
+        case JTAG_RESET:
+            CH347_Reset();
+            break;
+        case JTAG_RUNTEST:
+            CH347_RunTest(cmd->cmd.runtest->num_cycles,
+                          cmd->cmd.runtest->end_state);
+            break;
+        case JTAG_STABLECLOCKS:
+            CH347_TableClocks(cmd->cmd.stableclocks->num_cycles);
+            break;
+        case JTAG_TLR_RESET:
+            CH347_MoveState(cmd->cmd.statemove->end_state, 0);
+            break;
+        case JTAG_PATHMOVE:
+            CH347_MovePath(cmd->cmd.pathmove);
+            break;
+        case JTAG_TMS:
+            CH347_TMS(cmd->cmd.tms);
+            break;
+        case JTAG_SLEEP:
+            CH347_Sleep(cmd->cmd.sleep->us);
+            break;
+        case JTAG_SCAN:
+            ret = CH347_Scan(cmd->cmd.scan);
+            break;
+        default:
+            LOG_ERROR("BUG: unknown JTAG command type 0x%X",
+                      cmd->type);
+            ret = ERROR_FAIL;
+            break;
+        }
+    }
+    return ret;
+}
+
+/**
+ * ch347_init - CH347 初始化函数
+ *
+ *  执行工作:
+ *                初始化动态库函数
+ *                打开设备
+ *  @return      成功返回0,失败返回ERROR_FAIL
+ */
+static int ch347_init(void)
+{
+    unsigned char clearBuffer[4096] = "";
+    unsigned long RxLen = 4096;
+
+    if (uhModule == 0) {
+        uhModule = LoadLibrary("CH347DLL.DLL");
+        if (uhModule) {
+            upOpenDev = (pCH347OpenDevice)GetProcAddress(uhModule, 
"CH347OpenDevice");
+            upCloseDev = (pCH347CloseDevice)GetProcAddress(uhModule, 
"CH347CloseDevice");
+            upReadData = (pCH347ReadData)GetProcAddress(uhModule, 
"CH347ReadData");
+            upWriteData = (pCH347WriteData)GetProcAddress(uhModule, 
"CH347WriteData");
+            upSetTimeout = (pCH347SetTimeout)GetProcAddress(uhModule, 
"CH347SetTimeout");
+            upJtagInit = (pCH347Jtag_INIT)GetProcAddress(uhModule, 
"CH347Jtag_INIT");
+            if (upOpenDev == NULL || upCloseDev == NULL || upSetTimeout == 
NULL || upReadData == NULL || upWriteData == NULL || upJtagInit == NULL) {
+                LOG_ERROR("Jtag_init error ");
+                return ERROR_FAIL;
+            }
+        }
+    }
+    DevIsOpened = upOpenDev(ugIndex);
+    if (DevIsOpened == false) {
+        ugOpen = false;
+        LOG_ERROR("CH347 Open Error.");
+        return ERROR_FAIL;
+    }
+
+    USBC_PACKET = USBC_PACKET_USBHS; // 默认为USB2.0高速,其单次传输USB包大小512字节
+
+    if (!CH347_Read(clearBuffer, &RxLen)) {
+        LOG_ERROR("CH347 clear Buffer Error.");
+        return ERROR_FAIL;
+    }
+
+    // upSetTimeout(ugIndex, 5000, 5000);
+
+    tap_set_state(TAP_RESET);
+    return 0;
+}
+
+/**
+ * ch347_quit - CH347 设备释放函数
+ *
+ * 执行工作:
+ *              复位JTAG引脚信号
+ *              关闭
+ *  @return    一直返回0
+ */
+static int ch347_quit(void)
+{
+    // 退出前将信号线全部设置为低电平
+    uint32_t retlen = 5;
+    unsigned char byte[5] = {CH347_CMD_JTAG_BIT_OP, 0x01, 0x00, 0x00, 0x00};
+
+    CH347_Write(byte, &retlen);
+
+    if (DevIsOpened) {
+        upCloseDev(ugIndex);
+        LOG_INFO("Close the CH347.");
+        DevIsOpened = false;
+    }
+    return 0;
+}
+
+/**
+ * ch347_speed - CH347 TCK频率设置
+ *  @param speed 设置的频率大小
+ *  @return     成功返回ERROR_OK,失败返回FALSE
+ */
+static int ch347_speed(int speed)
+{
+    int i = 0;
+    int retval;
+    int speed_clock[6] = {MHZ(1.875), MHZ(3.75), MHZ(7.5), MHZ(15), MHZ(30), 
MHZ(60)};
+
+    for (i = 0; i < sizeof(speed_clock) / sizeof(int); i++) {
+        if ((speed >= speed_clock[i]) && (speed <= speed_clock[i + 1])) {
+            retval = upJtagInit(ugIndex, i + 1);
+            if (!retval) {
+                LOG_ERROR("Couldn't set CH347 TCK speed");
+                return retval;
+            } else {
+                break;
+            }
+        } else if (speed < speed_clock[0]) {
+            retval = upJtagInit(ugIndex, 0);
+            if (!retval) {
+                LOG_ERROR("Couldn't set CH347 TCK speed");
+                return retval;
+            } else {
+                break;
+            }
+        }
+    }
+
+    return ERROR_OK;
+}
+
+static int ch347_speed_div(int speed, int *khz)
+{
+    *khz = speed / 1000;
+    return ERROR_OK;
+}
+
+static int ch347_khz(int khz, int *jtag_speed)
+{
+    if (khz == 0) {
+        LOG_ERROR("Couldn't support the adapter speed");
+        return ERROR_FAIL;
+    }
+    *jtag_speed = khz * 1000;
+    return ERROR_OK;
+}
+
+COMMAND_HANDLER(ch347_handle_vid_pid_command)
+{
+    // TODO
+    return ERROR_OK;
+}
+
+static const struct command_registration ch347_subcommand_handlers[] = {
+    {
+        .name = "vid_pid",
+        .handler = ch347_handle_vid_pid_command,
+        .mode = COMMAND_CONFIG,
+        .help = "",
+        .usage = "",
+    },
+    COMMAND_REGISTRATION_DONE};
+
+static const struct command_registration ch347_command_handlers[] = {
+    {
+        .name = "ch347",
+        .mode = COMMAND_ANY,
+        .help = "perform ch347 management",
+        .chain = ch347_subcommand_handlers,
+        .usage = "",
+    },
+    COMMAND_REGISTRATION_DONE};
+
+static struct jtag_interface ch347_interface = {
+    .supported = DEBUG_CAP_TMS_SEQ,
+    .execute_queue = ch347_execute_queue,
+};
+
+struct adapter_driver ch347_adapter_driver = {
+    .name = "ch347",
+    .transports = jtag_only,
+    .commands = ch347_command_handlers,
+
+    .init = ch347_init,
+    .quit = ch347_quit,
+    .speed = ch347_speed,
+    .khz = ch347_khz,
+    .speed_div = ch347_speed_div,
+
+    .jtag_ops = &ch347_interface,
+};
\ No newline at end of file
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index 67bbb3b366..6358c70afe 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -40,6 +40,9 @@ extern struct adapter_driver dummy_adapter_driver;
 #if BUILD_FTDI == 1
 extern struct adapter_driver ftdi_adapter_driver;
 #endif
+#if BUILD_CH347 == 1
+extern struct adapter_driver ch347_adapter_driver;
+#endif
 #if BUILD_USB_BLASTER == 1 || BUILD_USB_BLASTER_2 == 1
 extern struct adapter_driver usb_blaster_adapter_driver;
 #endif
@@ -160,6 +163,9 @@ struct adapter_driver *adapter_drivers[] = {
 #if BUILD_FTDI == 1
                &ftdi_adapter_driver,
 #endif
+#if BUILD_CH347 == 1
+       &ch347_adapter_driver,
+#endif
 #if BUILD_USB_BLASTER || BUILD_USB_BLASTER_2 == 1
                &usb_blaster_adapter_driver,
 #endif
diff --git a/tcl/target/ch347.cfg b/tcl/target/ch347.cfg
new file mode 100644
index 0000000000..2ba8051da1
--- /dev/null
+++ b/tcl/target/ch347.cfg
@@ -0,0 +1,3 @@
+adapter driver ch347
+ch347 vid_pid 0x1a86 0x55dd 
+adapter speed 10000
\ No newline at end of file

-- 

Reply via email to