Index: Makefile.am
===================================================================
--- Makefile.am	(Revision 1356)
+++ Makefile.am	(Arbeitskopie)
@@ -66,7 +66,7 @@
 libavrdude_a_CFLAGS   = @ENABLE_WARNINGS@
 libavrdude_la_CFLAGS  = $(libavrdude_a_CFLAGS)
 
-avrdude_LDADD  = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB_1_0@ @LIBUSB@ @LIBFTDI1@ @LIBFTDI@ @LIBHID@ @LIBELF@ @LIBPTHREAD@ -lm
+avrdude_LDADD  = $(top_builddir)/$(noinst_LIBRARIES) @LIBUSB_1_0@ @LIBHIDAPI@ @LIBUSB@ @LIBFTDI1@ @LIBFTDI@ @LIBHID@ @LIBELF@ @LIBPTHREAD@ -lm
 
 bin_PROGRAMS = avrdude
 
@@ -145,6 +145,8 @@
 	pgm_type.c \
 	pickit2.c \
 	pickit2.h \
+	mcprog.c \
+	mcprog.h \
 	pindefs.c \
 	ppi.c \
 	ppi.h \
Index: avrdude.conf.in
===================================================================
--- avrdude.conf.in	(Revision 1356)
+++ avrdude.conf.in	(Arbeitskopie)
@@ -1124,6 +1124,13 @@
 ;
 
 programmer
+  id    = "mcprog";
+  desc  = "mcprog is based on Microchip's MCP2210, a USB to SPI master IC";
+  type  = "mcprog";
+  connection_type = usb;
+;
+
+programmer
   id    = "flip1";
   desc  = "FLIP USB DFU protocol version 1 (doc7618)";
   type  = "flip1";
@@ -4255,6 +4262,29 @@
 
 
 #------------------------------------------------------------
+# ATmega164A
+#------------------------------------------------------------
+
+# close to ATmega16
+
+part parent "m16"
+    id               = "m164a";
+    desc             = "ATmega164A";
+    signature        = 0x1e 0x94 0x0f;
+
+    progmodedelay       = 0;
+    latchcycles         = 5;
+    togglevtg           = 1;
+    poweroffdelay       = 15;
+    resetdelayms        = 1;
+    allowfullpagebitstream = no;
+    chip_erase_delay = 55000;
+
+    ocdrev              = 3;
+  ;
+
+
+#------------------------------------------------------------
 # ATmega164P
 #------------------------------------------------------------
 
@@ -8170,6 +8200,21 @@
 ;
 
 #------------------------------------------------------------
+# ATmega16m1
+#------------------------------------------------------------
+
+part parent "m168"
+    id              = "m16m1";
+    desc            = "ATmega16M1";
+    # stk500_devcode	= 0x;
+    # avr910_devcode	= 0x;
+    signature       = 0x1e 0x94 0x84;
+    bs2             = 0xe2;
+
+;
+
+
+#------------------------------------------------------------
 # ATtiny88
 #------------------------------------------------------------
 
Index: configure.ac
===================================================================
--- configure.ac	(Revision 1356)
+++ configure.ac	(Arbeitskopie)
@@ -150,6 +150,25 @@
    AC_CHECK_HEADERS([libusb.h])
 fi
 AC_SUBST(LIBUSB_1_0, $LIBUSB_1_0)
+
+AH_TEMPLATE([HAVE_LIBHIDAPI],
+            [Define if HID support is enabled via libhidapi])
+AC_SEARCH_LIBS([hid_init], [hidapi hidapi-libusb hidapi-hidraw], [have_libhidapi=yes])
+if test x$have_libhidapi = xyes; then
+   case $target in
+       *-*-darwin*)
+               LIBHIDAPI="-lhidapi -iframework CoreFoundation -framework IOKit"
+               ;;
+       *)
+               LIBHIDAPI="$ac_cv_lib_hid_init"
+               ;;
+   esac
+   AC_DEFINE([HAVE_LIBHIDAPI])
+   AC_CHECK_HEADERS([hidapi/hidapi.h])
+fi
+AC_SUBST(LIBHIDAPI, $LIBHIDAPI)
+
+
 AH_TEMPLATE([HAVE_LIBFTDI1],
             [Define if FTDI support is enabled via libftdi1])
 AH_TEMPLATE([HAVE_LIBFTDI],
@@ -499,6 +518,12 @@
    echo "DON'T HAVE libusb_1_0"
 fi
 
+if test x$have_libhidapi = xyes; then
+   echo "DO HAVE     libhidapi"
+else
+   echo "DON'T HAVE  libhidapi"
+fi
+
 if test x$have_libftdi1 = xyes; then
    echo "DO HAVE    libftdi1"
 else
Index: mcprog.c
===================================================================
--- mcprog.c	(Revision 0)
+++ mcprog.c	(Arbeitskopie)
@@ -0,0 +1,1025 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2005 Erik Walthinsen
+ * Copyright (C) 2002-2004 Brian S. Dean <bsd@bsdhome.com>
+ * Copyright (C) 2006 David Moore
+ * Copyright (C) 2006,2007 Joerg Wunsch <j@uriah.heep.sax.de>
+ *
+ * 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/>.
+ */
+
+/* $Id: pickit2.c 2010-05-03 dbrown$ */
+/* Based on Id: stk500v2.c 836 2009-07-10 22:39:37Z joerg_wunsch */
+
+/*
+ * avrdude interface for mcprog programmer
+ *
+ * The mcprog programmer is one-chip solution,
+ * based on an MCP2210 USB to SPI master bridge IC.
+ */
+
+#include "ac_cfg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include "avrdude.h"
+#include "libavrdude.h"
+
+#if defined(HAVE_LIBHIDAPI)
+
+#include <hidapi/hidapi.h>
+
+#define MCP2210_VID 0x04d8
+#define MCP2210_PID 0x00DE
+
+#define SPI_MAX_CHUNK (64 - 4)    // max packet size less the command overhead
+
+//static int usb_open_device(struct usb_dev_handle **dev, int vid, int pid);
+//#define INVALID_HANDLE_VALUE NULL
+//#define USB_ERROR_NONE      0
+//#define USB_ERROR_ACCESS    1
+//#define USB_ERROR_NOTFOUND  2
+//#define USB_ERROR_BUSY      16
+//#define USB_ERROR_IO        5
+
+#define DEBUG(...) ((void)0)
+
+static int mcprog_write_report(PROGRAMMER *pgm, const unsigned char report[65]);
+static int mcprog_read_report(PROGRAMMER *pgm, unsigned char report[65]);
+
+#ifndef MIN
+#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
+#endif
+
+/*
+ * Private data for this programmer.
+ */
+struct pdata
+{
+    hid_device *hidapi_handle;
+    uint8_t clock_period;  // SPI clock period in us
+    uint8_t use_pgm_led;
+    uint8_t gpios[65];
+
+
+    //int transaction_timeout;    // usb trans timeout in ms
+};
+
+#define PDATA(pgm) ((struct pdata *)(pgm->cookie))
+
+
+static void mcprog_setup(PROGRAMMER * pgm)
+{
+    if ((pgm->cookie = malloc(sizeof(struct pdata))) == 0)
+    {
+        avrdude_message(MSG_INFO, "%s: mcprog_setup(): Out of memory allocating private data\n",
+                        progname);
+        exit(1);
+    }
+    memset(pgm->cookie, 0, sizeof(struct pdata));
+
+    //PDATA(pgm)->transaction_timeout = 1500;    // default value, may be overridden with -x timeout=ms
+    PDATA(pgm)->clock_period = 30;    // default value, may be overridden with -x clockrate=us or -B or -i
+    PDATA(pgm)->use_pgm_led = 1;      // default is on, may be overridden with -x use_pgm_led=0
+}
+
+static int mcprog_set_spi_settings(PROGRAMMER * pgm, unsigned short spi_len)
+{
+    static unsigned char report[65] = {0, 0x41}; // get current spi settings
+    static int initialized = 0;
+    static int _spi_len = -1;
+    static int _clk = -1;
+    int errorCode;
+  
+  
+    int clock_rate = (int)(3000000 / (PDATA(pgm)->clock_period + 5e-7));    // assume highest speed is 3MHz - should probably check this
+
+    if ((_clk == clock_rate) && (_spi_len == spi_len))
+    {
+        return 1;
+    }
+
+    _spi_len = spi_len;
+    _clk = clock_rate;
+
+    if (!initialized) {
+        initialized = 1;
+        // Get SPI settings
+        if ((errorCode = mcprog_write_report(pgm, report)) < 0)
+	{
+	    avrdude_message(MSG_INFO, "mcprog get SPI settings failed horribly: (ec %d). %s\n", errorCode,  -1/*usb_strerror()*/);
+	    return -1;
+	}
+	else
+	{
+	    if ((errorCode = mcprog_read_report(pgm, report)) <= 0) // read SPI settings
+	    {
+	        return -1; // something went wrong ... TBD
+	    }    
+	}
+    }
+    //Set SPI settings
+    report[0] = 0x00;
+    report[1] = 0x40;
+    report[2] = 0x00;
+    report[3] = 0x00;
+    report[4] = 0x00;
+    report[5] = (clock_rate >>  0) & 0xff;
+    report[6] = (clock_rate >>  8) & 0xff;
+    report[7] = (clock_rate >> 16) & 0xff;
+    report[8] = (clock_rate >> 24) & 0xff;
+    report[19] = (spi_len >> 0) & 0xff;
+    report[20] = (spi_len >> 8) & 0xff;
+    if (mcprog_write_report(pgm, report) < 0)
+    {
+        avrdude_message(MSG_INFO, "mcprog: setting SPI settings failed horribly: (ec %d). %s\n", errorCode,  -1/*usb_strerror()*/);
+	return -1;
+    }
+    else
+    {
+        if ((errorCode = mcprog_read_report(pgm, report)) <= 0) // dummy read to satisfy MCP2210
+	{
+	    return -1; // something went wrong ... TBD
+	}
+	else {
+	    //avrdude_message(MSG_INFO, "readback of new SPI settings worked!\n", progname, pgm->desc);
+	}
+    
+    }
+    return 1;
+}
+
+static void mcprog_teardown(PROGRAMMER * pgm)
+{
+    free(pgm->cookie);
+}
+
+static int mcprog_open(PROGRAMMER * pgm, char * port)
+{
+    hid_device *hidapi_handle;
+
+    hidapi_handle = hid_open(MCP2210_VID, MCP2210_PID, NULL);
+    if (hidapi_handle == NULL)
+    {
+        /* no mcprog found */
+        avrdude_message(MSG_INFO, "%s: error: could not find mcprog with vid=0x%x pid=0x%x\n",
+                        progname, MCP2210_VID, MCP2210_PID);
+        return -1;
+    }
+    PDATA(pgm)->hidapi_handle = hidapi_handle;
+
+    if (pgm->ispdelay > 0)
+    {
+        PDATA(pgm)->clock_period = MIN(pgm->ispdelay * 3, 255);
+    }
+    else if (pgm->bitclock > 0.0)
+    {
+        PDATA(pgm)->clock_period = MIN(pgm->bitclock * 3 * 1e6, 255);
+    }
+
+    uint8_t r[65] =
+        { 
+          0, 0x30,0,0,0,
+          0x01, 0x00
+        };
+    memcpy(PDATA(pgm)->gpios, r, 65);
+
+    return 0;
+}
+
+
+static void mcprog_close(PROGRAMMER * pgm)
+{
+    // set the pins, apply reset
+    // i.e. set GPIO config
+    int errorCode = 0;
+    
+    uint8_t report[65] = {0,};
+
+    uint8_t *r = PDATA(pgm)->gpios;
+    r[5] |= (0x01);
+    if (mcprog_write_report(pgm, r) < 0)
+    {
+        avrdude_message(MSG_INFO, "mcprog: couldn't release reset: (ec %d). %s\n", errorCode, -1/*usb_strerror()*/);
+        return;
+    }
+    else
+    {
+        if ((errorCode = mcprog_read_report(pgm, report)) <= 0) // dummy read to satisfy MCP2210
+        {
+            return; // something went wrong ... TBD
+        }
+        
+    }
+    
+    
+    hid_close(PDATA(pgm)->hidapi_handle);
+}
+
+
+static int mcprog_initialize(PROGRAMMER * pgm, AVRPART * p)
+{
+    unsigned char temp[4];
+    memset(temp, 0, sizeof(temp));
+
+    int errorCode = 0;
+
+    /* set sck period */
+    //if (pgm->set_sck_period)
+    //    pgm->set_sck_period(pgm, pgm->bitclock);
+
+    // reset any eventually still ongoing transfers so we can then configure the SPI settings etc
+    static const unsigned char report[65] = {0, 0x11};
+    if ((errorCode = mcprog_write_report(pgm, report)) > 0)
+    {
+        unsigned char report[65] = {0};
+        if ((errorCode = mcprog_read_report(pgm, report)) >= 0)
+        {
+            // set the pins to desired function
+            // i.e. set GPIO config
+            uint8_t gpio_config[65] = 
+                {
+                    0, 0x21, 0, 0, 0,
+                    0,1,0,0,0,2,0,0,0,
+                    0,0,0,0x01,0,0,0,0,0,0,0
+                };
+
+
+            if (mcprog_write_report(pgm, gpio_config) < 0)
+            {
+                avrdude_message(MSG_INFO, "mcprog write gpio config failed (ec %d). %s\n", errorCode, -1/*usb_strerror()*/);
+                return -1;
+            }
+            else
+            {
+                if ((errorCode = mcprog_read_report(pgm, report)) <= 0) // dummy read to satisfy MCP2210
+                {
+                    return -1; // something went wrong ... TBD
+                }
+
+            }
+
+	    if (mcprog_set_spi_settings(pgm, 4) < 0)
+            {
+                return -1;
+	    }
+
+            uint8_t *r = PDATA(pgm)->gpios;
+            r[5] &= ~(0x01); // set atmegas RESET Low to enter programming mode
+            if (mcprog_write_report(pgm, r) < 0)
+            {
+                avrdude_message(MSG_INFO, "mcprog: couldn't set reset: (ec %d). %s\n", errorCode, -1/*usb_strerror()*/);
+                return -1;
+            }
+            else
+            {
+                if ((errorCode = mcprog_read_report(pgm, report)) <= 0) // dummy read to satisfy MCP2210
+                {
+                    return -1; // something went wrong ... TBD
+                }
+
+            }
+
+        }
+        else
+        {
+            avrdude_message(MSG_INFO, "mcprog_read_report failed (ec %d). %s\n", errorCode, -1/*usb_strerror()*/);
+            return -1;
+        }
+    }
+    else
+    {
+        avrdude_message(MSG_INFO, "mcprog_write_report failed (ec %d). %s\n", errorCode, -1/*usb_strerror()*/);
+        return -1;
+    }
+
+    if (pgm->program_enable)
+    {
+        return pgm->program_enable(pgm, p);
+    }
+    else
+        return -1;
+}
+
+
+static void mcprog_disable(PROGRAMMER * pgm)
+{
+    /* make sure all pins are floating & all voltages are off */
+    /*
+    static const unsigned char report[65] =
+    {
+        0, CMD_EXEC_SCRIPT_2(8),
+        SCR_SET_PINS_2(1,1,0,0),
+        SCR_SET_AUX_2(1,0),
+        SCR_MCLR_GND_OFF,
+        SCR_VPP_OFF,
+        SCR_VDD_OFF,
+        SCR_BUSY_LED_OFF,
+        CMD_END_OF_BUFFER
+    };
+
+    mcprog_write_report(pgm, report);
+    */
+    return;
+}
+
+
+static void mcprog_enable(PROGRAMMER * pgm)
+{
+    /* Do nothing. */
+
+    return;
+}
+
+static void mcprog_display(PROGRAMMER * pgm, const char * p)
+{
+    DEBUG( "%s: Found \"%s\" version %d.%d.%d\n", progname, p, 1, 1, 1);
+    return;
+}
+
+#define sendReport(x)
+#define readReport(x) 0
+
+#if 0
+static int  mcprog_rdy_led        (struct programmer_t * pgm, int value)
+{
+    // no rdy led
+    return 0;
+}
+#endif
+
+static int  mcprog_err_led(struct programmer_t * pgm, int value)
+{
+    uint8_t report[65] = {0,};
+    uint8_t *r = PDATA(pgm)->gpios;
+    int errorCode;
+
+    if (value) 
+    {
+        r[5] |= (0x80);
+    }
+    else
+    {
+        r[5] &= ~(0x80);
+    }
+
+    if ((errorCode = mcprog_write_report(pgm, r)) < 0)
+    {
+        avrdude_message(MSG_INFO, "mcprog: couldn't set PROG LED: (ec %d). %s\n", errorCode, -1/*usb_strerror()*/);
+        return -1;
+    }
+    else
+    {
+        if ((errorCode = mcprog_read_report(pgm, report)) <= 0) // dummy read to satisfy MCP2210
+        {
+            return -1; // something went wrong ... TBD
+        }
+        
+    }
+
+    return 1;
+}
+
+static int  mcprog_pgm_led (struct programmer_t * pgm, int value)
+{
+    uint8_t *r = PDATA(pgm)->gpios;
+    uint8_t report[65] = {0,};
+    int errorCode;
+
+    if (PDATA(pgm)->use_pgm_led) {
+        if (value) 
+        {
+            r[5] |=  (0x40);
+        }
+        else
+        {
+            r[5] &= ~(0x40);
+        }
+
+        if ((errorCode = mcprog_write_report(pgm, r)) < 0)
+        {
+            avrdude_message(MSG_INFO, "mcprog: couldn't set PROG LED: (ec %d). %s\n", errorCode, -1/*usb_strerror()*/);
+            return -1;
+        }
+        else
+        {
+            if ((errorCode = mcprog_read_report(pgm, report)) <= 0) // dummy read to satisfy MCP2210
+            {
+                return -1; // something went wrong ... TBD
+            }
+        
+        }
+        
+    }    
+    return 1;
+}
+
+
+static int  mcprog_vfy_led        (struct programmer_t * pgm, int value)
+{
+    // no such thing - maybe just call pgm_led
+
+    return pgm->pgm_led(pgm, value);
+}
+
+static void mcprog_powerup(struct programmer_t * pgm)
+{
+    // turn vdd on?
+}
+
+static void mcprog_powerdown(struct programmer_t * pgm)
+{
+    // do what?
+    pgm->disable(pgm);
+}
+
+static int  mcprog_program_enable(struct programmer_t * pgm, AVRPART * p)
+{
+    unsigned char cmd[4];
+    unsigned char res[4];
+
+    if (p->op[AVR_OP_PGM_ENABLE] == NULL)
+    {
+        avrdude_message(MSG_INFO, "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;
+        avrdude_message(MSG_DEBUG, "program_enable(): sending command. Resp = ");
+
+        for (i = 0; i < 4; i++)
+        {
+            avrdude_message(MSG_DEBUG, "%x ", (int)res[i]);
+        }
+        avrdude_message(MSG_DEBUG, "\n");
+    }
+
+    // check for sync character
+    if (res[2] != cmd[1])
+    {
+        //avrdude_message(MSG_INFO, "program_enable(): FAILED!. Cmd = %02x %02x %02x %02x Resp = %02x %02x %02x %02x\n", cmd[0], cmd[1], cmd[2], cmd[3], res[0], res[1], res[2], res[3]);
+        return -2;
+    }
+    return 0;
+}
+
+static int  mcprog_chip_erase(struct programmer_t * pgm, AVRPART * p)
+{
+    unsigned char cmd[4];
+    unsigned char res[4];
+
+    if (p->op[AVR_OP_CHIP_ERASE] == NULL)
+    {
+        avrdude_message(MSG_INFO, "chip erase instruction not defined for part \"%s\"\n",
+                p->desc);
+        return -1;
+    }
+
+    pgm->pgm_led(pgm, 1);
+
+    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, 0);
+
+    return 0;
+}
+
+static int  mcprog_paged_load(PROGRAMMER * pgm, AVRPART * p, 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;
+    }
+
+    DEBUG( "paged read ps %d, mem %s\n", page_size, mem->desc);
+
+    OPCODE *readop = 0, *lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+    uint8_t data = 0, cmd[SPI_MAX_CHUNK], res[SPI_MAX_CHUNK];
+    unsigned int addr_base;
+    unsigned int max_addr = addr + n_bytes;
+
+    pgm->pgm_led(pgm, 1);
+
+    for (addr_base = addr; addr_base < max_addr; )
+    {
+        if ((addr_base == 0 || (addr_base % /*ext_address_boundary*/ 65536) == 0)
+                && lext != NULL)
+        {
+            memset(cmd, 0, sizeof(cmd));
+
+            avr_set_bits(lext, cmd);
+            avr_set_addr(lext, cmd, addr_base);
+            pgm->cmd(pgm, cmd, res);
+        }
+
+        // bytes to send in the next packet -- not necessary as mcprog_spi() handles breaking up
+        // the data into packets -- but we need to keep transfers frequent so that we can update the
+        // status indicator bar
+        uint32_t blockSize = MIN(65536 - (addr_base % 65536), MIN(max_addr - addr_base, SPI_MAX_CHUNK / 4));
+
+        memset(cmd, 0, sizeof(cmd));
+        memset(res, 0, sizeof(res));
+
+        uint8_t addr_off;
+        for (addr_off = 0; addr_off < blockSize; addr_off++)
+        {
+            int addr = addr_base + addr_off, caddr = addr;
+
+            if (mem->op[AVR_OP_READ_LO] != NULL && mem->op[AVR_OP_READ_HI] != NULL)
+            {
+                if (addr & 0x00000001)
+                    readop = mem->op[AVR_OP_READ_HI];
+                else
+                    readop = mem->op[AVR_OP_READ_LO];
+
+                caddr /= 2;
+            }
+            else if (mem->op[AVR_OP_READ] != NULL)
+            {
+                readop = mem->op[AVR_OP_READ];
+            }
+            else
+            {
+                avrdude_message(MSG_INFO, "no read command specified\n");
+                return -1;
+            }
+
+            avr_set_bits(readop, &cmd[addr_off*4]);
+            avr_set_addr(readop, &cmd[addr_off*4], caddr);
+        }
+
+        int bytes_read = pgm->spi(pgm, cmd, res, blockSize*4);
+
+        if (bytes_read < 0)
+        {
+            avrdude_message(MSG_INFO, "Failed @ pgm->spi()\n");
+            pgm->err_led(pgm, 1);
+            return -1;
+        }
+
+        DEBUG( "\npaged_load @ %X, wrote: %d, read: %d bytes\n", addr_base, blockSize*4, bytes_read);
+
+        for (addr_off = 0; addr_off < bytes_read / 4; addr_off++)
+        {
+            data = 0;
+            avr_get_output(readop, &res[addr_off*4], &data);
+            mem->buf[addr_base + addr_off] = data;
+
+            DEBUG( "%2X(%c)", (int)data, data<0x20?'.':data);
+        }
+        DEBUG( "\n");
+
+        addr_base += blockSize;
+    }
+
+    pgm->pgm_led(pgm, 0);
+
+    return n_bytes;
+}
+
+
+static int mcprog_commit_page(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                        unsigned long addr)
+{
+    OPCODE * wp, * lext;
+
+    wp = mem->op[AVR_OP_WRITEPAGE];
+    if (wp == NULL)
+    {
+        avrdude_message(MSG_INFO, "mcprog_commit_page(): memory \"%s\" not configured for page writes\n",
+                        mem->desc);
+        return -1;
+    }
+
+    // adjust the address if this memory is word-addressable
+    if ((mem->op[AVR_OP_LOADPAGE_LO]) || (mem->op[AVR_OP_READ_LO]))
+        addr /= 2;
+
+    unsigned char cmd[8];
+    memset(cmd, 0, sizeof(cmd));
+
+    // use the "load extended address" command, if available
+    lext = mem->op[AVR_OP_LOAD_EXT_ADDR];
+    if (lext != NULL)
+    {
+        avr_set_bits(lext, cmd);
+        avr_set_addr(lext, cmd, addr);
+    }
+
+    // make up the write page command in the 2nd cmd position
+    avr_set_bits(wp, &cmd[4]);
+    avr_set_addr(wp, &cmd[4], addr);
+
+    if (lext != NULL)
+    {
+        // write the load extended address cmd && the write_page cmd
+        pgm->spi(pgm, cmd, NULL, 8);
+    }
+    else
+    {
+        // write just the write_page cmd
+      //avrdude_message(MSG_INFO, "\nmcprog_commit_page(): cmd: %x:%x:%x:%x\n", cmd[4], cmd[5], cmd[6], cmd[7]);
+        pgm->spi(pgm, &cmd[4], NULL, 4);
+    }
+
+    // just delay the max
+    usleep(mem->max_write_delay);
+
+    return 0;
+}
+
+// not actually a paged write, but a bulk/batch write
+static int  mcprog_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * mem,
+                         unsigned int page_size, unsigned int addr, unsigned int n_bytes)
+{
+    // only paged write for flash implemented
+    if (strcmp(mem->desc, "flash") != 0 && strcmp(mem->desc, "eeprom") != 0)
+    {
+        avrdude_message(MSG_INFO, "Part does not support %d paged write of %s\n", page_size, mem->desc);
+        return -1;
+    }
+
+    DEBUG( "page size %d mem %s supported: %d\n", page_size, mem->desc, mem->paged);
+    DEBUG( "loadpagehi %x, loadpagelow %x, writepage %x\n", (int)mem->op[AVR_OP_LOADPAGE_HI], (int)mem->op[AVR_OP_LOADPAGE_LO], (int)mem->op[AVR_OP_WRITEPAGE]);
+
+    OPCODE *writeop;
+    uint8_t cmd[SPI_MAX_CHUNK], res[SPI_MAX_CHUNK];
+    unsigned int addr_base;
+    unsigned int max_addr = addr + n_bytes;
+
+    pgm->pgm_led(pgm, 1);
+
+    for (addr_base = addr; addr_base < max_addr; )
+    {
+        uint32_t blockSize;
+
+        if (mem->paged)
+        {
+            blockSize = MIN(page_size - (addr_base % page_size), MIN(max_addr - addr_base, SPI_MAX_CHUNK/4) );     // bytes remaining in page
+        }
+        else
+        {
+            blockSize = 1;
+        }
+
+        memset(cmd, 0, sizeof(cmd));
+        memset(res, 0, sizeof(res));
+
+        uint8_t addr_off;
+        for (addr_off = 0; addr_off < blockSize; addr_off++)
+        {
+            int addr = addr_base + addr_off;
+            int caddr = 0;
+
+            /*
+             * determine which memory opcode to use
+             */
+            if (mem->paged && mem->op[AVR_OP_LOADPAGE_HI] && mem->op[AVR_OP_LOADPAGE_LO])
+            {
+                if (addr & 0x01)
+                    writeop = mem->op[AVR_OP_LOADPAGE_HI];
+                else
+                    writeop = mem->op[AVR_OP_LOADPAGE_LO];
+                caddr = addr / 2;
+            }
+            else if (mem->paged && mem->op[AVR_OP_LOADPAGE_LO])
+            {
+                writeop = mem->op[AVR_OP_LOADPAGE_LO];
+                caddr = addr;
+            }
+            else if (mem->op[AVR_OP_WRITE_LO])
+            {
+                writeop = mem->op[AVR_OP_WRITE_LO];
+                caddr = addr;       // maybe this should divide by 2 & use the write_high opcode also
+
+                avrdude_message(MSG_INFO, "Error AVR_OP_WRITE_LO defined only (where's the HIGH command?)\n");
+                return -1;
+            }
+            else
+            {
+                writeop = mem->op[AVR_OP_WRITE];
+                caddr = addr;
+            }
+
+            if (writeop == NULL)
+            {
+                pgm->err_led(pgm, 1);
+                // not supported!
+                return -1;
+            }
+
+            avr_set_bits(writeop, &cmd[addr_off*4]);
+            avr_set_addr(writeop, &cmd[addr_off*4], caddr);
+            avr_set_input(writeop, &cmd[addr_off*4], mem->buf[addr]);
+        }
+	
+	/* avrdude_message(MSG_INFO, "\npaged_write: spi: b-%d\n", blockSize); */
+	/* int i; */
+	/* for (i=0; i<blockSize; i++) { */
+	/*   avrdude_message(MSG_INFO, "%x:%x:%x:%x-", */
+	/* 		  cmd[4*i+0], cmd[4*i+1], cmd[4*i+2], cmd[4*i+3]); */
+	/* } */
+	/* avrdude_message(MSG_INFO, "\n"); */
+        int bytes_read = pgm->spi(pgm, cmd, res, blockSize*4);
+
+        if (bytes_read < 0)
+        {
+            avrdude_message(MSG_INFO, "Failed @ pgm->spi()\n");
+            pgm->err_led(pgm, 1);
+            return -1;
+        }
+
+        addr_base += blockSize;
+
+        // write the page - this function looks after extended address also
+        if (mem->paged && (((addr_base % page_size) == 0) || (addr_base == max_addr)))
+        {
+            DEBUG( "Calling mcprog_commit_page()\n");
+            mcprog_commit_page(pgm, p, mem, addr_base-blockSize);
+	    //avrdude_message(MSG_INFO, "\n paged_write: commiting page: a-%d p-%d\n", addr_base, page_size);
+        }
+        else if (!mem->paged)
+        {
+            usleep(mem->max_write_delay);
+        }
+    }
+
+    pgm->pgm_led(pgm, 0);
+
+    return n_bytes;
+}
+
+
+static int mcprog_cmd(struct programmer_t * pgm, const unsigned char *cmd,
+                unsigned char *res)
+{
+    return pgm->spi(pgm, cmd, res, 4);
+}
+
+// breaks up the cmd[] data into  packets & sends to the mcprog. Data shifted in is stored in res[].
+static int mcprog_spi(struct programmer_t * pgm, const unsigned char *cmd,
+                unsigned char *res, int n_bytes)
+{
+    int retval = 0, temp1 = 0, temp2 = 0, count = n_bytes;
+
+    while (count > 0)
+    {
+        uint8_t i, blockSize = MIN(count, SPI_MAX_CHUNK);
+        uint8_t report[65] = {0, 0x42, blockSize};
+        uint8_t *repptr = report + 5;
+        uint8_t report2[65] = {0, 0x42, 0};
+        unsigned num_rx_bytes;
+
+        memset(report + 3, 0x00, sizeof(report) - 3);
+
+        // append some data to write to SPI
+        for (i = 0; i < blockSize; i++)
+        {
+            *repptr++ = *cmd++;
+            count--;    // 1 less byte to pack
+        }
+
+        // check return values
+        mcprog_set_spi_settings(pgm, blockSize);
+        if ((temp1=mcprog_write_report(pgm, report)) < 0 ||
+            (temp2=mcprog_read_report(pgm, report)) < 0)
+        {
+            return -1;
+        }
+        num_rx_bytes=0;
+        while(num_rx_bytes<blockSize) 
+        {
+	    //usleep(100);
+
+            if ((temp1=mcprog_write_report(pgm, report2)) < 0 ||
+                (temp2=mcprog_read_report(pgm, report)) < 0) 
+            {
+                return -1;
+            }
+            if (report[2]==0)
+            {
+                num_rx_bytes += report[3];
+            }
+	  
+            if (report[2]!=0 && report[2] != 0xf8)
+            {
+                avrdude_message(MSG_INFO, "fail: report[2]==%x\n",report[3]); 
+                return -1;
+            }
+
+            if ((report[4] == 0x10) && (num_rx_bytes < blockSize))
+            {
+                avrdude_message(MSG_INFO, "fail: wrong number of data bytes: b=%d n=%d\n",blockSize, num_rx_bytes); 
+                return -1;
+            }
+            retval = report[3]; // upload-length field
+            repptr = &report[5];    // actual data starts here
+
+            if (res)                // copy data if user has specified a storage location
+            {
+                memcpy(res, repptr, retval);
+                res += retval;
+            }
+            
+        }
+    }
+    
+    return n_bytes;
+}
+
+static int mcprog_write_report(PROGRAMMER * pgm, const unsigned char report[65])
+{
+    int r = hid_write(PDATA(pgm)->hidapi_handle, report, 65);
+    return r;
+}
+
+static int mcprog_read_report(PROGRAMMER * pgm, unsigned char report[65])
+{
+    int r = hid_read(PDATA(pgm)->hidapi_handle, report+1, 64);
+    return r;
+}
+
+static int  mcprog_parseextparams(struct programmer_t * pgm, LISTID extparms)
+{
+    LNODEID ln;
+    const char *extended_param;
+    int rv = 0;
+
+    for (ln = lfirst(extparms); ln; ln = lnext(ln))
+    {
+        extended_param = ldata(ln);
+
+        if (strncmp(extended_param, "clockrate=", strlen("clockrate=")) == 0)
+        {
+            int clock_rate;
+            if (sscanf(extended_param, "clockrate=%i", &clock_rate) != 1 || clock_rate <= 0)
+            {
+                avrdude_message(MSG_INFO, "%s: mcprog_parseextparms(): invalid clockrate '%s'\n",
+                                progname, extended_param);
+                rv = -1;
+                continue;
+            }
+	    
+	    clock_rate = MIN(clock_rate, 3000000);
+            int clock_period = MIN(3000000 / clock_rate, 255);    // max period is 255
+            clock_rate = (int)(3000000 / clock_period);    // assume highest speed is 2MHz - should probably check this
+
+            avrdude_message(MSG_NOTICE2, "%s: mcprog_parseextparms(): clockrate set to 0x%02x\n",
+                                progname, clock_rate);
+            PDATA(pgm)->clock_period = clock_period;
+
+            continue;
+        }
+        if (strncmp(extended_param, "use_pgm_led=", strlen("use_pgm_led=")) == 0)
+        {
+            int use_pgm_led;
+
+            if (sscanf(extended_param, "use_pgm_led=%i", &use_pgm_led) != 1 )
+            {
+                avrdude_message(MSG_INFO, "%s: mcprog_parseextparms(): invalid value for use_pgm_led '%s'\n",
+                                progname, extended_param);
+                rv = -1;
+                continue;
+            }
+            avrdude_message(MSG_NOTICE2, "%s: mcprog_parseextparms(): use_pgm_led set to 0x%02x\n",
+                                progname, use_pgm_led);
+            PDATA(pgm)->use_pgm_led = (use_pgm_led?1:0);
+
+            continue;
+
+        }
+        /* if (strncmp(extended_param, "timeout=", strlen("timeout=")) == 0) */
+        /* { */
+        /*     int timeout; */
+        /*     if (sscanf(extended_param, "timeout=%i", &timeout) != 1 || timeout <= 0) */
+        /*     { */
+        /*         avrdude_message(MSG_INFO, "%s: mcprog_parseextparms(): invalid timeout '%s'\n", */
+        /*                         progname, extended_param); */
+        /*         rv = -1; */
+        /*         continue; */
+        /*     } */
+
+        /*     avrdude_message(MSG_NOTICE2, "%s: mcprog_parseextparms(): usb timeout set to 0x%02x\n", */
+        /*                         progname, timeout); */
+        /*     PDATA(pgm)->transaction_timeout = timeout; */
+
+        /*     continue; */
+        /* } */
+
+        avrdude_message(MSG_INFO, "%s: mcprog_parseextparms(): invalid extended parameter '%s'\n",
+                        progname, extended_param);
+        rv = -1;
+    }
+
+    return rv;
+}
+
+
+void mcprog_initpgm (PROGRAMMER * pgm)
+{
+    /*
+     * mandatory functions - these are called without checking to see
+     * whether they are assigned or not
+     */
+
+    pgm->initialize     = mcprog_initialize;
+    pgm->display        = mcprog_display;
+    pgm->enable         = mcprog_enable;
+    pgm->disable        = mcprog_disable;
+    pgm->powerup        = mcprog_powerup;
+    pgm->powerdown      = mcprog_powerdown;
+    pgm->program_enable = mcprog_program_enable;
+    pgm->chip_erase     = mcprog_chip_erase;
+    pgm->open           = mcprog_open;
+    pgm->close          = mcprog_close;
+
+    pgm->read_byte      = avr_read_byte_default;
+    pgm->write_byte     = avr_write_byte_default;
+
+    /*
+     * predefined functions - these functions have a valid default
+     * implementation. Hence, they don't need to be defined in
+     * the programmer.
+     */
+    //pgm->rdy_led        = mcprog_rdy_led;
+    pgm->err_led        = mcprog_err_led;
+    pgm->pgm_led        = mcprog_pgm_led;
+    pgm->vfy_led        = mcprog_vfy_led;
+
+    /*
+     * optional functions - these are checked to make sure they are
+     * assigned before they are called
+     */
+
+    pgm->cmd            = mcprog_cmd;
+    pgm->spi            = mcprog_spi;
+    pgm->paged_write    = mcprog_paged_write;
+    pgm->paged_load     = mcprog_paged_load;
+    //pgm->write_setup    = NULL;
+    //pgm->read_sig_bytes = NULL;
+    //pgm->set_vtarget    = NULL;//mcprog_vtarget;
+    //pgm->set_varef      = NULL;
+    //pgm->set_fosc       = NULL;
+    //pgm->perform_osccal = NULL;
+
+    pgm->parseextparams = mcprog_parseextparams;
+
+    pgm->setup          = mcprog_setup;
+    pgm->teardown       = mcprog_teardown;
+    // pgm->page_size      = 256;        // not sure what this does... maybe the max page size that the page read/write function can handle
+
+    strncpy(pgm->type, "mcprog", sizeof(pgm->type));
+}
+
+#else // defined(HAVE_LIBHIDAPI)
+static int mcprog_nohidapi_open (struct programmer_t *pgm, char * name) {
+    avrdude_message(MSG_INFO, 
+            "%s: error: no hidapi support. Please compile again with hidapi installed.\n",
+            progname);
+
+    return -1;
+}
+
+void mcprog_initpgm (PROGRAMMER * pgm)
+{
+    /*
+     * mandatory functions - these are called without checking to see
+     * whether they are assigned or not
+     */
+
+    pgm->open           = mcprog_nohidapi_open;
+
+    strncpy(pgm->type, "mcprog", sizeof(pgm->type));
+}
+#endif // defined(HAVE_LIBHIDAPI)
+
+const char mcprog_desc[] = "Microchip's MCP2210 IC";
+
Index: mcprog.h
===================================================================
--- mcprog.h	(Revision 0)
+++ mcprog.h	(Arbeitskopie)
@@ -0,0 +1,35 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006  Thomas Fischl
+ *
+ * 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/>.
+ */
+
+/* $Id: pickit2.h 2010-05-03 dbrown $ */
+
+#ifndef mcprog_h
+#define mcprog_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const char mcprog_desc[];
+void mcprog_initpgm (PROGRAMMER * pgm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // mprog_h
Index: pgm_type.c
===================================================================
--- pgm_type.c	(Revision 1356)
+++ pgm_type.c	(Arbeitskopie)
@@ -42,6 +42,7 @@
 #include "linuxgpio.h"
 #include "par.h"
 #include "pickit2.h"
+#include "mcprog.h"
 #include "ppi.h"
 #include "serbb.h"
 #include "stk500.h"
@@ -82,6 +83,7 @@
         {"linuxgpio", linuxgpio_initpgm, linuxgpio_desc},
         {"par", par_initpgm, par_desc},
         {"pickit2", pickit2_initpgm, pickit2_desc},
+        {"mcprog", mcprog_initpgm, mcprog_desc},
         {"serbb", serbb_initpgm, serbb_desc},
         {"stk500", stk500_initpgm, stk500_desc},
         {"stk500generic", stk500generic_initpgm, stk500generic_desc},
