diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index d75a0457..568172a3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -168,6 +168,8 @@ add_library(libavrdude
     freebsd_ppi.h
     ft245r.c
     ft245r.h
+    ispv2renew.h
+    ispv2renew.c
     jtagmkI.c
     jtagmkI.h
     jtagmkI_private.h
@@ -184,6 +186,8 @@ add_library(libavrdude
     linuxspi.h
     linux_ppdev.h
     lists.c
+    mcupro.h
+    mcupro.c
     micronucleus.c
     micronucleus.h
     par.c
@@ -231,6 +235,8 @@ add_library(libavrdude
     urclock_private.h
     usbasp.c
     usbasp.h
+    usbisp3.h
+    usbisp3.c
     usbdevs.h
     usb_hidapi.c
     usb_libusb.c
diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in
index 43dbe767..55541b5e 100644
--- a/src/avrdude.conf.in
+++ b/src/avrdude.conf.in
@@ -2482,6 +2482,42 @@ programmer
     connection_type        = usb;
 ;
 
+#------------------------------------------------------------
+# usbisp3
+#------------------------------------------------------------
+
+programmer
+    id                     = "usbisp3";
+    desc                   = "USB ISP 3.0 by Ngo Hung Cuong";
+    type                   = "usbisp3";
+    prog_modes             = PM_ISP;
+    connection_type        = usb;
+;
+
+#------------------------------------------------------------
+# ispv2renew
+#------------------------------------------------------------
+
+programmer
+    id                     = "ispv2renew";
+    desc                   = "ISP v2 Renew by Ngo Hung Cuong";
+    type                   = "ispv2renew";
+    prog_modes             = PM_ISP;
+    connection_type        = usb;
+;
+
+#------------------------------------------------------------
+# mcupro
+#------------------------------------------------------------
+
+programmer
+    id                     = "mcupro";
+    desc                   = "MCU Pro by Ngo Hung Cuong";
+    type                   = "mcupro";
+    prog_modes             = PM_ISP;
+    connection_type        = usb;
+;
+
 #------------------------------------------------------------
 # flip1
 #------------------------------------------------------------
diff --git a/src/ispv2renew.c b/src/ispv2renew.c
new file mode 100644
index 00000000..6cf6d239
--- /dev/null
+++ b/src/ispv2renew.c
@@ -0,0 +1,851 @@
+#include "ac_cfg.h"
+
+#include <windows.h>
+#include <Setupapi.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "libavrdude.h"
+
+#include "ispv2renew.h"
+
+#include <lusb0_usb.h>
+
+const char ispv2renew_desc[] = "ISP v2 Renew by Ngo Hung Cuong";
+
+// libusb support
+static usb_dev_handle* hUsb;
+static uint8_t buff[64 * 1024];
+static uint32_t connected = 0;
+
+static uint32_t KT_LibUSB_OpenVidPid(uint32_t vid, uint32_t pid);
+static void KT_LibUSB_Close(void);
+static uint32_t KT_LibUSB_Read(uint8_t ep, uint8_t* p_data, uint32_t length);
+static uint32_t KT_LibUSB_Write(uint8_t ep, uint8_t* p_data, uint32_t length);
+
+// ispv2renew
+static char szFirmwareVer[] = "ISP v2 Renew b230421";
+
+static uint32_t usbisp3_spi_exch(const PROGRAMMER* pgm, const uint8_t* pu8Send, uint8_t* pu8Recv, int u8Length)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x24;
+    u8Buff[1] = u8Length;
+    memmove(&u8Buff[4], pu8Send, u8Length);
+    if (!KT_LibUSB_Write(0x01, u8Buff, 64))
+    {
+        return -1;
+    }
+    if (!KT_LibUSB_Read(0x81, u8Buff, 64))
+    {
+        return -1;
+    }
+    memmove(pu8Recv, u8Buff, u8Length);
+
+    return 0;
+}
+
+static uint32_t usbisp3_avr_setup(const PROGRAMMER* pgm, uint8_t u8Speed, uint8_t u8Type, uint8_t u8Time)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x10;
+    u8Buff[1] = u8Type;
+    u8Buff[2] = u8Speed;
+    u8Buff[3] = u8Time;
+
+    return KT_LibUSB_Write(0x01, u8Buff, 64);
+}
+
+static uint32_t usbisp3_avr_exit(const PROGRAMMER* pgm, uint8_t u8RstType, uint8_t u8RstVal)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x11;
+    u8Buff[1] = u8RstType;
+    u8Buff[2] = u8RstVal;
+
+    return KT_LibUSB_Write(0x01, u8Buff, 64);
+}
+
+static int usbisp3_initialize(const PROGRAMMER* pgm, const AVRPART* p)
+{
+    uint8_t i;
+
+    for (i = 0; i < 8; ++i) {
+        if (!usbisp3_avr_setup(pgm, i, 1, 0))
+        {
+            usbisp3_avr_exit(pgm, 0, 0);
+            return -1;
+        }
+
+        if (pgm->program_enable(pgm, p) == 0x00)
+        {
+            return 0;
+        }
+    }
+    
+    return -1;
+}
+
+static void usbisp3_display(const PROGRAMMER* pgm, const char* p)
+{
+
+    return;
+}
+
+static void usbisp3_enable(PROGRAMMER* pgm, const AVRPART* p)
+{
+
+    return;
+}
+
+static void usbisp3_disable(const PROGRAMMER* pgm)
+{
+    
+    usbisp3_avr_exit(pgm, 0, 0);
+}
+
+static void usbisp3_powerdown(const PROGRAMMER* pgm)
+{
+    
+    pgm->disable(pgm);
+}
+
+static int  usbisp3_program_enable(const PROGRAMMER* pgm, const AVRPART* p)
+{
+    uint8_t cmd[4];
+    uint8_t res[4];
+
+    if (p->op[AVR_OP_PGM_ENABLE] == NULL)
+    {
+        pmsg_error("program enable instruction not defined for part %s\n", p->desc);
+        return -1;
+    }
+
+    memset(cmd, 0, sizeof(cmd));
+    avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
+
+    pgm->cmd(pgm, cmd, res);
+
+    {
+        int i;
+        msg_debug("program_enable(): sending command. Resp = ");
+
+        for (i = 0; i < 4; i++)
+        {
+            msg_debug("%02x ", res[i]);
+        }
+        msg_debug("\n");
+    }
+
+    // check for sync character
+    if (res[2] != cmd[1])
+        return -2;
+
+    return 0;
+}
+
+static int  usbisp3_chip_erase(const PROGRAMMER* pgm, const AVRPART* p)
+{
+
+    unsigned char cmd[4];
+    unsigned char res[4];
+
+    if (p->op[AVR_OP_CHIP_ERASE] == NULL)
+    {
+        pmsg_error("chip erase instruction not defined for part %s\n", p->desc);
+        return -1;
+    }
+
+    pgm->pgm_led(pgm, ON);
+
+    memset(cmd, 0, sizeof(cmd));
+
+    avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+    pgm->cmd(pgm, cmd, res);
+    usleep(p->chip_erase_delay);
+
+    pgm->initialize(pgm, p);
+
+    pgm->pgm_led(pgm, OFF);
+
+    return 0;
+}
+
+static int usbisp3_open(PROGRAMMER* pgm, const char* port)
+{
+    uint8_t u8Buff[64];
+
+    if (KT_LibUSB_OpenVidPid(0x1986, 0x0023))
+    {
+        u8Buff[0] = 0x00;
+        if (!KT_LibUSB_Write(0x01, u8Buff, 64))
+        {
+            pmsg_error("USB IO: FAILED\n");
+            return -1;
+        }
+        if (!KT_LibUSB_Read(0x81, u8Buff, 64)) {
+            pmsg_error("USB IO: FAILED\n");
+            return -1;
+        }
+        if (strcmpi((char*)u8Buff, szFirmwareVer))
+        {
+            pmsg_error("Wrong firmware version\n");
+            KT_LibUSB_Close();
+            return -1;
+        }
+
+        return 0;
+    }
+
+    return -1;
+}
+
+static void usbisp3_close(PROGRAMMER* pgm)
+{
+
+    KT_LibUSB_Close();
+}
+
+static int usbisp3_cmd(const PROGRAMMER* pgm, const unsigned char* cmd,
+    unsigned char* res)
+{
+
+    return pgm->spi(pgm, cmd, res, 4);
+}
+
+static uint32_t usbisp3_spi_exch_n(const PROGRAMMER* pgm, uint32_t u32Length, uint8_t* pu8Send, uint8_t* pu8Recv)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x03;
+    u8Buff[1] = (u32Length);
+    u8Buff[2] = (u32Length >> 8);
+    u8Buff[3] = (0);
+    u8Buff[4] = (0);
+
+    if (!KT_LibUSB_Write(0x01, u8Buff, 64)) {
+        return 0;
+    }
+
+    if (!KT_LibUSB_Write(0x01, pu8Send, u32Length)) {
+        return 0;
+    }
+
+    u8Buff[0] = 0x25;
+    u8Buff[1] = (u32Length);
+    u8Buff[2] = (u32Length >> 8);
+    u8Buff[3] = (0);
+    u8Buff[4] = (0);
+
+    if (!KT_LibUSB_Write(0x01, u8Buff, 64)) {
+        return 0;
+    }
+
+    u8Buff[0] = 0x04;
+    u8Buff[1] = (u32Length);
+    u8Buff[2] = (u32Length >> 8);
+    u8Buff[3] = (u32Length >> 16);
+    u8Buff[4] = (u32Length >> 24);
+
+    if (!KT_LibUSB_Write(0x01, u8Buff, 64)) {
+        return 0;
+    }
+
+    return KT_LibUSB_Read(0x81, pu8Recv, u32Length);
+}
+
+static uint32_t usbisp3_avr_read_flash(const PROGRAMMER* pgm, uint16_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[8 * 1024];
+    u16Length >>= 1;
+    u16Address >>= 1;
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+
+    for (i = 0; i < u16Length; ++i) {
+        *p = 0x20;
+        ++p;
+        *p = (u16Address >> 8);
+        ++p;
+        *p = (u16Address);
+        ++p;
+        *p = 0x00;
+        ++p;
+
+        *p = 0x28;
+        ++p;
+        *p = (u16Address >> 8);
+        ++p;
+        *p = (u16Address);
+        ++p;
+        *p = 0x00;
+        ++p;
+
+        ++u16Address;
+    }
+
+    if (usbisp3_spi_exch_n(pgm, u16Length * 8, u8SendBuff, u8SendBuff)) {
+        p = pu8Data;
+        for (i = 0; i < u16Length; ++i) {
+            *p = u8SendBuff[i * 8 + 3];
+            ++p;
+            *p = u8SendBuff[i * 8 + 7];
+            ++p;
+        }
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
+static uint32_t usbisp3_avr_read_eeprom(const PROGRAMMER* pgm, uint16_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[8 * 1024];
+
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+
+    for (i = 0; i < u16Length; ++i) {
+        *p = 0xA0;
+        ++p;
+        *p = (u16Address >> 8);
+        ++p;
+        *p = (u16Address);
+        ++p;
+        *p = 0x00;
+        ++p;
+
+        ++u16Address;
+    }
+
+    if (usbisp3_spi_exch_n(pgm, u16Length * 4, u8SendBuff, u8SendBuff)) {
+        p = pu8Data;
+        for (i = 0; i < u16Length; ++i) {
+            *p = u8SendBuff[i * 4 + 3];
+            ++p;
+        }
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
+static uint32_t usbisp3_avr_write_flash(const PROGRAMMER* pgm, uint32_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[1024];
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+    uint8_t* pS;
+    pS = pu8Data;
+    uint16_t u16TmpAddress;
+    uint16_t u16Pos = 0;
+    uint8_t u8Poll;
+
+    if (u16Length < 16) {
+        u16TmpAddress = 0;
+        p = u8SendBuff;
+        pS = pu8Data;
+        for (i = 0; i < (u16Length / 2); ++i) {
+            *p = 0x40;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            *p = 0x48;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            ++u16TmpAddress;
+        }
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, u16Length * 4)) {
+            return 0;
+        }
+        
+        u8SendBuff[0] = 0x4c;
+        u8SendBuff[1] = (u16Address >> 9);
+        u8SendBuff[2] = (u16Address >> 1);
+        u8SendBuff[3] = 0x00;
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+            return 0;
+        }
+        
+        for (i = 0; i < u16Length; ++i) {
+            if (pu8Data[i] != 0xff) {
+                u16Pos = i;
+                break;
+            }
+        }
+        if (u16Pos != u16Length) {
+            if (u16Pos % 2) {
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x28;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+            else {
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x20;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+        }
+        else {
+            Sleep(10);
+            return 1;
+        }
+    }
+    else {
+        u16TmpAddress = 0;
+        p = u8SendBuff;
+        pS = pu8Data;
+        for (i = 0; i < (u16Length / 2); ++i) {
+            *p = 0x40;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            *p = 0x48;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            ++u16TmpAddress;
+        }
+        if (!usbisp3_spi_exch_n(pgm, u16Length * 4, u8SendBuff, u8SendBuff)) {
+            return 0;
+        }
+
+        u8SendBuff[0] = 0x4c;
+        u8SendBuff[1] = (u16Address >> 9);
+        u8SendBuff[2] = (u16Address >> 1);
+        u8SendBuff[3] = 0x00;
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+            return 0;
+        }
+
+        for (i = 0; i < u16Length; ++i) {
+            if (pu8Data[i] != 0xff) {
+                u16Pos = i;
+                break;
+            }
+        }
+        if (u16Pos != u16Length) {
+
+            if (u16Pos % 2) {
+
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x28;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+            else {
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x20;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+        }
+        else {
+            Sleep(10);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static uint32_t usbisp3_avr_write_eeprom(const PROGRAMMER* pgm, uint32_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[1024];
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+    uint8_t* pS;
+    pS = pu8Data;
+    uint16_t u16TmpAddress;
+    uint16_t u16Pos = 0;
+    uint8_t u8Poll;
+
+    if (u16Length != 0x01) {
+        
+        u16TmpAddress = 0;
+        p = u8SendBuff;
+        pS = pu8Data;
+        for (i = 0; i < u16Length; ++i) {
+            *p = 0xC1;
+            ++p;
+            *p = (i >> 8);
+            ++p;
+            *p = (i);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+        }
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, u16Length * 4)) {
+            return 0;
+        }
+        for (i = 0; i < u16Length; ++i) {
+            if (pu8Data[i] != 0xff) {
+                u16Pos = i;
+                break;
+            }
+        }
+        if (u16Pos != u16Length) {
+            u8Poll = 0;
+            for (i = 0; i < 1000; ++i) {
+                u8SendBuff[0] = 0xA0;
+                u8SendBuff[1] = ((u16Address + u16Pos) >> 8);
+                u8SendBuff[2] = (u16Address + u16Pos);
+                u8SendBuff[3] = 0x00;
+                if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                    return 0;
+                }
+                if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                    u8Poll = 1;
+                    break;
+                }
+            }
+            if (u8Poll) {
+                return 1;
+            }
+            else {
+                return 0;
+            }
+        }
+        else {
+            Sleep(10);
+            return 1;
+        }
+    }
+    else {
+        u8SendBuff[0] = 0xC0;
+        u8SendBuff[1] = (u16Address >> 8);
+        u8SendBuff[2] = (u16Address);
+        u8SendBuff[3] = pu8Data[0];
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+            return 0;
+        }
+        u8Poll = 0;
+        for (i = 0; i < 1000; ++i) {
+            u8SendBuff[0] = 0xA0;
+            u8SendBuff[1] = (u16Address >> 8);
+            u8SendBuff[2] = (u16Address);
+            u8SendBuff[3] = 0x00;
+            if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                return 0;
+            }
+            if (u8SendBuff[3] == pu8Data[0]) {
+                u8Poll = 1;
+                break;
+            }
+        }
+        if (u8Poll) {
+            return 1;
+        }
+        else {
+            return 0;
+        }
+    }
+
+    return 0;
+}
+
+static int  usbisp3_paged_write(const PROGRAMMER* pgm, const AVRPART* p, const AVRMEM* mem,
+    unsigned int page_size, unsigned int addr, unsigned int n_bytes)
+{
+    if ((!mem->paged || page_size <= 1) || (strcmp(mem->desc, "flash") != 0 && strcmp(mem->desc, "eeprom") != 0))
+    {
+        return -1;
+    }
+
+    if (strcmp(mem->desc, "flash") == 0)
+    {
+        OPCODE* readop = 0, * lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+        uint8_t data = 0, cmd[64], res[64];
+
+        if (lext) {
+            memset(cmd, 0, sizeof(cmd));
+            avr_set_bits(lext, cmd);
+            avr_set_addr(lext, cmd, addr / 2);
+            pgm->cmd(pgm, cmd, res);
+        }
+
+        if (usbisp3_avr_write_flash(pgm, addr, n_bytes, &mem->buf[addr]))
+        {
+            return 0;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+    if (usbisp3_avr_write_eeprom(pgm, addr, n_bytes, &mem->buf[addr]))
+    {
+        return 0;
+    }
+    else
+    {
+        return -1;
+    }
+
+    return -1;
+}
+
+static int usbisp3_paged_load(const PROGRAMMER* pgm, const AVRPART* p, const AVRMEM* mem,
+    unsigned int page_size, unsigned int addr, unsigned int n_bytes)
+{
+
+    // only supporting flash & eeprom page reads
+    if ((!mem->paged || page_size <= 1) || (strcmp(mem->desc, "flash") != 0 && strcmp(mem->desc, "eeprom") != 0))
+    {
+        return -1;
+    }
+
+    if (strcmp(mem->desc, "flash") == 0)
+    {
+        OPCODE* readop = 0, * lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+        uint8_t data = 0, cmd[64], res[64];
+
+        if (lext) {
+            memset(cmd, 0, sizeof(cmd));
+            avr_set_bits(lext, cmd);
+            avr_set_addr(lext, cmd, addr / 2);
+            pgm->cmd(pgm, cmd, res);
+        }
+
+        if (usbisp3_avr_read_flash(pgm, addr, n_bytes, &mem->buf[addr]))
+        {
+            return 0;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+    if (usbisp3_avr_read_eeprom(pgm, addr, n_bytes, &mem->buf[addr]))
+    {
+        return 0;
+    }
+    else
+    {
+        return -1;
+    }
+
+    return -1;
+}
+
+static int  usbisp3_parseextparams(const PROGRAMMER* pgm, const LISTID extparms)
+{
+
+    return 0;
+}
+
+void ispv2renew_initpgm(PROGRAMMER* pgm)
+{
+    pgm->initialize = usbisp3_initialize;
+    pgm->display = usbisp3_display;
+    pgm->enable = usbisp3_enable;
+    pgm->disable = usbisp3_disable;
+    pgm->powerdown = usbisp3_powerdown;
+    pgm->program_enable = usbisp3_program_enable;
+    pgm->chip_erase = usbisp3_chip_erase;
+    pgm->open = usbisp3_open;
+    pgm->close = usbisp3_close;
+    pgm->spi = usbisp3_spi_exch;
+
+    pgm->read_byte = avr_read_byte_default;
+    pgm->write_byte = avr_write_byte_default;
+
+    pgm->cmd = usbisp3_cmd;
+    pgm->paged_write = usbisp3_paged_write;
+    pgm->paged_load = usbisp3_paged_load;
+
+    pgm->parseextparams = usbisp3_parseextparams;
+
+    strncpy(pgm->type, "ispv2renew", sizeof(pgm->type));
+}
+
+uint32_t KT_LibUSB_OpenVidPid(uint32_t vid, uint32_t pid)
+{
+    connected = 0;
+    usb_init(); /* initialize the library */
+    usb_find_busses(); /* find all busses */
+    usb_find_devices(); /* find all connected devices */
+
+    struct usb_bus* bus;
+    struct usb_device* dev;
+    for (bus = usb_get_busses(); bus; bus = bus->next)
+    {
+        for (dev = bus->devices; dev; dev = dev->next)
+        {
+            if (dev->descriptor.idVendor == vid
+                && dev->descriptor.idProduct == pid)
+            {
+                hUsb = usb_open(dev); //Opens a USB device
+                break;
+            }
+        }
+    }
+    if (!hUsb)
+    {
+        return 0;
+    }
+    if (usb_set_configuration(hUsb, 1) < 0) // Sets the Active configuration of the device
+    {
+        usb_close(hUsb);
+        return 0;
+    }
+
+    if (usb_claim_interface(hUsb, 0) < 0)  //claims the interface with the Operating System
+    {
+        //Closes a device opened since the claim interface is failed.
+        usb_close(hUsb);
+        return 0;
+    }
+    
+    connected = 1;
+    return 1;
+}
+
+void KT_LibUSB_Close(void)
+{
+
+    if (connected)
+    {
+        connected = 0;
+        usb_release_interface(hUsb, 0);
+        usb_close(hUsb);
+    }
+}
+
+uint32_t KT_LibUSB_Read(uint8_t ep, uint8_t* p_data, uint32_t length)
+{
+
+    if (usb_bulk_read(hUsb, ep | 0x80, (char*)buff, length, 5000) != length) {
+        return 0;
+    }
+    memmove(p_data, buff, length);
+    
+    return 1;
+}
+
+uint32_t KT_LibUSB_Write(uint8_t ep, uint8_t* p_data, uint32_t length)
+{
+    memmove(buff, p_data, length);
+    if (usb_bulk_write(hUsb, ep, (char*)buff, length, 5000) < 0) {
+        return 0;
+    }
+
+    return 1;
+}
diff --git a/src/ispv2renew.h b/src/ispv2renew.h
new file mode 100644
index 00000000..f6b1bcec
--- /dev/null
+++ b/src/ispv2renew.h
@@ -0,0 +1,15 @@
+#ifndef ISPV2RENEW_H_
+#define ISPV2RENEW_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    extern const char ispv2renew_desc[];
+    void ispv2renew_initpgm(PROGRAMMER* pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/mcupro.c b/src/mcupro.c
new file mode 100644
index 00000000..0325eb3e
--- /dev/null
+++ b/src/mcupro.c
@@ -0,0 +1,851 @@
+#include "ac_cfg.h"
+
+#include <windows.h>
+#include <Setupapi.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "libavrdude.h"
+
+#include "mcupro.h"
+
+#include <lusb0_usb.h>
+
+const char mcupro_desc[] = "MCU Pro by Ngo Hung Cuong";
+
+// libusb support
+static usb_dev_handle* hUsb;
+static uint8_t buff[64 * 1024];
+static uint32_t connected = 0;
+
+static uint32_t KT_LibUSB_OpenVidPid(uint32_t vid, uint32_t pid);
+static void KT_LibUSB_Close(void);
+static uint32_t KT_LibUSB_Read(uint8_t ep, uint8_t* p_data, uint32_t length);
+static uint32_t KT_LibUSB_Write(uint8_t ep, uint8_t* p_data, uint32_t length);
+
+// ispv2renew
+static char szFirmwareVer[] = "MCU PRO b221223";
+
+static uint32_t usbisp3_spi_exch(const PROGRAMMER* pgm, const uint8_t* pu8Send, uint8_t* pu8Recv, int u8Length)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x24;
+    u8Buff[1] = u8Length;
+    memmove(&u8Buff[4], pu8Send, u8Length);
+    if (!KT_LibUSB_Write(0x01, u8Buff, 64))
+    {
+        return -1;
+    }
+    if (!KT_LibUSB_Read(0x81, u8Buff, 64))
+    {
+        return -1;
+    }
+    memmove(pu8Recv, u8Buff, u8Length);
+
+    return 0;
+}
+
+static uint32_t usbisp3_avr_setup(const PROGRAMMER* pgm, uint8_t u8Speed, uint8_t u8Type, uint8_t u8Time)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x10;
+    u8Buff[1] = u8Type;
+    u8Buff[2] = u8Speed;
+    u8Buff[3] = u8Time;
+
+    return KT_LibUSB_Write(0x01, u8Buff, 64);
+}
+
+static uint32_t usbisp3_avr_exit(const PROGRAMMER* pgm, uint8_t u8RstType, uint8_t u8RstVal)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x11;
+    u8Buff[1] = u8RstType;
+    u8Buff[2] = u8RstVal;
+
+    return KT_LibUSB_Write(0x01, u8Buff, 64);
+}
+
+static int usbisp3_initialize(const PROGRAMMER* pgm, const AVRPART* p)
+{
+    uint8_t i;
+
+    for (i = 0; i < 8; ++i) {
+        if (!usbisp3_avr_setup(pgm, i, 1, 0))
+        {
+            usbisp3_avr_exit(pgm, 0, 0);
+            return -1;
+        }
+
+        if (pgm->program_enable(pgm, p) == 0x00)
+        {
+            return 0;
+        }
+    }
+    
+    return -1;
+}
+
+static void usbisp3_display(const PROGRAMMER* pgm, const char* p)
+{
+
+    return;
+}
+
+static void usbisp3_enable(PROGRAMMER* pgm, const AVRPART* p)
+{
+
+    return;
+}
+
+static void usbisp3_disable(const PROGRAMMER* pgm)
+{
+    
+    usbisp3_avr_exit(pgm, 0, 0);
+}
+
+static void usbisp3_powerdown(const PROGRAMMER* pgm)
+{
+    
+    pgm->disable(pgm);
+}
+
+static int  usbisp3_program_enable(const PROGRAMMER* pgm, const AVRPART* p)
+{
+    uint8_t cmd[4];
+    uint8_t res[4];
+
+    if (p->op[AVR_OP_PGM_ENABLE] == NULL)
+    {
+        pmsg_error("program enable instruction not defined for part %s\n", p->desc);
+        return -1;
+    }
+
+    memset(cmd, 0, sizeof(cmd));
+    avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
+
+    pgm->cmd(pgm, cmd, res);
+
+    {
+        int i;
+        msg_debug("program_enable(): sending command. Resp = ");
+
+        for (i = 0; i < 4; i++)
+        {
+            msg_debug("%02x ", res[i]);
+        }
+        msg_debug("\n");
+    }
+
+    // check for sync character
+    if (res[2] != cmd[1])
+        return -2;
+
+    return 0;
+}
+
+static int  usbisp3_chip_erase(const PROGRAMMER* pgm, const AVRPART* p)
+{
+
+    unsigned char cmd[4];
+    unsigned char res[4];
+
+    if (p->op[AVR_OP_CHIP_ERASE] == NULL)
+    {
+        pmsg_error("chip erase instruction not defined for part %s\n", p->desc);
+        return -1;
+    }
+
+    pgm->pgm_led(pgm, ON);
+
+    memset(cmd, 0, sizeof(cmd));
+
+    avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+    pgm->cmd(pgm, cmd, res);
+    usleep(p->chip_erase_delay);
+
+    pgm->initialize(pgm, p);
+
+    pgm->pgm_led(pgm, OFF);
+
+    return 0;
+}
+
+static int usbisp3_open(PROGRAMMER* pgm, const char* port)
+{
+    uint8_t u8Buff[64];
+
+    if (KT_LibUSB_OpenVidPid(0x4348, 0x0005))
+    {
+        u8Buff[0] = 0x00;
+        if (!KT_LibUSB_Write(0x01, u8Buff, 64))
+        {
+            pmsg_error("USB IO: FAILED\n");
+            return -1;
+        }
+        if (!KT_LibUSB_Read(0x81, u8Buff, 64)) {
+            pmsg_error("USB IO: FAILED\n");
+            return -1;
+        }
+        if (strcmpi((char*)u8Buff, szFirmwareVer))
+        {
+            pmsg_error("Wrong firmware version\n");
+            KT_LibUSB_Close();
+            return -1;
+        }
+
+        return 0;
+    }
+
+    return -1;
+}
+
+static void usbisp3_close(PROGRAMMER* pgm)
+{
+
+    KT_LibUSB_Close();
+}
+
+static int usbisp3_cmd(const PROGRAMMER* pgm, const unsigned char* cmd,
+    unsigned char* res)
+{
+
+    return pgm->spi(pgm, cmd, res, 4);
+}
+
+static uint32_t usbisp3_spi_exch_n(const PROGRAMMER* pgm, uint32_t u32Length, uint8_t* pu8Send, uint8_t* pu8Recv)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x03;
+    u8Buff[1] = (u32Length);
+    u8Buff[2] = (u32Length >> 8);
+    u8Buff[3] = (0);
+    u8Buff[4] = (0);
+
+    if (!KT_LibUSB_Write(0x01, u8Buff, 64)) {
+        return 0;
+    }
+
+    if (!KT_LibUSB_Write(0x01, pu8Send, u32Length)) {
+        return 0;
+    }
+
+    u8Buff[0] = 0x25;
+    u8Buff[1] = (u32Length);
+    u8Buff[2] = (u32Length >> 8);
+    u8Buff[3] = (0);
+    u8Buff[4] = (0);
+
+    if (!KT_LibUSB_Write(0x01, u8Buff, 64)) {
+        return 0;
+    }
+
+    u8Buff[0] = 0x04;
+    u8Buff[1] = (u32Length);
+    u8Buff[2] = (u32Length >> 8);
+    u8Buff[3] = (u32Length >> 16);
+    u8Buff[4] = (u32Length >> 24);
+
+    if (!KT_LibUSB_Write(0x01, u8Buff, 64)) {
+        return 0;
+    }
+
+    return KT_LibUSB_Read(0x81, pu8Recv, u32Length);
+}
+
+static uint32_t usbisp3_avr_read_flash(const PROGRAMMER* pgm, uint16_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[8 * 1024];
+    u16Length >>= 1;
+    u16Address >>= 1;
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+
+    for (i = 0; i < u16Length; ++i) {
+        *p = 0x20;
+        ++p;
+        *p = (u16Address >> 8);
+        ++p;
+        *p = (u16Address);
+        ++p;
+        *p = 0x00;
+        ++p;
+
+        *p = 0x28;
+        ++p;
+        *p = (u16Address >> 8);
+        ++p;
+        *p = (u16Address);
+        ++p;
+        *p = 0x00;
+        ++p;
+
+        ++u16Address;
+    }
+
+    if (usbisp3_spi_exch_n(pgm, u16Length * 8, u8SendBuff, u8SendBuff)) {
+        p = pu8Data;
+        for (i = 0; i < u16Length; ++i) {
+            *p = u8SendBuff[i * 8 + 3];
+            ++p;
+            *p = u8SendBuff[i * 8 + 7];
+            ++p;
+        }
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
+static uint32_t usbisp3_avr_read_eeprom(const PROGRAMMER* pgm, uint16_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[8 * 1024];
+
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+
+    for (i = 0; i < u16Length; ++i) {
+        *p = 0xA0;
+        ++p;
+        *p = (u16Address >> 8);
+        ++p;
+        *p = (u16Address);
+        ++p;
+        *p = 0x00;
+        ++p;
+
+        ++u16Address;
+    }
+
+    if (usbisp3_spi_exch_n(pgm, u16Length * 4, u8SendBuff, u8SendBuff)) {
+        p = pu8Data;
+        for (i = 0; i < u16Length; ++i) {
+            *p = u8SendBuff[i * 4 + 3];
+            ++p;
+        }
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
+static uint32_t usbisp3_avr_write_flash(const PROGRAMMER* pgm, uint32_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[1024];
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+    uint8_t* pS;
+    pS = pu8Data;
+    uint16_t u16TmpAddress;
+    uint16_t u16Pos = 0;
+    uint8_t u8Poll;
+
+    if (u16Length < 16) {
+        u16TmpAddress = 0;
+        p = u8SendBuff;
+        pS = pu8Data;
+        for (i = 0; i < (u16Length / 2); ++i) {
+            *p = 0x40;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            *p = 0x48;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            ++u16TmpAddress;
+        }
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, u16Length * 4)) {
+            return 0;
+        }
+        
+        u8SendBuff[0] = 0x4c;
+        u8SendBuff[1] = (u16Address >> 9);
+        u8SendBuff[2] = (u16Address >> 1);
+        u8SendBuff[3] = 0x00;
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+            return 0;
+        }
+        
+        for (i = 0; i < u16Length; ++i) {
+            if (pu8Data[i] != 0xff) {
+                u16Pos = i;
+                break;
+            }
+        }
+        if (u16Pos != u16Length) {
+            if (u16Pos % 2) {
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x28;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+            else {
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x20;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+        }
+        else {
+            Sleep(10);
+            return 1;
+        }
+    }
+    else {
+        u16TmpAddress = 0;
+        p = u8SendBuff;
+        pS = pu8Data;
+        for (i = 0; i < (u16Length / 2); ++i) {
+            *p = 0x40;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            *p = 0x48;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            ++u16TmpAddress;
+        }
+        if (!usbisp3_spi_exch_n(pgm, u16Length * 4, u8SendBuff, u8SendBuff)) {
+            return 0;
+        }
+
+        u8SendBuff[0] = 0x4c;
+        u8SendBuff[1] = (u16Address >> 9);
+        u8SendBuff[2] = (u16Address >> 1);
+        u8SendBuff[3] = 0x00;
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+            return 0;
+        }
+
+        for (i = 0; i < u16Length; ++i) {
+            if (pu8Data[i] != 0xff) {
+                u16Pos = i;
+                break;
+            }
+        }
+        if (u16Pos != u16Length) {
+
+            if (u16Pos % 2) {
+
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x28;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+            else {
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x20;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+        }
+        else {
+            Sleep(10);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static uint32_t usbisp3_avr_write_eeprom(const PROGRAMMER* pgm, uint32_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[1024];
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+    uint8_t* pS;
+    pS = pu8Data;
+    uint16_t u16TmpAddress;
+    uint16_t u16Pos = 0;
+    uint8_t u8Poll;
+
+    if (u16Length != 0x01) {
+        
+        u16TmpAddress = 0;
+        p = u8SendBuff;
+        pS = pu8Data;
+        for (i = 0; i < u16Length; ++i) {
+            *p = 0xC1;
+            ++p;
+            *p = (i >> 8);
+            ++p;
+            *p = (i);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+        }
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, u16Length * 4)) {
+            return 0;
+        }
+        for (i = 0; i < u16Length; ++i) {
+            if (pu8Data[i] != 0xff) {
+                u16Pos = i;
+                break;
+            }
+        }
+        if (u16Pos != u16Length) {
+            u8Poll = 0;
+            for (i = 0; i < 1000; ++i) {
+                u8SendBuff[0] = 0xA0;
+                u8SendBuff[1] = ((u16Address + u16Pos) >> 8);
+                u8SendBuff[2] = (u16Address + u16Pos);
+                u8SendBuff[3] = 0x00;
+                if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                    return 0;
+                }
+                if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                    u8Poll = 1;
+                    break;
+                }
+            }
+            if (u8Poll) {
+                return 1;
+            }
+            else {
+                return 0;
+            }
+        }
+        else {
+            Sleep(10);
+            return 1;
+        }
+    }
+    else {
+        u8SendBuff[0] = 0xC0;
+        u8SendBuff[1] = (u16Address >> 8);
+        u8SendBuff[2] = (u16Address);
+        u8SendBuff[3] = pu8Data[0];
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+            return 0;
+        }
+        u8Poll = 0;
+        for (i = 0; i < 1000; ++i) {
+            u8SendBuff[0] = 0xA0;
+            u8SendBuff[1] = (u16Address >> 8);
+            u8SendBuff[2] = (u16Address);
+            u8SendBuff[3] = 0x00;
+            if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                return 0;
+            }
+            if (u8SendBuff[3] == pu8Data[0]) {
+                u8Poll = 1;
+                break;
+            }
+        }
+        if (u8Poll) {
+            return 1;
+        }
+        else {
+            return 0;
+        }
+    }
+
+    return 0;
+}
+
+static int  usbisp3_paged_write(const PROGRAMMER* pgm, const AVRPART* p, const AVRMEM* mem,
+    unsigned int page_size, unsigned int addr, unsigned int n_bytes)
+{
+    if ((!mem->paged || page_size <= 1) || (strcmp(mem->desc, "flash") != 0 && strcmp(mem->desc, "eeprom") != 0))
+    {
+        return -1;
+    }
+
+    if (strcmp(mem->desc, "flash") == 0)
+    {
+        OPCODE* readop = 0, * lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+        uint8_t data = 0, cmd[64], res[64];
+
+        if (lext) {
+            memset(cmd, 0, sizeof(cmd));
+            avr_set_bits(lext, cmd);
+            avr_set_addr(lext, cmd, addr / 2);
+            pgm->cmd(pgm, cmd, res);
+        }
+
+        if (usbisp3_avr_write_flash(pgm, addr, n_bytes, &mem->buf[addr]))
+        {
+            return 0;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+    if (usbisp3_avr_write_eeprom(pgm, addr, n_bytes, &mem->buf[addr]))
+    {
+        return 0;
+    }
+    else
+    {
+        return -1;
+    }
+
+    return -1;
+}
+
+static int usbisp3_paged_load(const PROGRAMMER* pgm, const AVRPART* p, const AVRMEM* mem,
+    unsigned int page_size, unsigned int addr, unsigned int n_bytes)
+{
+
+    // only supporting flash & eeprom page reads
+    if ((!mem->paged || page_size <= 1) || (strcmp(mem->desc, "flash") != 0 && strcmp(mem->desc, "eeprom") != 0))
+    {
+        return -1;
+    }
+
+    if (strcmp(mem->desc, "flash") == 0)
+    {
+        OPCODE* readop = 0, * lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+        uint8_t data = 0, cmd[64], res[64];
+
+        if (lext) {
+            memset(cmd, 0, sizeof(cmd));
+            avr_set_bits(lext, cmd);
+            avr_set_addr(lext, cmd, addr / 2);
+            pgm->cmd(pgm, cmd, res);
+        }
+
+        if (usbisp3_avr_read_flash(pgm, addr, n_bytes, &mem->buf[addr]))
+        {
+            return 0;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+    if (usbisp3_avr_read_eeprom(pgm, addr, n_bytes, &mem->buf[addr]))
+    {
+        return 0;
+    }
+    else
+    {
+        return -1;
+    }
+
+    return -1;
+}
+
+static int  usbisp3_parseextparams(const PROGRAMMER* pgm, const LISTID extparms)
+{
+
+    return 0;
+}
+
+void mcupro_initpgm(PROGRAMMER* pgm)
+{
+    pgm->initialize = usbisp3_initialize;
+    pgm->display = usbisp3_display;
+    pgm->enable = usbisp3_enable;
+    pgm->disable = usbisp3_disable;
+    pgm->powerdown = usbisp3_powerdown;
+    pgm->program_enable = usbisp3_program_enable;
+    pgm->chip_erase = usbisp3_chip_erase;
+    pgm->open = usbisp3_open;
+    pgm->close = usbisp3_close;
+    pgm->spi = usbisp3_spi_exch;
+
+    pgm->read_byte = avr_read_byte_default;
+    pgm->write_byte = avr_write_byte_default;
+
+    pgm->cmd = usbisp3_cmd;
+    pgm->paged_write = usbisp3_paged_write;
+    pgm->paged_load = usbisp3_paged_load;
+
+    pgm->parseextparams = usbisp3_parseextparams;
+
+    strncpy(pgm->type, "mcupro", sizeof(pgm->type));
+}
+
+uint32_t KT_LibUSB_OpenVidPid(uint32_t vid, uint32_t pid)
+{
+    connected = 0;
+    usb_init(); /* initialize the library */
+    usb_find_busses(); /* find all busses */
+    usb_find_devices(); /* find all connected devices */
+
+    struct usb_bus* bus;
+    struct usb_device* dev;
+    for (bus = usb_get_busses(); bus; bus = bus->next)
+    {
+        for (dev = bus->devices; dev; dev = dev->next)
+        {
+            if (dev->descriptor.idVendor == vid
+                && dev->descriptor.idProduct == pid)
+            {
+                hUsb = usb_open(dev); //Opens a USB device
+                break;
+            }
+        }
+    }
+    if (!hUsb)
+    {
+        return 0;
+    }
+    if (usb_set_configuration(hUsb, 1) < 0) // Sets the Active configuration of the device
+    {
+        usb_close(hUsb);
+        return 0;
+    }
+
+    if (usb_claim_interface(hUsb, 0) < 0)  //claims the interface with the Operating System
+    {
+        //Closes a device opened since the claim interface is failed.
+        usb_close(hUsb);
+        return 0;
+    }
+    
+    connected = 1;
+    return 1;
+}
+
+void KT_LibUSB_Close(void)
+{
+
+    if (connected)
+    {
+        connected = 0;
+        usb_release_interface(hUsb, 0);
+        usb_close(hUsb);
+    }
+}
+
+uint32_t KT_LibUSB_Read(uint8_t ep, uint8_t* p_data, uint32_t length)
+{
+
+    if (usb_bulk_read(hUsb, ep | 0x80, (char*)buff, length, 5000) != length) {
+        return 0;
+    }
+    memmove(p_data, buff, length);
+    
+    return 1;
+}
+
+uint32_t KT_LibUSB_Write(uint8_t ep, uint8_t* p_data, uint32_t length)
+{
+    memmove(buff, p_data, length);
+    if (usb_bulk_write(hUsb, ep, (char*)buff, length, 5000) < 0) {
+        return 0;
+    }
+
+    return 1;
+}
diff --git a/src/mcupro.h b/src/mcupro.h
new file mode 100644
index 00000000..a96d3a15
--- /dev/null
+++ b/src/mcupro.h
@@ -0,0 +1,15 @@
+#ifndef MCUPRO_H_
+#define MCUPRO_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    extern const char mcupro_desc[];
+    void mcupro_initpgm(PROGRAMMER* pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/pgm_type.c b/src/pgm_type.c
index 91400fea..a421051d 100644
--- a/src/pgm_type.c
+++ b/src/pgm_type.c
@@ -36,11 +36,13 @@
 #include "flip1.h"
 #include "flip2.h"
 #include "ft245r.h"
+#include "ispv2renew.h"
 #include "jtagmkI.h"
 #include "jtagmkII.h"
 #include "jtag3.h"
 #include "linuxgpio.h"
 #include "linuxspi.h"
+#include "mcupro.h"
 #include "micronucleus.h"
 #include "par.h"
 #include "pickit2.h"
@@ -53,6 +55,7 @@
 #include "teensy.h"
 #include "urclock.h"
 #include "usbasp.h"
+#include "usbisp3.h"
 #include "usbtiny.h"
 #include "wiring.h"
 #include "xbee.h"
@@ -75,6 +78,7 @@ const PROGRAMMER_TYPE programmers_types[] = { // Name(s) the programmers call th
   {"flip1", flip1_initpgm, flip1_desc}, // "flip1"
   {"flip2", flip2_initpgm, flip2_desc}, // "flip2"
   {"ftdi_syncbb", ft245r_initpgm, ft245r_desc}, // "ftdi_syncbb"
+  {"ispv2renew", ispv2renew_initpgm, ispv2renew_desc}, // "ispv2renew"
   {"jtagmki", jtagmkI_initpgm, jtagmkI_desc}, // "JTAGMKI"
   {"jtagmkii", jtagmkII_initpgm, jtagmkII_desc}, // "JTAGMKII"
   {"jtagmkii_avr32", jtagmkII_avr32_initpgm, jtagmkII_avr32_desc}, // "JTAGMKII_AVR32"
@@ -90,6 +94,7 @@ const PROGRAMMER_TYPE programmers_types[] = { // Name(s) the programmers call th
   {"jtagice3_tpi", jtag3_tpi_initpgm, jtag3_tpi_desc}, // "JTAGICE3_TPI"
   {"linuxgpio", linuxgpio_initpgm, linuxgpio_desc}, // "linuxgpio"
   {"linuxspi", linuxspi_initpgm, linuxspi_desc}, // LINUXSPI
+  {"mcupro", mcupro_initpgm, mcupro_desc}, // "mcupro"
   {"micronucleus", micronucleus_initpgm, micronucleus_desc}, // "micronucleus" or "Micronucleus V2.0"
   {"par", par_initpgm, par_desc}, // "PPI"
   {"pickit2", pickit2_initpgm, pickit2_desc}, // "pickit2"
@@ -106,6 +111,7 @@ const PROGRAMMER_TYPE programmers_types[] = { // Name(s) the programmers call th
   {"teensy", teensy_initpgm, teensy_desc}, // "teensy"
   {"urclock", urclock_initpgm, urclock_desc}, // "Urclock"
   {"usbasp", usbasp_initpgm, usbasp_desc}, // "usbasp"
+  {"usbisp3", usbisp3_initpgm, usbisp3_desc}, // "usbisp3"
   {"usbtiny", usbtiny_initpgm, usbtiny_desc}, // "USBtiny" or "usbtiny"
   {"wiring", wiring_initpgm, wiring_desc}, // "Wiring"
   {"xbee", xbee_initpgm, xbee_desc}, // "XBee"
diff --git a/src/usbisp3.c b/src/usbisp3.c
new file mode 100644
index 00000000..5b39a753
--- /dev/null
+++ b/src/usbisp3.c
@@ -0,0 +1,959 @@
+#include "ac_cfg.h"
+
+#include <windows.h>
+#include <Setupapi.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "libavrdude.h"
+
+#include "usbisp3.h"
+
+#include "winusb.h"
+
+const char usbisp3_desc[] = "USB ISP 3.0 by Ngo Hung Cuong";
+
+// winusb support
+static WINUSB_INTERFACE_HANDLE hWinUsb;
+static uint8_t buff[64 * 1024];
+static OVERLAPPED ov;
+static HANDLE hUsb;
+static uint32_t connected = 0;
+
+static uint32_t KT_WinUSB_OpenVidPid(uint32_t vid, uint32_t pid);
+static void KT_WinUSB_Close(void);
+static uint32_t KT_WinUSB_Read(uint8_t ep, uint8_t* p_data, uint32_t length);
+static uint32_t KT_WinUSB_Write(uint8_t ep, uint8_t* p_data, uint32_t length);
+
+// usbisp3
+static char szFirmwareVer[] = "USB ISP 3.0 version 230726";
+static char szSerialVer[] = "ICVN.VN-230722";
+
+static uint32_t usbisp3_spi_exch(const PROGRAMMER* pgm, const uint8_t* pu8Send, uint8_t* pu8Recv, int u8Length)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x24;
+    u8Buff[1] = u8Length;
+    memmove(&u8Buff[4], pu8Send, u8Length);
+    if (!KT_WinUSB_Write(0x01, u8Buff, 64))
+    {
+        return -1;
+    }
+    if (!KT_WinUSB_Read(0x81, u8Buff, 64))
+    {
+        return -1;
+    }
+    memmove(pu8Recv, u8Buff, u8Length);
+
+    return 0;
+}
+
+static uint32_t usbisp3_avr_setup(const PROGRAMMER* pgm, uint8_t u8Speed, uint8_t u8Type, uint8_t u8Time)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x10;
+    u8Buff[1] = u8Type;
+    u8Buff[2] = u8Speed;
+    u8Buff[3] = u8Time;
+
+    return KT_WinUSB_Write(0x01, u8Buff, 64);
+}
+
+static uint32_t usbisp3_avr_exit(const PROGRAMMER* pgm, uint8_t u8RstType, uint8_t u8RstVal)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x11;
+    u8Buff[1] = u8RstType;
+    u8Buff[2] = u8RstVal;
+
+    return KT_WinUSB_Write(0x01, u8Buff, 64);
+}
+
+static int usbisp3_initialize(const PROGRAMMER* pgm, const AVRPART* p)
+{
+    uint8_t i;
+
+    for (i = 0; i < 8; ++i) {
+        if (!usbisp3_avr_setup(pgm, i, 1, 0))
+        {
+            usbisp3_avr_exit(pgm, 0, 0);
+            return -1;
+        }
+
+        if (pgm->program_enable(pgm, p) == 0x00)
+        {
+            return 0;
+        }
+    }
+    
+    return -1;
+}
+
+static void usbisp3_display(const PROGRAMMER* pgm, const char* p)
+{
+
+    return;
+}
+
+static void usbisp3_enable(PROGRAMMER* pgm, const AVRPART* p)
+{
+
+    return;
+}
+
+static void usbisp3_disable(const PROGRAMMER* pgm)
+{
+    
+    usbisp3_avr_exit(pgm, 0, 0);
+}
+
+static void usbisp3_powerdown(const PROGRAMMER* pgm)
+{
+    
+    pgm->disable(pgm);
+}
+
+static int  usbisp3_program_enable(const PROGRAMMER* pgm, const AVRPART* p)
+{
+    uint8_t cmd[4];
+    uint8_t res[4];
+
+    if (p->op[AVR_OP_PGM_ENABLE] == NULL)
+    {
+        pmsg_error("program enable instruction not defined for part %s\n", p->desc);
+        return -1;
+    }
+
+    memset(cmd, 0, sizeof(cmd));
+    avr_set_bits(p->op[AVR_OP_PGM_ENABLE], cmd);
+
+    pgm->cmd(pgm, cmd, res);
+
+    {
+        int i;
+        msg_debug("program_enable(): sending command. Resp = ");
+
+        for (i = 0; i < 4; i++)
+        {
+            msg_debug("%02x ", res[i]);
+        }
+        msg_debug("\n");
+    }
+
+    // check for sync character
+    if (res[2] != cmd[1])
+        return -2;
+
+    return 0;
+}
+
+static int  usbisp3_chip_erase(const PROGRAMMER* pgm, const AVRPART* p)
+{
+
+    unsigned char cmd[4];
+    unsigned char res[4];
+
+    if (p->op[AVR_OP_CHIP_ERASE] == NULL)
+    {
+        pmsg_error("chip erase instruction not defined for part %s\n", p->desc);
+        return -1;
+    }
+
+    pgm->pgm_led(pgm, ON);
+
+    memset(cmd, 0, sizeof(cmd));
+
+    avr_set_bits(p->op[AVR_OP_CHIP_ERASE], cmd);
+    pgm->cmd(pgm, cmd, res);
+    usleep(p->chip_erase_delay);
+
+    pgm->initialize(pgm, p);
+
+    pgm->pgm_led(pgm, OFF);
+
+    return 0;
+}
+
+static int usbisp3_open(PROGRAMMER* pgm, const char* port)
+{
+    uint8_t u8Buff[64];
+
+    if (KT_WinUSB_OpenVidPid(0x03eb, 0xc8b4))
+    {
+        uint8_t ser[100];
+        char szSer[100];
+        uint32_t len;
+
+        if (WinUsb_GetDescriptor(hWinUsb, USB_STRING_DESCRIPTOR_TYPE, 3, 3, ser, 100, (PULONG)&len))
+        {
+            if (len > 64)
+            {
+                KT_WinUSB_Close();
+                return -1;
+            }
+            if (len != ser[0])
+            {
+                KT_WinUSB_Close();
+                return -1;
+            }
+            uint32_t i;
+            for (i = 0; i < (len / 2 - 1); ++i)
+            {
+                szSer[i] = ser[2 + i * 2];
+            }
+            szSer[i] = 0;
+            if (strcmpi(szSer, szSerialVer))
+            {
+                pmsg_error("Wrong firmware version\n");
+                KT_WinUSB_Close();
+                return -1;
+            }
+            u8Buff[0] = 0x00;
+            if (!KT_WinUSB_Write(0x01, u8Buff, 64))
+            {
+                pmsg_error("USB IO: FAILED\n");
+                return -1;
+            }
+            if (!KT_WinUSB_Read(0x81, u8Buff, 64)) {
+                pmsg_error("USB IO: FAILED\n");
+                return -1;
+            }
+            if (strcmpi((char *)u8Buff, szFirmwareVer))
+            {
+                pmsg_error("Wrong firmware version\n");
+                KT_WinUSB_Close();
+                return -1;
+            }
+
+            return 0;
+        }
+        else
+        {
+            KT_WinUSB_Close();
+            return -1;
+        }
+
+        return -1;
+    }
+
+    return -1;
+}
+
+static void usbisp3_close(PROGRAMMER* pgm)
+{
+
+    KT_WinUSB_Close();
+}
+
+static int usbisp3_cmd(const PROGRAMMER* pgm, const unsigned char* cmd,
+    unsigned char* res)
+{
+
+    return pgm->spi(pgm, cmd, res, 4);
+}
+
+static uint32_t usbisp3_spi_exch_n(const PROGRAMMER* pgm, uint32_t u32Length, uint8_t* pu8Send, uint8_t* pu8Recv)
+{
+    uint8_t u8Buff[64];
+
+    u8Buff[0] = 0x03;
+    u8Buff[1] = (u32Length);
+    u8Buff[2] = (u32Length >> 8);
+    u8Buff[3] = (0);
+    u8Buff[4] = (0);
+
+    if (!KT_WinUSB_Write(0x01, u8Buff, 64)) {
+        return 0;
+    }
+
+    if (!KT_WinUSB_Write(0x01, pu8Send, u32Length)) {
+        return 0;
+    }
+
+    u8Buff[0] = 0x25;
+    u8Buff[1] = (u32Length);
+    u8Buff[2] = (u32Length >> 8);
+    u8Buff[3] = (0);
+    u8Buff[4] = (0);
+
+    if (!KT_WinUSB_Write(0x01, u8Buff, 64)) {
+        return 0;
+    }
+
+    u8Buff[0] = 0x04;
+    u8Buff[1] = (u32Length);
+    u8Buff[2] = (u32Length >> 8);
+    u8Buff[3] = (u32Length >> 16);
+    u8Buff[4] = (u32Length >> 24);
+
+    if (!KT_WinUSB_Write(0x01, u8Buff, 64)) {
+        return 0;
+    }
+
+    return KT_WinUSB_Read(0x81, pu8Recv, u32Length);
+}
+
+static uint32_t usbisp3_avr_read_flash(const PROGRAMMER* pgm, uint16_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[8 * 1024];
+    u16Length >>= 1;
+    u16Address >>= 1;
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+
+    for (i = 0; i < u16Length; ++i) {
+        *p = 0x20;
+        ++p;
+        *p = (u16Address >> 8);
+        ++p;
+        *p = (u16Address);
+        ++p;
+        *p = 0x00;
+        ++p;
+
+        *p = 0x28;
+        ++p;
+        *p = (u16Address >> 8);
+        ++p;
+        *p = (u16Address);
+        ++p;
+        *p = 0x00;
+        ++p;
+
+        ++u16Address;
+    }
+
+    if (usbisp3_spi_exch_n(pgm, u16Length * 8, u8SendBuff, u8SendBuff)) {
+        p = pu8Data;
+        for (i = 0; i < u16Length; ++i) {
+            *p = u8SendBuff[i * 8 + 3];
+            ++p;
+            *p = u8SendBuff[i * 8 + 7];
+            ++p;
+        }
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
+static uint32_t usbisp3_avr_read_eeprom(const PROGRAMMER* pgm, uint16_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[8 * 1024];
+
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+
+    for (i = 0; i < u16Length; ++i) {
+        *p = 0xA0;
+        ++p;
+        *p = (u16Address >> 8);
+        ++p;
+        *p = (u16Address);
+        ++p;
+        *p = 0x00;
+        ++p;
+
+        ++u16Address;
+    }
+
+    if (usbisp3_spi_exch_n(pgm, u16Length * 4, u8SendBuff, u8SendBuff)) {
+        p = pu8Data;
+        for (i = 0; i < u16Length; ++i) {
+            *p = u8SendBuff[i * 4 + 3];
+            ++p;
+        }
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
+static uint32_t usbisp3_avr_write_flash(const PROGRAMMER* pgm, uint32_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[1024];
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+    uint8_t* pS;
+    pS = pu8Data;
+    uint16_t u16TmpAddress;
+    uint16_t u16Pos = 0;
+    uint8_t u8Poll;
+
+    if (u16Length < 16) {
+        u16TmpAddress = 0;
+        p = u8SendBuff;
+        pS = pu8Data;
+        for (i = 0; i < (u16Length / 2); ++i) {
+            *p = 0x40;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            *p = 0x48;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            ++u16TmpAddress;
+        }
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, u16Length * 4)) {
+            return 0;
+        }
+        
+        u8SendBuff[0] = 0x4c;
+        u8SendBuff[1] = (u16Address >> 9);
+        u8SendBuff[2] = (u16Address >> 1);
+        u8SendBuff[3] = 0x00;
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+            return 0;
+        }
+        
+        for (i = 0; i < u16Length; ++i) {
+            if (pu8Data[i] != 0xff) {
+                u16Pos = i;
+                break;
+            }
+        }
+        if (u16Pos != u16Length) {
+            if (u16Pos % 2) {
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x28;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+            else {
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x20;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+        }
+        else {
+            Sleep(10);
+            return 1;
+        }
+    }
+    else {
+        u16TmpAddress = 0;
+        p = u8SendBuff;
+        pS = pu8Data;
+        for (i = 0; i < (u16Length / 2); ++i) {
+            *p = 0x40;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            *p = 0x48;
+            ++p;
+            *p = (u16TmpAddress >> 8);
+            ++p;
+            *p = (u16TmpAddress);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+
+            ++u16TmpAddress;
+        }
+        if (!usbisp3_spi_exch_n(pgm, u16Length * 4, u8SendBuff, u8SendBuff)) {
+            return 0;
+        }
+
+        u8SendBuff[0] = 0x4c;
+        u8SendBuff[1] = (u16Address >> 9);
+        u8SendBuff[2] = (u16Address >> 1);
+        u8SendBuff[3] = 0x00;
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+            return 0;
+        }
+
+        for (i = 0; i < u16Length; ++i) {
+            if (pu8Data[i] != 0xff) {
+                u16Pos = i;
+                break;
+            }
+        }
+        if (u16Pos != u16Length) {
+
+            if (u16Pos % 2) {
+
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x28;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+            else {
+                u16TmpAddress = u16Address + u16Pos;
+                u16TmpAddress >>= 1;
+                u8Poll = 0;
+                for (i = 0; i < 1000; ++i) {
+                    u8SendBuff[0] = 0x20;
+                    u8SendBuff[1] = (u16TmpAddress >> 8);
+                    u8SendBuff[2] = (u16TmpAddress);
+                    u8SendBuff[3] = 0x00;
+                    if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                        return 0;
+                    }
+                    if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                        u8Poll = 1;
+                        break;
+                    }
+                }
+                if (u8Poll) {
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+        }
+        else {
+            Sleep(10);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static uint32_t usbisp3_avr_write_eeprom(const PROGRAMMER* pgm, uint32_t u16Address, uint16_t u16Length, uint8_t* pu8Data)
+{
+    uint8_t u8SendBuff[1024];
+    uint32_t i;
+    uint8_t* p;
+    p = u8SendBuff;
+    uint8_t* pS;
+    pS = pu8Data;
+    uint16_t u16TmpAddress;
+    uint16_t u16Pos = 0;
+    uint8_t u8Poll;
+
+    if (u16Length != 0x01) {
+        
+        u16TmpAddress = 0;
+        p = u8SendBuff;
+        pS = pu8Data;
+        for (i = 0; i < u16Length; ++i) {
+            *p = 0xC1;
+            ++p;
+            *p = (i >> 8);
+            ++p;
+            *p = (i);
+            ++p;
+            *p = *pS;
+            ++pS;
+            ++p;
+        }
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, u16Length * 4)) {
+            return 0;
+        }
+        for (i = 0; i < u16Length; ++i) {
+            if (pu8Data[i] != 0xff) {
+                u16Pos = i;
+                break;
+            }
+        }
+        if (u16Pos != u16Length) {
+            u8Poll = 0;
+            for (i = 0; i < 1000; ++i) {
+                u8SendBuff[0] = 0xA0;
+                u8SendBuff[1] = ((u16Address + u16Pos) >> 8);
+                u8SendBuff[2] = (u16Address + u16Pos);
+                u8SendBuff[3] = 0x00;
+                if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                    return 0;
+                }
+                if (u8SendBuff[3] == pu8Data[u16Pos]) {
+                    u8Poll = 1;
+                    break;
+                }
+            }
+            if (u8Poll) {
+                return 1;
+            }
+            else {
+                return 0;
+            }
+        }
+        else {
+            Sleep(10);
+            return 1;
+        }
+    }
+    else {
+        u8SendBuff[0] = 0xC0;
+        u8SendBuff[1] = (u16Address >> 8);
+        u8SendBuff[2] = (u16Address);
+        u8SendBuff[3] = pu8Data[0];
+        if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+            return 0;
+        }
+        u8Poll = 0;
+        for (i = 0; i < 1000; ++i) {
+            u8SendBuff[0] = 0xA0;
+            u8SendBuff[1] = (u16Address >> 8);
+            u8SendBuff[2] = (u16Address);
+            u8SendBuff[3] = 0x00;
+            if (!usbisp3_spi_exch(pgm, u8SendBuff, u8SendBuff, 4)) {
+                return 0;
+            }
+            if (u8SendBuff[3] == pu8Data[0]) {
+                u8Poll = 1;
+                break;
+            }
+        }
+        if (u8Poll) {
+            return 1;
+        }
+        else {
+            return 0;
+        }
+    }
+
+    return 0;
+}
+
+static int  usbisp3_paged_write(const PROGRAMMER* pgm, const AVRPART* p, const AVRMEM* mem,
+    unsigned int page_size, unsigned int addr, unsigned int n_bytes)
+{
+    if ((!mem->paged || page_size <= 1) || (strcmp(mem->desc, "flash") != 0 && strcmp(mem->desc, "eeprom") != 0))
+    {
+        return -1;
+    }
+
+    if (strcmp(mem->desc, "flash") == 0)
+    {
+        OPCODE* readop = 0, * lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+        uint8_t data = 0, cmd[64], res[64];
+
+        if (lext) {
+            memset(cmd, 0, sizeof(cmd));
+            avr_set_bits(lext, cmd);
+            avr_set_addr(lext, cmd, addr / 2);
+            pgm->cmd(pgm, cmd, res);
+        }
+
+        if (usbisp3_avr_write_flash(pgm, addr, n_bytes, &mem->buf[addr]))
+        {
+            return 0;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+    if (usbisp3_avr_write_eeprom(pgm, addr, n_bytes, &mem->buf[addr]))
+    {
+        return 0;
+    }
+    else
+    {
+        return -1;
+    }
+
+    return -1;
+}
+
+static int usbisp3_paged_load(const PROGRAMMER* pgm, const AVRPART* p, const AVRMEM* mem,
+    unsigned int page_size, unsigned int addr, unsigned int n_bytes)
+{
+
+    // only supporting flash & eeprom page reads
+    if ((!mem->paged || page_size <= 1) || (strcmp(mem->desc, "flash") != 0 && strcmp(mem->desc, "eeprom") != 0))
+    {
+        return -1;
+    }
+
+    if (strcmp(mem->desc, "flash") == 0)
+    {
+        OPCODE* readop = 0, * lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+        uint8_t data = 0, cmd[64], res[64];
+
+        if (lext) {
+            memset(cmd, 0, sizeof(cmd));
+            avr_set_bits(lext, cmd);
+            avr_set_addr(lext, cmd, addr / 2);
+            pgm->cmd(pgm, cmd, res);
+        }
+
+        if (usbisp3_avr_read_flash(pgm, addr, n_bytes, &mem->buf[addr]))
+        {
+            return 0;
+        }
+        else
+        {
+            return -1;
+        }
+    }
+
+    if (usbisp3_avr_read_eeprom(pgm, addr, n_bytes, &mem->buf[addr]))
+    {
+        return 0;
+    }
+    else
+    {
+        return -1;
+    }
+
+    return -1;
+}
+
+static int  usbisp3_parseextparams(const PROGRAMMER* pgm, const LISTID extparms)
+{
+
+    return 0;
+}
+
+void usbisp3_initpgm(PROGRAMMER* pgm)
+{
+    pgm->initialize = usbisp3_initialize;
+    pgm->display = usbisp3_display;
+    pgm->enable = usbisp3_enable;
+    pgm->disable = usbisp3_disable;
+    pgm->powerdown = usbisp3_powerdown;
+    pgm->program_enable = usbisp3_program_enable;
+    pgm->chip_erase = usbisp3_chip_erase;
+    pgm->open = usbisp3_open;
+    pgm->close = usbisp3_close;
+    pgm->spi = usbisp3_spi_exch;
+
+    pgm->read_byte = avr_read_byte_default;
+    pgm->write_byte = avr_write_byte_default;
+
+    pgm->cmd = usbisp3_cmd;
+    pgm->paged_write = usbisp3_paged_write;
+    pgm->paged_load = usbisp3_paged_load;
+
+    pgm->parseextparams = usbisp3_parseextparams;
+
+    strncpy(pgm->type, "usbisp3", sizeof(pgm->type));
+}
+
+uint32_t KT_WinUSB_OpenVidPid(uint32_t vid, uint32_t pid)
+{
+    connected = 0;
+    HANDLE hDevInfoSet;
+
+    GUID hidGuid = { 0xdee824ef, 0x729b, 0x4a0e, 0x9c, 0x14, 0xb7, 0x11, 0x7d, 0x33, 0xa8,  0x17 };
+
+    hDevInfoSet = SetupDiGetClassDevsA(&hidGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+    if (!hDevInfoSet) {
+        return 0;
+    }
+    DWORD dwRes;
+    DWORD dwStatus;
+    DWORD dwInterfaceIndex = 0;
+    SP_DEVICE_INTERFACE_DATA devInterfaceData;
+    SP_DEVICE_INTERFACE_DETAIL_DATA detail;
+    devInterfaceData.cbSize = sizeof(devInterfaceData);
+    char* pBuff;
+    SP_DEVINFO_DATA devInfoData;
+    DWORD dwRegType, dwRegSize;
+    DWORD dwFound = 0;
+    while (1) {
+        dwRes = SetupDiEnumDeviceInterfaces(hDevInfoSet, NULL, &hidGuid, dwInterfaceIndex, &devInterfaceData);
+        if (dwRes) {
+            dwStatus = GetLastError();
+        }
+        else {
+            return 0;
+        }
+        
+        if (dwStatus == ERROR_NO_MORE_ITEMS) {
+            return 0;
+        }
+        
+        devInfoData.cbSize = sizeof(devInfoData);
+        SetupDiEnumDeviceInfo(hDevInfoSet, dwInterfaceIndex, &devInfoData);
+
+        SetupDiGetDeviceRegistryPropertyA(hDevInfoSet, &devInfoData, SPDRP_HARDWAREID, &dwRegType, NULL, 0, &dwRegSize);
+
+        pBuff = (char*)malloc(dwRegSize);
+        if (!pBuff) {
+            return 0;
+        }
+        
+        SetupDiGetDeviceRegistryPropertyA(hDevInfoSet, &devInfoData, SPDRP_HARDWAREID, &dwRegType, (unsigned char*)pBuff, dwRegSize, NULL);
+        
+        char szVid[100];
+        char szPid[100];
+        char* p;
+        wsprintfA(szPid, "pid_%04x", pid);
+        wsprintfA(szVid, "vid_%04x&", vid);
+        lstrcatA(szVid, szPid);
+        DWORD dwLen, dwJ;
+        dwLen = lstrlenA(pBuff);
+        for (dwJ = 0; dwJ < dwLen; ++dwJ) {
+            if (pBuff[dwJ] >= 'A' && pBuff[dwJ] <= 'Z')
+                pBuff[dwJ] += 0x20;
+        }
+        p = strstr(pBuff, szVid);
+        if (p) {
+            dwFound = 1;
+            break;
+        }
+        ++dwInterfaceIndex;
+    }
+
+    if (dwFound) {
+    }
+    else {
+        return 0;
+    }
+
+    memset(&detail, 0, sizeof(detail));
+    detail.cbSize = sizeof(detail);
+    DWORD dwSize = 0;
+    SetupDiGetDeviceInterfaceDetail(hDevInfoSet, &devInterfaceData, NULL, 0, &dwSize, NULL);
+    PSP_DEVICE_INTERFACE_DETAIL_DATA ktNew;
+    ktNew = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(dwSize);
+    if (!ktNew) {
+        return 0;
+    }
+    ktNew->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
+    SetupDiGetDeviceInterfaceDetail(hDevInfoSet, &devInterfaceData, ktNew, dwSize, NULL, NULL);
+
+    hUsb = CreateFile(ktNew->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+    if (!hUsb) {
+        return 0;
+    }
+    if (!WinUsb_Initialize(hUsb, &hWinUsb)) {
+        return 0;
+    }
+    
+    connected = 1;
+    return 1;
+}
+
+void KT_WinUSB_Close(void)
+{
+
+    if (connected)
+    {
+        connected = 0;
+        CloseHandle(hUsb);
+        WinUsb_Free(hWinUsb);
+    }
+}
+
+uint32_t KT_WinUSB_Read(uint8_t ep, uint8_t* p_data, uint32_t length)
+{
+    DWORD len;
+
+    ov.hEvent = CreateEventA(NULL, TRUE, FALSE, "KT_WinUsb");
+    if (ov.hEvent == NULL)
+    {
+        return 0;
+    }
+    DWORD dwTimeOut = 5000;
+
+    WinUsb_SetPipePolicy(hWinUsb, 0x81, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &dwTimeOut);
+
+    WinUsb_ReadPipe(hWinUsb, ep | 0x80, buff, length, &len, &ov);
+    DWORD dwTrans;
+
+    WinUsb_GetOverlappedResult(hWinUsb, &ov, &dwTrans, TRUE);
+    if (dwTrans != length) {
+        CloseHandle(ov.hEvent);
+        return 0;
+    }
+
+    memmove(p_data, buff, length);
+    CloseHandle(ov.hEvent);
+    return 1;
+}
+
+uint32_t KT_WinUSB_Write(uint8_t ep, uint8_t* p_data, uint32_t length)
+{
+    DWORD len;
+
+    memmove(buff, p_data, length);
+
+    return WinUsb_WritePipe(hWinUsb, ep, buff, length, &len, NULL);
+}
diff --git a/src/usbisp3.h b/src/usbisp3.h
new file mode 100644
index 00000000..1d54d750
--- /dev/null
+++ b/src/usbisp3.h
@@ -0,0 +1,15 @@
+#ifndef USBISP3_H_
+#define USBISP3_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+    extern const char usbisp3_desc[];
+    void usbisp3_initpgm(PROGRAMMER* pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif