diff --git a/avrdude/ChangeLog b/avrdude/ChangeLog
index 3e7587db..226056bf 100644
--- a/avrdude/ChangeLog
+++ b/avrdude/ChangeLog
@@ -1,3 +1,17 @@
+2006-12-21 Joerg Wunsch <j@uriah.heep.sax.de>
+
+	Submitted by Christian Starkjohann:
+	patch #5507: Support for AVR-Doper USB programmer in HID mode
+	* configure.ac: Add hooks to detect the Win32 HID library,
+	as well as the existence of <ddk/hidsdi.h>.
+	* Makefile.am: Add new files.
+	* my_ddk_hidsdi.h: (New file.)
+	* ser_avrdoper.c: (New file.)
+	* serial.h: Add declaration for avrdoper_serdev.
+	* stk500v2.c: Add hook to divert to the AVR Doper code.
+	* avrdude.1: Document the AVR Doper support.
+	* doc/avrdude.texi: (Ditto.)
+
 2006-12-15 Joerg Wunsch <j@uriah.heep.sax.de>
 
 	Submitted by ivanv at netman.ru
diff --git a/avrdude/Makefile.am b/avrdude/Makefile.am
index b2300a07..5f881ab3 100644
--- a/avrdude/Makefile.am
+++ b/avrdude/Makefile.am
@@ -98,6 +98,7 @@ avrdude_SOURCES = \
 	lists.c \
 	lists.h \
 	main.c \
+	my_ddk_hidsdi.h \
 	par.c \
 	par.h \
 	pgm.c \
@@ -112,6 +113,7 @@ avrdude_SOURCES = \
 	serbb.h \
 	serbb_posix.c \
 	serbb_win32.c \
+	ser_avrdoper.c \
 	ser_posix.c \
 	ser_win32.c \
 	solaris_ecpp.h \
diff --git a/avrdude/NEWS b/avrdude/NEWS
index 99655380..bca82d82 100644
--- a/avrdude/NEWS
+++ b/avrdude/NEWS
@@ -12,6 +12,8 @@ Current:
 
   * Add support for debugWire (both, JTAG ICE mkII, and AVR Dragon).
 
+  * Add support for the AVR Doper USB HID-class programmer.
+
   * Bugfixes.
 
 Version 5.2:
diff --git a/avrdude/avrdude.1 b/avrdude/avrdude.1
index 9491ae63..2abb1ca6 100644
--- a/avrdude/avrdude.1
+++ b/avrdude/avrdude.1
@@ -412,6 +412,12 @@ from the serial number need to be given.
 As the AVRISP mkII device can only be talked to over USB, the very
 same method of specifying the port is required there.
 .Pp
+For the USB programmer "AVR-Doper" running in HID mode, the port must
+be specified as
+.Ar avrdoper.
+Libusb support is required on Unix but not on Windows. For more
+information about AVR-Doper see http://www.obdev.at/avrusb/avrdoper.html.
+.Pp
 For programmers that attach to a serial port using some kind of
 higher level protocol (as opposed to bit-bang style programmers),
 .Ar port
diff --git a/avrdude/configure.ac b/avrdude/configure.ac
index 555f7d18..7696d5c4 100644
--- a/avrdude/configure.ac
+++ b/avrdude/configure.ac
@@ -60,9 +60,49 @@ if test x$have_libusb = xyes; then
 fi
 AC_SUBST(LIBUSB, $LIBUSB)
 
+AC_MSG_CHECKING([for a Win32 HID libray])
+SAVED_LIBS="${LIBS}"
+case $target in
+	*-*-mingw32*)
+		LIBHID="-lhid -lsetupapi"
+		HIDINCLUDE="#include <ddk/hidsdi.h>"
+		;;
+	*)
+		LIBHID="-lhid"
+		HIDINCLUDE='#include "my_ddk_hidsdi.h"'
+		;;
+esac
+LIBS="${LIBS} ${LIBHID}"
+
+AH_TEMPLATE([HAVE_LIBHID],
+            [Define if HID support is enabled via the Win32 DDK])
+AC_TRY_RUN([#include <windows.h>
+#include <setupapi.h>
+$HIDINCLUDE
+
+int
+main(void)
+{
+    GUID hidGuid;
+    HidD_GetHidGuid(&hidGuid);
+
+    return 0;
+}
+], [have_libhid=yes], [have_libhid=no], [have_libhid=no])
+AC_MSG_RESULT([$have_libhid])
+if test x$have_libhid = xyes; then
+   AC_DEFINE([HAVE_LIBHID])
+else
+   LIBHID=""
+fi
+LIBS="${SAVED_LIBS}"
+
 # Checks for header files.
 AC_HEADER_STDC
-AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h sys/ioctl.h sys/time.h termios.h unistd.h])
+AC_CHECK_HEADERS([limits.h stdlib.h string.h])
+AC_CHECK_HEADERS([fcntl.h sys/ioctl.h sys/time.h termios.h unistd.h])
+AC_CHECK_HEADERS([ddk/hidsdi.h],,,[#include <windows.h>
+#include <setupapi.h>])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_C_CONST
diff --git a/avrdude/doc/avrdude.texi b/avrdude/doc/avrdude.texi
index 18c69c15..4bb7d7bc 100644
--- a/avrdude/doc/avrdude.texi
+++ b/avrdude/doc/avrdude.texi
@@ -559,6 +559,11 @@ attached to USB, see @ref{Example Command Line Invocations}.
 As the AVRISP mkII device can only be talked to over USB, the very
 same method of specifying the port is required there.
 
+For the USB programmer "AVR-Doper" running in HID mode, the port must
+be specified as @var{avrdoper}. Libusb support is required on Unix
+but not on Windows. For more information about AVR-Doper see
+@url{http://www.obdev.at/avrusb/avrdoper.html}.
+
 For programmers that attach to a serial port using some kind of
 higher level protocol (as opposed to bit-bang style programmers),
 @var{port} can be specified as @code{net}:@var{host}:@var{port}.
diff --git a/avrdude/my_ddk_hidsdi.h b/avrdude/my_ddk_hidsdi.h
new file mode 100644
index 00000000..99859d06
--- /dev/null
+++ b/avrdude/my_ddk_hidsdi.h
@@ -0,0 +1,49 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2006 Christian Starkjohann
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+/*
+The following is a replacement for hidsdi.h from the Windows DDK. It defines some
+of the types and function prototypes of this header for our project. If you
+have the Windows DDK version of this file or a version shipped with MinGW, use
+that instead.
+*/
+#ifndef MY_DDK_HIDSDI_H
+#define MY_DDK_HIDSDI_H
+#include <pshpack4.h>
+#include <ddk/hidusage.h>
+#include <ddk/hidpi.h>
+typedef struct{
+    ULONG   Size;
+    USHORT  VendorID;
+    USHORT  ProductID;
+    USHORT  VersionNumber;
+}HIDD_ATTRIBUTES;
+void __stdcall      HidD_GetHidGuid(OUT LPGUID hidGuid);
+BOOLEAN __stdcall   HidD_GetAttributes(IN HANDLE device, OUT HIDD_ATTRIBUTES *attributes);
+BOOLEAN __stdcall   HidD_GetManufacturerString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen);
+BOOLEAN __stdcall   HidD_GetProductString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen);
+BOOLEAN __stdcall   HidD_GetSerialNumberString(IN HANDLE device, OUT void *buffer, IN ULONG bufferLen);
+BOOLEAN __stdcall   HidD_GetFeature(IN HANDLE device, OUT void *reportBuffer, IN ULONG bufferLen);
+BOOLEAN __stdcall   HidD_SetFeature(IN HANDLE device, IN void *reportBuffer, IN ULONG bufferLen);
+BOOLEAN __stdcall   HidD_GetNumInputBuffers(IN HANDLE device, OUT ULONG *numBuffers);
+BOOLEAN __stdcall   HidD_SetNumInputBuffers(IN HANDLE device, OUT ULONG numBuffers);
+#include <poppack.h>
+#endif /* MY_DDK_HIDSDI_H */
diff --git a/avrdude/ser_avrdoper.c b/avrdude/ser_avrdoper.c
new file mode 100644
index 00000000..638fb5eb
--- /dev/null
+++ b/avrdude/ser_avrdoper.c
@@ -0,0 +1,647 @@
+/*
+ * avrdude - A Downloader/Uploader for AVR device programmers
+ * Copyright (C) 2003-2004  Theodore A. Roth  <troth@openavr.org>
+ * Copyright (C) 2006 Joerg Wunsch <j@uriah.heep.sax.de>
+ * Copyright (C) 2006 Christian Starkjohann
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* $Id$ */
+
+/*
+ * Serial Interface emulation for USB programmer "AVR-Doper" in HID mode.
+ */
+
+#include "ac_cfg.h"
+
+#if defined(HAVE_LIBUSB) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
+
+#include <stdio.h>
+#include <string.h>
+
+#include "serial.h"
+
+/* ------------------------------------------------------------------------ */
+
+/* Numeric constants for 'reportType' parameters */
+#define USB_HID_REPORT_TYPE_INPUT   1
+#define USB_HID_REPORT_TYPE_OUTPUT  2
+#define USB_HID_REPORT_TYPE_FEATURE 3
+
+/* These are the error codes which can be returned by functions of this
+ * module.
+ */
+#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 USB_VENDOR_ID   0x16c0
+#define USB_PRODUCT_ID  0x05df
+
+extern char *progname;
+extern int verbose;
+
+static int  reportDataSizes[4] = {13, 29, 61, 125};
+
+static unsigned char    avrdoperRxBuffer[280];  /* buffer for receive data */
+static int              avrdoperRxLength = 0;   /* amount of valid bytes in rx buffer */
+static int              avrdoperRxPosition = 0; /* amount of bytes already consumed in rx buffer */
+
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
+#ifdef WIN32NATIVE
+
+#include <windows.h>
+#include <setupapi.h>
+
+#if defined(HAVE_DDK_HIDSDI_H)
+#  include <ddk/hidsdi.h>
+#else
+#  include "my_ddk_hidsdi.h"
+#endif
+#include <ddk/hidpi.h>
+
+#ifdef USB_DEBUG
+#define DEBUG_PRINT(arg)    printf arg
+#else
+#define DEBUG_PRINT(arg)
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static void convertUniToAscii(char *buffer)
+{
+    unsigned short  *uni = (void *)buffer;
+    char            *ascii = buffer;
+
+    while(*uni != 0){
+        if(*uni >= 256){
+            *ascii++ = '?';
+        }else{
+            *ascii++ = *uni++;
+        }
+    }
+    *ascii++ = 0;
+}
+
+static int usbOpenDevice(union filedescriptor *fdp, int vendor, char *vendorName,
+			 int product, char *productName, int usesReportIDs)
+{
+    GUID                                hidGuid;        /* GUID for HID driver */
+    HDEVINFO                            deviceInfoList;
+    SP_DEVICE_INTERFACE_DATA            deviceInfo;
+    SP_DEVICE_INTERFACE_DETAIL_DATA     *deviceDetails = NULL;
+    DWORD                               size;
+    int                                 i, openFlag = 0;  /* may be FILE_FLAG_OVERLAPPED */
+    int                                 errorCode = USB_ERROR_NOTFOUND;
+    HANDLE                              handle = INVALID_HANDLE_VALUE;
+    HIDD_ATTRIBUTES                     deviceAttributes;
+
+    HidD_GetHidGuid(&hidGuid);
+    deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
+					 DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
+    deviceInfo.cbSize = sizeof(deviceInfo);
+    for(i=0;;i++){
+        if(handle != INVALID_HANDLE_VALUE){
+            CloseHandle(handle);
+            handle = INVALID_HANDLE_VALUE;
+        }
+        if(!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i, &deviceInfo))
+            break;  /* no more entries */
+        /* first do a dummy call just to determine the actual size required */
+        SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, NULL, 0, &size, NULL);
+        if(deviceDetails != NULL)
+            free(deviceDetails);
+        deviceDetails = malloc(size);
+        deviceDetails->cbSize = sizeof(*deviceDetails);
+        /* this call is for real: */
+        SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo, deviceDetails,
+					size, &size, NULL);
+        DEBUG_PRINT(("checking HID path \"%s\"\n", deviceDetails->DevicePath));
+        /* attempt opening for R/W -- we don't care about devices which can't be accessed */
+        handle = CreateFile(deviceDetails->DevicePath, GENERIC_READ|GENERIC_WRITE,
+			    FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+			    openFlag, NULL);
+        if(handle == INVALID_HANDLE_VALUE){
+            DEBUG_PRINT(("opening failed: %d\n", (int)GetLastError()));
+            /* errorCode = USB_ERROR_ACCESS; opening will always fail for mouse -- ignore */
+            continue;
+        }
+        deviceAttributes.Size = sizeof(deviceAttributes);
+        HidD_GetAttributes(handle, &deviceAttributes);
+        DEBUG_PRINT(("device attributes: vid=%d pid=%d\n",
+		     deviceAttributes.VendorID, deviceAttributes.ProductID));
+        if(deviceAttributes.VendorID != vendor || deviceAttributes.ProductID != product)
+            continue;   /* ignore this device */
+        errorCode = USB_ERROR_NOTFOUND;
+        if(vendorName != NULL && productName != NULL){
+            char    buffer[512];
+            if(!HidD_GetManufacturerString(handle, buffer, sizeof(buffer))){
+                DEBUG_PRINT(("error obtaining vendor name\n"));
+                errorCode = USB_ERROR_IO;
+                continue;
+            }
+            convertUniToAscii(buffer);
+            DEBUG_PRINT(("vendorName = \"%s\"\n", buffer));
+            if(strcmp(vendorName, buffer) != 0)
+                continue;
+            if(!HidD_GetProductString(handle, buffer, sizeof(buffer))){
+                DEBUG_PRINT(("error obtaining product name\n"));
+                errorCode = USB_ERROR_IO;
+                continue;
+            }
+            convertUniToAscii(buffer);
+            DEBUG_PRINT(("productName = \"%s\"\n", buffer));
+            if(strcmp(productName, buffer) != 0)
+                continue;
+        }
+        break;  /* we have found the device we are looking for! */
+    }
+    SetupDiDestroyDeviceInfoList(deviceInfoList);
+    if(deviceDetails != NULL)
+        free(deviceDetails);
+    if(handle != INVALID_HANDLE_VALUE){
+	fdp->pfd = (void *)handle;
+    }
+    return errorCode;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static void    usbCloseDevice(union filedescriptor *fdp)
+{
+    CloseHandle((HANDLE)fdp->pfd);
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int usbSetReport(union filedescriptor *fdp, int reportType, char *buffer, int len)
+{
+    HANDLE  handle = (HANDLE)fdp->pfd;
+    BOOLEAN rval = 0;
+    DWORD   bytesWritten;
+
+    switch(reportType){
+    case USB_HID_REPORT_TYPE_INPUT:
+        break;
+    case USB_HID_REPORT_TYPE_OUTPUT:
+        rval = WriteFile(handle, buffer, len, &bytesWritten, NULL);
+        break;
+    case USB_HID_REPORT_TYPE_FEATURE:
+        rval = HidD_SetFeature(handle, buffer, len);
+        break;
+    }
+    return rval == 0 ? USB_ERROR_IO : 0;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int usbGetReport(union filedescriptor *fdp, int reportType, int reportNumber,
+			char *buffer, int *len)
+{
+    HANDLE  handle = (HANDLE)fdp->pfd;
+    BOOLEAN rval = 0;
+    DWORD   bytesRead;
+
+    switch(reportType){
+    case USB_HID_REPORT_TYPE_INPUT:
+        buffer[0] = reportNumber;
+        rval = ReadFile(handle, buffer, *len, &bytesRead, NULL);
+        if(rval)
+            *len = bytesRead;
+        break;
+    case USB_HID_REPORT_TYPE_OUTPUT:
+        break;
+    case USB_HID_REPORT_TYPE_FEATURE:
+        buffer[0] = reportNumber;
+        rval = HidD_GetFeature(handle, buffer, *len);
+        break;
+    }
+    return rval == 0 ? USB_ERROR_IO : 0;
+}
+
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
+#else /* !WIN32NATIVE */
+
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
+#include <usb.h>
+
+/* ------------------------------------------------------------------------- */
+
+#define USBRQ_HID_GET_REPORT    0x01
+#define USBRQ_HID_SET_REPORT    0x09
+
+static int  usesReportIDs;
+
+/* ------------------------------------------------------------------------- */
+
+static int  usbGetStringAscii(usb_dev_handle *dev, int index, int langid, char *buf, int buflen)
+{
+    char    buffer[256];
+    int     rval, i;
+
+    if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
+			       (USB_DT_STRING << 8) + index, langid, buffer,
+			       sizeof(buffer), 1000)) < 0)
+        return rval;
+    if(buffer[1] != USB_DT_STRING)
+        return 0;
+    if((unsigned char)buffer[0] < rval)
+        rval = (unsigned char)buffer[0];
+    rval /= 2;
+    /* lossy conversion to ISO Latin1 */
+    for(i=1;i<rval;i++){
+        if(i > buflen)  /* destination buffer overflow */
+            break;
+        buf[i-1] = buffer[2 * i];
+        if(buffer[2 * i + 1] != 0)  /* outside of ISO Latin1 range */
+            buf[i-1] = '?';
+    }
+    buf[i-1] = 0;
+    return i-1;
+}
+
+static int usbOpenDevice(union filedescriptor *fdp, int vendor, char *vendorName,
+			 int product, char *productName, int doReportIDs)
+{
+    struct usb_bus      *bus;
+    struct usb_device   *dev;
+    usb_dev_handle      *handle = NULL;
+    int                 errorCode = USB_ERROR_NOTFOUND;
+    static int          didUsbInit = 0;
+
+    if(!didUsbInit){
+        usb_init();
+        didUsbInit = 1;
+    }
+    usb_find_busses();
+    usb_find_devices();
+    for(bus=usb_get_busses(); bus; bus=bus->next){
+        for(dev=bus->devices; dev; dev=dev->next){
+            if(dev->descriptor.idVendor == vendor && dev->descriptor.idProduct == product){
+                char    string[256];
+                int     len;
+                handle = usb_open(dev); /* we need to open the device in order to query strings */
+                if(!handle){
+                    errorCode = USB_ERROR_ACCESS;
+                    fprintf(stderr, "Warning: cannot open USB device: %s\n",
+			    usb_strerror());
+                    continue;
+                }
+                if(vendorName == NULL && productName == NULL){  /* name does not matter */
+                    break;
+                }
+                /* now check whether the names match: */
+                len = usbGetStringAscii(handle, dev->descriptor.iManufacturer,
+					0x0409, string, sizeof(string));
+                if(len < 0){
+                    errorCode = USB_ERROR_IO;
+                    fprintf(stderr,
+			    "Warning: cannot query manufacturer for device: %s\n",
+			    usb_strerror());
+                }else{
+                    errorCode = USB_ERROR_NOTFOUND;
+                    /* fprintf(stderr, "seen device from vendor ->%s<-\n", string); */
+                    if(strcmp(string, vendorName) == 0){
+                        len = usbGetStringAscii(handle, dev->descriptor.iProduct,
+						0x0409, string, sizeof(string));
+                        if(len < 0){
+                            errorCode = USB_ERROR_IO;
+                            fprintf(stderr,
+				    "Warning: cannot query product for device: %s\n",
+				    usb_strerror());
+                        }else{
+                            errorCode = USB_ERROR_NOTFOUND;
+                            /* fprintf(stderr, "seen product ->%s<-\n", string); */
+                            if(strcmp(string, productName) == 0)
+                                break;
+                        }
+                    }
+                }
+                usb_close(handle);
+                handle = NULL;
+            }
+        }
+        if(handle)
+            break;
+    }
+    if(handle != NULL){
+        int rval, retries = 3;
+        if(usb_set_configuration(handle, 1)){
+            fprintf(stderr, "Warning: could not set configuration: %s\n",
+		    usb_strerror());
+        }
+        /* now try to claim the interface and detach the kernel HID driver on
+         * linux and other operating systems which support the call.
+         */
+        while((rval = usb_claim_interface(handle, 0)) != 0 && retries-- > 0){
+#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
+            if(usb_detach_kernel_driver_np(handle, 0) < 0){
+                fprintf(stderr, "Warning: could not detach kernel HID driver: %s\n",
+			usb_strerror());
+            }
+#endif
+        }
+        if(rval != 0)
+            fprintf(stderr, "Warning: could not claim interface\n");
+/* Continue anyway, even if we could not claim the interface. Control transfers
+ * should still work.
+ */
+        errorCode = 0;
+        fdp->pfd = (void *)handle;
+        usesReportIDs = doReportIDs;
+    }
+    return errorCode;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void    usbCloseDevice(union filedescriptor *fdp)
+{
+    usb_close((usb_dev_handle *)fdp->pfd);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int usbSetReport(union filedescriptor *fdp, int reportType, char *buffer, int len)
+{
+    int bytesSent;
+
+    if(!usesReportIDs){
+        buffer++;   /* skip dummy report ID */
+        len--;
+    }
+    bytesSent = usb_control_msg((usb_dev_handle *)fdp->pfd, USB_TYPE_CLASS |
+				USB_RECIP_INTERFACE | USB_ENDPOINT_OUT, USBRQ_HID_SET_REPORT,
+				reportType << 8 | buffer[0], 0, buffer, len, 5000);
+    if(bytesSent != len){
+        if(bytesSent < 0)
+            fprintf(stderr, "Error sending message: %s\n", usb_strerror());
+        return USB_ERROR_IO;
+    }
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int usbGetReport(union filedescriptor *fdp, int reportType, int reportNumber,
+			char *buffer, int *len)
+{
+    int bytesReceived, maxLen = *len;
+
+    if(!usesReportIDs){
+        buffer++;   /* make room for dummy report ID */
+        maxLen--;
+    }
+    bytesReceived = usb_control_msg((usb_dev_handle *)fdp->pfd, USB_TYPE_CLASS |
+				    USB_RECIP_INTERFACE | USB_ENDPOINT_IN, USBRQ_HID_GET_REPORT,
+				    reportType << 8 | reportNumber, 0, buffer, maxLen, 5000);
+    if(bytesReceived < 0){
+        fprintf(stderr, "Error sending message: %s\n", usb_strerror());
+        return USB_ERROR_IO;
+    }
+    *len = bytesReceived;
+    if(!usesReportIDs){
+        buffer[-1] = reportNumber;  /* add dummy report ID */
+        *len++;
+    }
+    return 0;
+}
+
+#endif  /* WIN32NATIVE */
+
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
+/* ------------------------------------------------------------------------- */
+
+static void dumpBlock(char *prefix, unsigned char *buf, int len)
+{
+    int i;
+
+    if(len <= 8){   /* more compact format for short blocks */
+        fprintf(stderr, "%s: %d bytes: ", prefix, len);
+        for(i = 0; i < len; i++){
+            fprintf(stderr, "%02x ", buf[i]);
+        }
+        fprintf(stderr, " \"");
+        for(i = 0; i < len; i++){
+            if(buf[i] >= 0x20 && buf[i] < 0x7f){
+                fputc(buf[i], stderr);
+            }else{
+                fputc('.', stderr);
+            }
+        }
+        fprintf(stderr, "\"\n");
+    }else{
+        fprintf(stderr, "%s: %d bytes:\n", prefix, len);
+        while(len > 0){
+            for(i = 0; i < 16; i++){
+                if(i < len){
+                    fprintf(stderr, "%02x ", buf[i]);
+                }else{
+                    fprintf(stderr, "   ");
+                }
+                if(i == 7)
+                    fputc(' ', stderr);
+            }
+            fprintf(stderr, "  \"");
+            for(i = 0; i < 16; i++){
+                if(i < len){
+                    if(buf[i] >= 0x20 && buf[i] < 0x7f){
+                        fputc(buf[i], stderr);
+                    }else{
+                        fputc('.', stderr);
+                    }
+                }
+            }
+            fprintf(stderr, "\"\n");
+            buf += 16;
+            len -= 16;
+        }
+    }
+}
+
+static char *usbErrorText(int usbErrno)
+{
+    static char buffer[32];
+
+    switch(usbErrno){
+        case USB_ERROR_NONE:    return "Success.";
+        case USB_ERROR_ACCESS:  return "Access denied.";
+        case USB_ERROR_NOTFOUND:return "Device not found.";
+        case USB_ERROR_BUSY:    return "Device is busy.";
+        case USB_ERROR_IO:      return "I/O Error.";
+        default:
+            sprintf(buffer, "Unknown error %d.", usbErrno);
+            return buffer;
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void avrdoper_open(char *port, long baud, union filedescriptor *fdp)
+{
+    int rval;
+    char *vname = "obdev.at";
+    char *devname = "AVR-Doper";
+
+    rval = usbOpenDevice(fdp, USB_VENDOR_ID, vname, USB_PRODUCT_ID, devname, 1);
+    if(rval != 0){
+        fprintf(stderr, "%s: avrdoper_open(): %s\n", progname, usbErrorText(rval));
+        exit(1);
+    }
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void avrdoper_close(union filedescriptor *fdp)
+{
+    usbCloseDevice(fdp);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int  chooseDataSize(int len)
+{
+    int i;
+
+    for(i = 0; i < sizeof(reportDataSizes)/sizeof(reportDataSizes[0]); i++){
+        if(reportDataSizes[i] >= len)
+            return i;
+    }
+    return i - 1;
+}
+
+static int avrdoper_send(union filedescriptor *fdp, unsigned char *buf, size_t buflen)
+{
+    if(verbose > 3)
+        dumpBlock("Send", buf, buflen);
+    while(buflen > 0){
+        unsigned char buffer[256];
+        int rval, lenIndex = chooseDataSize(buflen);
+        int thisLen = buflen > reportDataSizes[lenIndex] ?
+	    reportDataSizes[lenIndex] : buflen;
+        buffer[0] = lenIndex + 1;   /* report ID */
+        buffer[1] = thisLen;
+        memcpy(buffer + 2, buf, thisLen);
+        if(verbose > 3)
+            fprintf(stderr, "Sending %d bytes data chunk\n", thisLen);
+        rval = usbSetReport(fdp, USB_HID_REPORT_TYPE_FEATURE, (char *)buffer,
+			    reportDataSizes[lenIndex] + 2);
+        if(rval != 0){
+            fprintf(stderr, "%s: avrdoper_send(): %s\n", progname, usbErrorText(rval));
+            exit(1);
+        }
+        buflen -= thisLen;
+        buf += thisLen;
+    }
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void avrdoperFillBuffer(union filedescriptor *fdp)
+{
+    int bytesPending = reportDataSizes[1];  /* guess how much data is buffered in device */
+
+    avrdoperRxPosition = avrdoperRxLength = 0;
+    while(bytesPending > 0){
+        int len, usbErr, lenIndex = chooseDataSize(bytesPending);
+        unsigned char buffer[128];
+        len = sizeof(avrdoperRxBuffer) - avrdoperRxLength;  /* bytes remaining */
+        if(reportDataSizes[lenIndex] + 2 > len) /* requested data would not fit into buffer */
+            break;
+        len = reportDataSizes[lenIndex] + 2;
+        usbErr = usbGetReport(fdp, USB_HID_REPORT_TYPE_FEATURE, lenIndex + 1,
+			      (char *)buffer, &len);
+        if(usbErr != 0){
+            fprintf(stderr, "%s: avrdoperFillBuffer(): %s\n", progname, usbErrorText(usbErr));
+            exit(1);
+        }
+        if(verbose > 3)
+            fprintf(stderr, "Received %d bytes data chunk of total %d\n", len - 2, buffer[1]);
+        len -= 2;   /* compensate for report ID and length byte */
+        bytesPending = buffer[1] - len; /* amount still buffered */
+        if(len > buffer[1])             /* cut away padding */
+            len = buffer[1];
+        if(avrdoperRxLength + len > sizeof(avrdoperRxBuffer)){
+            fprintf(stderr,
+		    "%s: avrdoperFillBuffer(): internal error: buffer overflow\n",
+		    progname);
+            exit(1);
+        }
+        memcpy(avrdoperRxBuffer + avrdoperRxLength, buffer + 2, len);
+        avrdoperRxLength += len;
+    }
+}
+
+static int avrdoper_recv(union filedescriptor *fdp, unsigned char *buf, size_t buflen)
+{
+    unsigned char   *p = buf;
+    int             remaining = buflen;
+
+    while(remaining > 0){
+        int len, available = avrdoperRxLength - avrdoperRxPosition;
+        if(available <= 0){ /* buffer is empty */
+            avrdoperFillBuffer(fdp);
+            continue;
+        }
+        len = remaining < available ? remaining : available;
+        memcpy(p, avrdoperRxBuffer + avrdoperRxPosition, len);
+        p += len;
+        remaining -= len;
+        avrdoperRxPosition += len;
+    }
+    if(verbose > 3)
+        dumpBlock("Receive", buf, buflen);
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int avrdoper_drain(union filedescriptor *fdp, int display)
+{
+    do{
+        avrdoperFillBuffer(fdp);
+    }while(avrdoperRxLength > 0);
+    return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+struct serial_device avrdoper_serdev =
+{
+  .open = avrdoper_open,
+  .close = avrdoper_close,
+  .send = avrdoper_send,
+  .recv = avrdoper_recv,
+  .drain = avrdoper_drain,
+  .flags = SERDEV_FL_NONE,
+};
+
+#endif /* defined(HAVE_LIBUSB) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID)) */
diff --git a/avrdude/serial.h b/avrdude/serial.h
index 1b19f26a..19ce5b4e 100644
--- a/avrdude/serial.h
+++ b/avrdude/serial.h
@@ -53,7 +53,10 @@ struct serial_device
 };
 
 extern struct serial_device *serdev;
-extern struct serial_device serial_serdev, usb_serdev, usb_serdev_frame;
+extern struct serial_device serial_serdev;
+extern struct serial_device usb_serdev;
+extern struct serial_device usb_serdev_frame;
+extern struct serial_device avrdoper_serdev;
 
 #define serial_open (serdev->open)
 #define serial_setspeed (serdev->setspeed)
diff --git a/avrdude/stk500v2.c b/avrdude/stk500v2.c
index db80d3fa..94ea11f5 100644
--- a/avrdude/stk500v2.c
+++ b/avrdude/stk500v2.c
@@ -960,6 +960,16 @@ static int stk500v2_open(PROGRAMMER * pgm, char * port)
 
   pgmtype = PGMTYPE_UNKNOWN;
 
+  if(strcasecmp(port, "avrdoper") == 0){
+#if defined(HAVE_LIBUSB) || defined(WIN32NATIVE)
+    serdev = &avrdoper_serdev;
+    pgmtype = PGMTYPE_STK500;
+#else
+    fprintf(stderr, "avrdude was compiled without usb support.\n");
+    return -1;
+#endif
+  }
+
   /*
    * If the port name starts with "usb", divert the serial routines
    * to the USB ones.  The serial_open() function for USB overrides