diff --git a/ChangeLog b/ChangeLog
index c52cd134..6a2a3b39 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2018-01-15  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
+
+	Submitted by Axel Simon:
+	patch #9033: avrdoper backend uses libhidapi instead of libusb
+	* ser_avrdoper: Add libhidapi implementation
+	* stk500v2.c: Adapt #ifdefs for LIBHIDAPI
+	* avrdude.1: Document change
+	* doc/avrdude.texi: (Dito)
+
 2018-01-13  Joerg Wunsch <j.gnu@uriah.heep.sax.de>
 
 	Submitted by David Mosberger-Tang
diff --git a/NEWS b/NEWS
index 2f1800d5..9aa33d37 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,7 @@ Current:
       debuggers (JTAGICE3 with firmware 3+, AtmelICE, EDBG, mEDBG)
     - UPDI support added (AVR8X family)
     - TPI support for USBtinyISP
+    - AVR Doper uses libhidapi rather than raw libusb (patch #9033)
 
   * New devices supported:
 
@@ -53,6 +54,7 @@ Current:
     patch #9317: Support atmega64m1 as part
     patch #9222: Enable silent build
     patch #8924: Enable TPI for usbtiny
+    patch #9033: avrdoper backend uses libhidapi instead of libusb
 
   * Internals:
     - New avrdude.conf keyword "family_id", used to verify SIB attributes
diff --git a/avrdude.1 b/avrdude.1
index 65fc7b1d..ce1f041f 100644
--- a/avrdude.1
+++ b/avrdude.1
@@ -485,7 +485,7 @@ 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
 .Ar avrdoper.
-Libusb support is required on Unix but not on Windows. For more
+Libhidapi support is required on Unix and Mac OS but not on Windows. For more
 information about AVR-Doper see http://www.obdev.at/avrusb/avrdoper.html.
 .Pp
 For the USBtinyISP, which is a simplicistic device not implementing
diff --git a/doc/avrdude.texi b/doc/avrdude.texi
index 227399fa..5da36c9c 100644
--- a/doc/avrdude.texi
+++ b/doc/avrdude.texi
@@ -542,8 +542,8 @@ 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
+be specified as @var{avrdoper}. Libhidapi support is required on Unix
+and Mac OS but not on Windows. For more information about AVR-Doper see
 @url{http://www.obdev.at/avrusb/avrdoper.html}.
 
 For the USBtinyISP, which is a simplistic device not implementing
diff --git a/ser_avrdoper.c b/ser_avrdoper.c
index 71080b7c..8eae2c3f 100644
--- a/ser_avrdoper.c
+++ b/ser_avrdoper.c
@@ -26,7 +26,7 @@
 
 #include "ac_cfg.h"
 
-#if defined(HAVE_LIBUSB) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
+#if defined(HAVE_LIBHIDAPI) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
 
 #include <stdio.h>
 #include <string.h>
@@ -64,7 +64,102 @@ static int              avrdoperRxPosition = 0; /* amount of bytes already consu
 /* ------------------------------------------------------------------------ */
 /* ------------------------------------------------------------------------ */
 
-#if defined(WIN32NATIVE) && defined(HAVE_LIBHID)
+#if defined(HAVE_LIBHIDAPI)
+
+#include <hidapi/hidapi.h>
+
+/* ------------------------------------------------------------------------- */
+
+static int usbOpenDevice(union filedescriptor *fdp, int vendor, char *vendorName,
+			 int product, char *productName, int doReportIDs)
+{
+    hid_device *dev;
+
+    dev = hid_open(vendor, product, NULL);
+    if (dev == NULL)
+    {
+      avrdude_message(MSG_INFO, "%s: usbOpenDevice(): No device found\n",
+		    progname);
+      return USB_ERROR_NOTFOUND;
+    }
+    fdp->usb.handle = dev;
+    return USB_ERROR_NONE;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void usbCloseDevice(union filedescriptor *fdp)
+{
+  hid_device *udev = (hid_device *)fdp->usb.handle;
+  fdp->usb.handle = NULL;
+
+  if (udev == NULL)
+    return;
+
+  hid_close(udev);
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int usbSetReport(union filedescriptor *fdp, int reportType, char *buffer, int len)
+{
+  hid_device *udev = (hid_device *)fdp->usb.handle;
+  int bytesSent = -1;
+
+  switch(reportType){
+  case USB_HID_REPORT_TYPE_INPUT:
+      break;
+  case USB_HID_REPORT_TYPE_OUTPUT:
+      bytesSent = hid_write(udev, (unsigned char*) buffer, len);
+      break;
+  case USB_HID_REPORT_TYPE_FEATURE:
+      bytesSent = hid_send_feature_report(udev, (unsigned char*) buffer, len);
+      break;
+  }
+
+  if(bytesSent != len){
+      if(bytesSent < 0)
+          avrdude_message(MSG_INFO, "Error sending message: %s\n", hid_error(udev));
+      return USB_ERROR_IO;
+  }
+  return USB_ERROR_NONE;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int usbGetReport(union filedescriptor *fdp, int reportType, int reportNumber,
+			char *buffer, int *len)
+{
+  hid_device *udev = (hid_device *)fdp->usb.handle;
+  int bytesReceived = -1;
+
+  switch(reportType){
+  case USB_HID_REPORT_TYPE_INPUT:
+      bytesReceived = hid_read_timeout(udev, (unsigned char*) buffer, *len, 300);
+      break;
+  case USB_HID_REPORT_TYPE_OUTPUT:
+      break;
+  case USB_HID_REPORT_TYPE_FEATURE:
+      bytesReceived = hid_get_feature_report(udev, (unsigned char*) buffer, *len);
+      break;
+  }
+  if(bytesReceived < 0){
+      avrdude_message(MSG_INFO, "Error sending message: %s\n", hid_error(udev));
+      return USB_ERROR_IO;
+  }
+  *len = bytesReceived;
+  return USB_ERROR_NONE;
+}
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
+#else /* !defined(HAVE_LIBHIDAPI) */
+
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+/* ------------------------------------------------------------------------ */
+
 
 #include <windows.h>
 #include <setupapi.h>
@@ -237,204 +332,6 @@ static int usbGetReport(union filedescriptor *fdp, int reportType, int reportNum
     return rval == 0 ? USB_ERROR_IO : 0;
 }
 
-/* ------------------------------------------------------------------------ */
-/* ------------------------------------------------------------------------ */
-/* ------------------------------------------------------------------------ */
-
-#else /* !(WIN32NATIVE && HAVE_LIBHID) */
-
-/* ------------------------------------------------------------------------ */
-/* ------------------------------------------------------------------------ */
-/* ------------------------------------------------------------------------ */
-
-#if defined(HAVE_USB_H)
-#  include <usb.h>
-#elif defined(HAVE_LUSB0_USB_H)
-#  include <lusb0_usb.h>
-#else
-#  error "libusb needs either <usb.h> or <lusb0_usb.h>"
-#endif
-
-/* ------------------------------------------------------------------------- */
-
-#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;
-                    avrdude_message(MSG_INFO, "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;
-                    avrdude_message(MSG_INFO, "Warning: cannot query manufacturer for device: %s\n",
-                                    usb_strerror());
-                }else{
-                    errorCode = USB_ERROR_NOTFOUND;
-                    /* avrdude_message(MSG_INFO, "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;
-                            avrdude_message(MSG_INFO, "Warning: cannot query product for device: %s\n",
-                                            usb_strerror());
-                        }else{
-                            errorCode = USB_ERROR_NOTFOUND;
-                            /* avrdude_message(MSG_INFO, "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)){
-            avrdude_message(MSG_INFO, "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){
-                avrdude_message(MSG_INFO, "Warning: could not detach kernel HID driver: %s\n",
-			usb_strerror());
-            }
-#endif
-        }
-        if(rval != 0)
-            avrdude_message(MSG_INFO, "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)
-            avrdude_message(MSG_INFO, "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){
-        avrdude_message(MSG_INFO, "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 */
 
 /* ------------------------------------------------------------------------ */
@@ -658,4 +555,4 @@ struct serial_device avrdoper_serdev =
   .flags = SERDEV_FL_NONE,
 };
 
-#endif /* defined(HAVE_LIBUSB) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID)) */
+#endif /* defined(HAVE_LIBHIDAPI) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID)) */
diff --git a/stk500v2.c b/stk500v2.c
index 0e5ff620..82050d36 100644
--- a/stk500v2.c
+++ b/stk500v2.c
@@ -1609,11 +1609,11 @@ static int stk500v2_open(PROGRAMMER * pgm, char * port)
   PDATA(pgm)->pgmtype = PGMTYPE_UNKNOWN;
 
   if(strcasecmp(port, "avrdoper") == 0){
-#if defined(HAVE_LIBUSB) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
+#if defined(HAVE_LIBHIDAPI) || (defined(WIN32NATIVE) && defined(HAVE_LIBHID))
     serdev = &avrdoper_serdev;
     PDATA(pgm)->pgmtype = PGMTYPE_STK500;
 #else
-    avrdude_message(MSG_INFO, "avrdude was compiled without usb support.\n");
+    avrdude_message(MSG_INFO, "avrdoper requires avrdude with hid support.\n");
     return -1;
 #endif
   }