Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[patch #8954] Enable usage of libusb-1.0 for stk500v2 (aka avrispmkii) #704

Closed
avrs-admin opened this issue Dec 13, 2021 · 8 comments
Closed
Labels
enhancement New feature or request

Comments

@avrs-admin
Copy link

Thu 24 Mar 2016 12:32:46 PM UTC

I tried using an AVRISPmkII in Windows 10 with avrdude 6.3, but libusb couldn't find the device ("avrdude.exe: usbdev_open(): did not find any USB device "usb" (0x03eb:0x2104)").

Since libusb 0.1 is marked deprecated in cygwin, I installed libusb-1.0 and had a look at usbasp.c, where v1.0 is already in use. I then added support for libusb-1.0 in usb_libusb.c, and expanded the corresponding preprocessor conditions in jtag3.c, jtagmkII.c and stk500v2.c.

After replacing the ATMEL driver of the AVRISP by the WinUSB driver using Zadig avrdude is once more able to flash my AVRs using AVRISPmkII.

I also successfully applied and tested my patch with said AVRISPmkII in a virtual machine running xubuntu 14.04.

file #36745: libusb.patch

This issue was migrated from https://savannah.nongnu.org/patch/?8954

@avrs-admin avrs-admin added the question Further information is requested label Dec 13, 2021
@avrs-admin
Copy link
Author

Joerg Wunsch <joerg_wunsch>
Sun 21 Jan 2018 10:21:05 PM UTC

This does unfortunately not compile under FreeBSD where the OS
offers a libusb-1.0 API compatible USB library:

usb_libusb.c:265:17: warning: implicit declaration of function 'libusb_has_capability' is invalid in C99
[-Wimplicit-function-declaration]
if (libusb_has_capability(LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER))
^
usb_libusb.c:265:39: error: use of undeclared identifier 'LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER'
if (libusb_has_capability(LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER))
^
usb_libusb.c:723:62: warning: passing 'char *' to parameter of type 'uint8_t *' (aka 'unsigned char *') converts between
pointers to integer types with different sign [-Wpointer-sign]
errcode = libusb_interrupt_transfer(udev, fd->usb.wep, (char *)bp, tx_size, &rv, 10000);
^~~~~~~~~~
/usr/include/libusb.h:549:87: note: passing argument to parameter 'data' here
int     libusb_interrupt_transfer(libusb_device_handle * devh, uint8_t endpoint, uint8_t *data, int length, int *trans...
^
usb_libusb.c:725:57: warning: passing 'char *' to parameter of type 'uint8_t *' (aka 'unsigned char *') converts between
pointers to integer types with different sign [-Wpointer-sign]
errcode = libusb_bulk_transfer(udev, fd->usb.wep, (char *)bp, tx_size, &rv, 10000);
^~~~~~~~~~
/usr/include/libusb.h:548:82: note: passing argument to parameter 'data' here
int     libusb_bulk_transfer(libusb_device_handle * devh, uint8_t endpoint, uint8_t *data, int length, int *transferre...
^
usb_libusb.c:792:51: warning: passing 'char [512]' to parameter of type 'uint8_t *' (aka 'unsigned char *') converts between
pointers to integer types with different sign [-Wpointer-sign]
errcode = libusb_interrupt_transfer(udev, ep, usbbuf, maxsize, &rv, 10000);
^~~~~~
/usr/include/libusb.h:549:87: note: passing argument to parameter 'data' here
int     libusb_interrupt_transfer(libusb_device_handle * devh, uint8_t endpoint, uint8_t *data, int length, int *trans...
^
usb_libusb.c:794:46: warning: passing 'char [512]' to parameter of type 'uint8_t *' (aka 'unsigned char *') converts between
pointers to integer types with different sign [-Wpointer-sign]
errcode = libusb_bulk_transfer(udev, ep, usbbuf, maxsize, &rv, 10000);
^~~~~~
/usr/include/libusb.h:548:82: note: passing argument to parameter 'data' here
int     libusb_bulk_transfer(libusb_device_handle * devh, uint8_t endpoint, uint8_t *data, int length, int *transferre...
^
usb_libusb.c:897:57: warning: passing 'char [512]' to parameter of type 'uint8_t *' (aka 'unsigned char *') converts between
pointers to integer types with different sign [-Wpointer-sign]
errcode = libusb_bulk_transfer(udev, fd->usb.eep, usbbuf,
^~~~~~
/usr/include/libusb.h:548:82: note: passing argument to parameter 'data' here
int     libusb_bulk_transfer(libusb_device_handle * devh, uint8_t endpoint, uint8_t *data, int length, int *transferre...
^
usb_libusb.c:923:64: warning: passing 'char [512]' to parameter of type 'uint8_t *' (aka 'unsigned char *') converts between
pointers to integer types with different sign [-Wpointer-sign]
errcode = libusb_interrupt_transfer(udev, fd->usb.rep, usbbuf,
^~~~~~
/usr/include/libusb.h:549:87: note: passing argument to parameter 'data' here
int     libusb_interrupt_transfer(libusb_device_handle * devh, uint8_t endpoint, uint8_t *data, int length, int *trans...
^
usb_libusb.c:926:59: warning: passing 'char [512]' to parameter of type 'uint8_t *' (aka 'unsigned char *') converts between
pointers to integer types with different sign [-Wpointer-sign]
errcode = libusb_bulk_transfer(udev, fd->usb.rep, usbbuf,
^~~~~~
/usr/include/libusb.h:548:82: note: passing argument to parameter 'data' here
int     libusb_bulk_transfer(libusb_device_handle * devh, uint8_t endpoint, uint8_t *data, int length, int *transferre...
^

So it seems the libusb_has_capability() needs an explicit
probing in configure.ac as it has not always been part of
the libusb-1.0 API.  (Unfortunately, LIBUSB_CAP_HAS_CAPABILITY
is part of an enum rather than a #define, so it cannot be
tested at compile-time.  Seems someone didn't really think
about that detail before.)

The warnings about char vs. uint8_t * can probably safely
be silenced using typecasts.

@mcuee
Copy link
Collaborator

mcuee commented May 22, 2022

I believe this issue has been fixed in later version of FreeBSD.
https://svnweb.freebsd.org/base?view=revision&revision=362224

@MCUdude
Copy link
Collaborator

MCUdude commented May 22, 2022

@dl8dtl can you confirm?

@dl8dtl
Copy link
Contributor

dl8dtl commented May 23, 2022

Well, it's supposed to be in the latest FreeBSD 11.x release (11.4 – 11.x is discontinued now), and since 12.2 in the 12.x release line (and then all more recent ones).

So yes, with any supported FreeBSD version, it compiles now. It causes a bunch of warnings though:

[  6%] Building C object src/CMakeFiles/libavrdude.dir/usb_libusb.c.o
/home/joerg/src/avrdude-official/src/usb_libusb.c:723:62: warning: passing 'char *' to parameter of type 'uint8_t *' (aka 'unsigned char *') converts between pointers to integer types where one is of the unique plain 'char' type and the other is not [-Wpointer-sign]
      errcode = libusb_interrupt_transfer(udev, fd->usb.wep, (char *)bp, tx_size, &rv, 10000);
                                                             ^~~~~~~~~~
/usr/include/libusb.h:569:87: note: passing argument to parameter 'data' here
int     libusb_interrupt_transfer(libusb_device_handle * devh, uint8_t endpoint, uint8_t *data, int length, int *transferred, uint32_t timeout);
                                                                                          ^

In the quoted case, there's even a (char *) typecast (which is completely wrong here), in some other cases, there's a warning without the cast as the parameter passed is of type char[].

Just reviewed the header file at https://github.com/libusb/libusb/blob/master/libusb/libusb.h, they also use unsigned char * for these functions.

Thus, the code needs a bit of cleanup at first, and thorough testing against all affected devices (AVRISPmkII, JTAGICEmkII, JTAGICE3, AtmelICE, STK600, AVR Dragon – did I forget any?) afterwards, as it changes the underlying transport library for all these devices.

@mcuee
Copy link
Collaborator

mcuee commented May 24, 2022

Thus, the code needs a bit of cleanup at first, and thorough testing against all affected devices (AVRISPmkII, JTAGICEmkII, JTAGICE3, AtmelICE, STK600, AVR Dragon – did I forget any?) afterwards, as it changes the underlying transport library for all these devices.

I have the AVR Dragon so I can help out testing.

Related topic:

@mcuee mcuee added the enhancement New feature or request label Jun 19, 2022
@mcuee mcuee removed the question Further information is requested label Aug 6, 2022
@mcuee
Copy link
Collaborator

mcuee commented Apr 9, 2023

Just post the patch code here for easier view.

Index: avrdude/jtag3.c
===================================================================
--- avrdude/jtag3.c	(revision 1387)
+++ avrdude/jtag3.c	(working copy)
@@ -1314,7 +1314,7 @@
   LNODEID usbpid;
   int rv = -1;
 
-#if !defined(HAVE_LIBUSB) && !defined(HAVE_LIBHIDAPI)
+#if !defined(HAVE_LIBUSB) && !defined(HAVE_LIBUSB_1_0) && !defined(HAVE_LIBHIDAPI)
   avrdude_message(MSG_INFO, "avrdude was compiled without USB or HIDAPI support.\n");
   return -1;
 #endif
@@ -1353,7 +1353,7 @@
   }
   if (rv < 0) {
 #endif	/* HAVE_LIBHIDAPI */
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev_frame;
     for (usbpid = lfirst(pgm->usbpid); rv < 0 && usbpid != NULL; usbpid = lnext(usbpid)) {
       pinfo.usbinfo.flags = PINFO_FL_SILENT;
@@ -1366,7 +1366,7 @@
       strcpy(pgm->port, port);
       rv = serial_open(port, pinfo, &pgm->fd);
     }
-#endif	/* HAVE_LIBUSB */
+#endif	/* HAVE_LIBUSB || HAVE_LIBUSB_1_0 */
 #if defined(HAVE_LIBHIDAPI)
   }
 #endif
Index: avrdude/jtagmkII.c
===================================================================
--- avrdude/jtagmkII.c	(revision 1387)
+++ avrdude/jtagmkII.c	(working copy)
@@ -1502,7 +1502,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
@@ -1554,7 +1554,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
@@ -1606,7 +1606,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
@@ -1659,7 +1659,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
@@ -1712,7 +1712,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
@@ -1765,7 +1765,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
@@ -3342,7 +3342,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
Index: avrdude/stk500v2.c
===================================================================
--- avrdude/stk500v2.c	(revision 1387)
+++ avrdude/stk500v2.c	(working copy)
@@ -1633,7 +1633,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev_frame;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
@@ -1691,7 +1691,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev_frame;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
@@ -3395,7 +3395,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
@@ -3506,7 +3506,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
@@ -3584,7 +3584,7 @@
    * search for.
    */
   if (strncmp(port, "usb", 3) == 0) {
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
     serdev = &usb_serdev;
     pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
     pinfo.usbinfo.flags = 0;
Index: avrdude/usb_libusb.c
===================================================================
--- avrdude/usb_libusb.c	(revision 1387)
+++ avrdude/usb_libusb.c	(working copy)
@@ -24,8 +24,11 @@
  */
 
 #include "ac_cfg.h"
-#if defined(HAVE_LIBUSB)
+#if defined(HAVE_LIBUSB) || defined(HAVE_LIBUSB_1_0)
 
+#ifdef HAVE_LIBUSB_1_0
+# define USE_LIBUSB_1_0
+#endif
 
 #include <ctype.h>
 #include <stdio.h>
@@ -35,6 +38,13 @@
 #include <sys/types.h>
 #include <sys/time.h>
 
+#if defined(USE_LIBUSB_1_0)
+# if defined(HAVE_LIBUSB_1_0_LIBUSB_H)
+#  include <libusb-1.0/libusb.h>
+# else
+#  include <libusb.h>
+# endif
+#else
 #if defined(HAVE_USB_H)
 #  include <usb.h>
 #elif defined(HAVE_LUSB0_USB_H)
@@ -42,6 +52,7 @@
 #else
 #  error "libusb needs either <usb.h> or <lusb0_usb.h>"
 #endif
+#endif
 
 #include "avrdude.h"
 #include "libavrdude.h"
@@ -58,6 +69,11 @@
 
 static int usb_interface;
 
+#ifdef USE_LIBUSB_1_0
+
+static libusb_context *ctx = NULL;
+
+
 /*
  * The "baud" parameter is meaningless for USB devices, so we reuse it
  * to pass the desired USB device ID.
@@ -66,6 +82,315 @@
 {
   char string[256];
   char product[256];
+  libusb_device **dev_list;
+  int dev_list_len;
+  char *serno, *cp2;
+  int i;
+  int iface;
+  size_t x;
+  int j;
+  int r;
+
+  /*
+   * The syntax for usb devices is defined as:
+   *
+   * -P usb[:serialnumber]
+   *
+   * See if we've got a serial number passed here.  The serial number
+   * might contain colons which we remove below, and we compare it
+   * right-to-left, so only the least significant nibbles need to be
+   * specified.
+   */
+  if ((serno = strchr(port, ':')) != NULL)
+  {
+    /* first, drop all colons there if any */
+    cp2 = ++serno;
+
+    while ((cp2 = strchr(cp2, ':')) != NULL)
+    {
+      x = strlen(cp2) - 1;
+      memmove(cp2, cp2 + 1, x);
+      cp2[x] = '\0';
+    }
+
+    if (strlen(serno) > 12)
+    {
+      avrdude_message(MSG_INFO, "%s: usbdev_open(): invalid serial number \"%s\"\n",
+              progname, serno);
+      return -1;
+    }
+  }
+
+  if (fd->usb.max_xfer == 0)
+    fd->usb.max_xfer = USBDEV_MAX_XFER_MKII;
+
+  if(ctx == NULL)
+  {
+    r = libusb_init(&ctx);
+    if (r < LIBUSB_SUCCESS)
+    {
+      avrdude_message(MSG_INFO, "%s: usb_open(): libusb_init failed \"%s\"\n",
+              progname, libusb_strerror(r));
+      /* no chance */
+      return -1;
+    }
+
+#if 1	/* enable debugging messages in the lib */
+    if (verbose > 3)
+      libusb_set_debug(ctx, LIBUSB_LOG_LEVEL_DEBUG);
+    else if (verbose > 2)
+      libusb_set_debug(ctx, LIBUSB_LOG_LEVEL_INFO);
+    else if (verbose > 1)
+      libusb_set_debug(ctx, LIBUSB_LOG_LEVEL_WARNING);
+    else if (verbose > 0)
+      libusb_set_debug(ctx, LIBUSB_LOG_LEVEL_ERROR);
+#endif
+  }
+
+  dev_list_len = libusb_get_device_list(ctx, &dev_list);
+
+  for (j = 0; j < dev_list_len; ++j)
+  {
+    libusb_device *dev = dev_list[j];
+    struct libusb_device_descriptor descriptor;
+
+    r = libusb_get_device_descriptor(dev, &descriptor);
+    if (r >= LIBUSB_SUCCESS)
+    {
+      if (descriptor.idVendor == pinfo.usbinfo.vid && descriptor.idProduct == pinfo.usbinfo.pid)
+      {
+        libusb_device_handle *udev = NULL;
+        struct libusb_config_descriptor *config = NULL;
+
+        /* we need to open the device in order to query strings */
+        r = libusb_open(dev, &udev);
+        if (udev)
+        {
+          /* yeah, we found something */
+          r = libusb_get_string_descriptor_ascii(udev, descriptor.iSerialNumber & 0xff, (unsigned char*)string, sizeof(string));
+          if (r < LIBUSB_SUCCESS)
+          {
+            avrdude_message(MSG_INFO, "%s: usb_open(): cannot read serial number \"%s\"\n",
+                    progname, libusb_strerror(r));
+            /*
+             * On some systems, libusb appears to have
+             * problems sending control messages.  Catch the
+             * benign case where the user did not request a
+             * particular serial number, so we could
+             * continue anyway.
+             */
+            if (serno != NULL)
+            {
+#if 0
+              /* user has to free all allocated lists and buffers */
+              libusb_close(udev);
+              libusb_free_device_list(dev_list,1);
+              return -1; /* no chance */
+#else
+              goto trynext;
+#endif
+            }
+            strcpy(string, "[unknown]");
+          }
+
+          r = libusb_get_string_descriptor_ascii(udev, descriptor.iProduct & 0xff, (unsigned char*)product, sizeof(product));
+          if (r < LIBUSB_SUCCESS)
+          {
+            avrdude_message(MSG_INFO, "%s: usb_open(): cannot read product name \"%s\"\n",
+                    progname, libusb_strerror(r));
+            strcpy(product, "[unnamed product]");
+          }
+          /*
+           * The CMSIS-DAP specification mandates the string
+           * "CMSIS-DAP" must be present somewhere in the
+           * product name string for a device compliant to
+           * that protocol.  Use this for the decisision
+           * whether we have to search for a HID interface
+           * below.
+           */
+          if(strstr(product, "CMSIS-DAP") != NULL)
+          {
+            pinfo.usbinfo.flags |= PINFO_FL_USEHID;
+            /* The JTAGICE3 running the CMSIS-DAP firmware doesn't
+             * use a separate endpoint for event reception. */
+            fd->usb.eep = 0;
+          }
+
+          if(strstr(product, "mEDBG") != NULL)
+          {
+            /* The AVR Xplained Mini uses different endpoints. */
+            fd->usb.rep = 0x81;
+            fd->usb.wep = 0x02;
+          }
+
+          avrdude_message(MSG_NOTICE, "%s: usbdev_open(): Found %s, serno: %s\n",
+                  progname, product, string);
+          if (serno != NULL)
+          {
+            /*
+             * See if the serial number requested by the
+             * user matches what we found, matching
+             * right-to-left.
+             */
+            x = strlen(string) - strlen(serno);
+            if (strcasecmp(string + x, serno) != 0)
+            {
+              avrdude_message(MSG_DEBUG, "%s: usbdev_open(): serial number doesn't match\n",
+                      progname);
+              goto trynext;
+            }
+          }
+
+          /* remember to free the allocated buffer when done */
+          libusb_get_config_descriptor(dev, 0, &config);
+          if (config == NULL)
+          {
+            avrdude_message(MSG_INFO, "%s: usbdev_open(): USB device has no configuration\n",
+                    progname);
+            goto trynext;
+          }
+
+          r = libusb_set_configuration(udev, config->bConfigurationValue);
+          if (r < LIBUSB_SUCCESS) {
+            avrdude_message(MSG_INFO, "%s: usbdev_open(): WARNING: failed to set configuration %d: %s\n",
+                    progname, config->bConfigurationValue,
+                    libusb_strerror(r));
+            /* let's hope it has already been configured */
+            // goto trynext;
+          }
+
+          for (iface = 0; iface < config->bNumInterfaces; iface++)
+          {
+            usb_interface = config->interface[iface].altsetting[0].bInterfaceNumber;
+            if (libusb_has_capability(LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER))
+            {
+              /*
+               * Many Linux systems attach the usbhid driver
+               * by default to any HID-class device.  On
+               * those, the driver needs to be detached before
+               * we can claim the interface.
+               */
+              (void)libusb_detach_kernel_driver(udev, usb_interface);
+            }
+            r = libusb_claim_interface(udev, usb_interface);
+            if (r < LIBUSB_SUCCESS)
+            {
+              avrdude_message(MSG_INFO, "%s: usbdev_open(): error claiming interface %d: %s\n",
+                      progname, usb_interface, libusb_strerror(r));
+            }
+            else
+            {
+              if (pinfo.usbinfo.flags & PINFO_FL_USEHID)
+              {
+                /* only consider an interface that is of class HID */
+                if (config->interface[iface].altsetting[0].bInterfaceClass !=
+                  LIBUSB_CLASS_HID)
+                  continue;
+                fd->usb.use_interrupt_xfer = 1;
+              }
+              break;
+            }
+          }
+
+          if (iface == config->bNumInterfaces)
+          {
+            avrdude_message(MSG_INFO, "%s: usbdev_open(): no usable interface found\n",
+                    progname);
+            goto trynext;
+          }
+          fd->usb.handle = udev;
+
+          if (fd->usb.rep == 0)
+          {
+            /* Try finding out what our read endpoint is. */
+            for (i = 0; i < config->interface[iface].altsetting[0].bNumEndpoints; i++)
+            {
+              int possible_ep = config->interface[iface].altsetting[0].
+                endpoint[i].bEndpointAddress;
+
+              if ((possible_ep & LIBUSB_ENDPOINT_DIR_MASK) != 0)
+              {
+                avrdude_message(MSG_NOTICE2, "%s: usbdev_open(): using read endpoint 0x%02x\n",
+                        progname, possible_ep);
+                fd->usb.rep = possible_ep;
+                break;
+              }
+            }
+            if (fd->usb.rep == 0)
+            {
+              avrdude_message(MSG_INFO, "%s: usbdev_open(): cannot find a read endpoint, using 0x%02x\n",
+                      progname, USBDEV_BULK_EP_READ_MKII);
+              fd->usb.rep = USBDEV_BULK_EP_READ_MKII;
+            }
+          }
+
+          for (i = 0; i < config->interface[iface].altsetting[0].bNumEndpoints; i++)
+          {
+            if ((config->interface[iface].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.rep ||
+              config->interface[iface].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.wep) &&
+              config->interface[iface].altsetting[0].endpoint[i].wMaxPacketSize < fd->usb.max_xfer)
+            {
+              avrdude_message(MSG_NOTICE, "%s: max packet size expected %d, but found %d due to EP 0x%02x's wMaxPacketSize\n",
+                      progname,
+                      fd->usb.max_xfer,
+                      config->interface[iface].altsetting[0].endpoint[i].wMaxPacketSize,
+                      config->interface[iface].altsetting[0].endpoint[i].bEndpointAddress);
+              fd->usb.max_xfer = config->interface[iface].altsetting[0].endpoint[i].wMaxPacketSize;
+            }
+          }
+          if (pinfo.usbinfo.flags & PINFO_FL_USEHID)
+          {
+            if (libusb_control_transfer(udev, 0x21, 0x0a /* SET_IDLE */, 0, 0, NULL, 0, 100) < 0)
+              avrdude_message(MSG_INFO, "%s: usbdev_open(): SET_IDLE failed\n", progname);
+          }
+
+          /* user has to free all allocated lists and buffers */
+          libusb_free_config_descriptor(config);
+          libusb_free_device_list(dev_list,1);
+          return 0;
+
+trynext:
+          /* user has to free all allocated lists and buffers */
+          if (config != NULL)
+            libusb_free_config_descriptor(config);
+          libusb_close(udev);
+          udev = NULL;
+        }
+        else
+        {
+          avrdude_message(MSG_INFO, "%s: usbdev_open(): cannot open device: %s\n",
+                  progname, libusb_strerror(r));
+        }
+      }
+    }
+  }
+
+  /* user has to free all allocated lists and buffers */
+  libusb_free_device_list(dev_list,1);
+
+  if (ctx != NULL)
+  {
+    libusb_exit(ctx);
+    ctx = NULL;
+  }
+
+  if ((pinfo.usbinfo.flags & PINFO_FL_SILENT) == 0)
+    avrdude_message(MSG_NOTICE, "%s: usbdev_open(): did not find any%s USB device \"%s\" (0x%04x:0x%04x)\n",
+      progname, serno? " (matching)": "", port,
+      (unsigned)pinfo.usbinfo.vid, (unsigned)pinfo.usbinfo.pid);
+  return -1;
+}
+
+#else  /* USE_LIBUSB_1_0 */
+
+/*
+ * The "baud" parameter is meaningless for USB devices, so we reuse it
+ * to pass the desired USB device ID.
+ */
+static int usbdev_open(char * port, union pinfo pinfo, union filedescriptor *fd)
+{
+  char string[256];
+  char product[256];
   struct usb_bus *bus;
   struct usb_device *dev;
   usb_dev_handle *udev;
@@ -306,8 +631,45 @@
   return -1;
 }
 
+#endif  /* USE_LIBUSB_1_0 */
+
+#ifdef USE_LIBUSB_1_0
+
 static void usbdev_close(union filedescriptor *fd)
 {
+  libusb_device_handle *udev = (libusb_device_handle *)fd->usb.handle;
+
+  if (udev == NULL)
+    return;
+
+  avrdude_message(MSG_DEBUG, "%s: usbdev_close()\n",
+    progname);
+
+  (void)libusb_release_interface(udev, usb_interface);
+
+#if defined(__linux__)
+  /*
+   * Without this reset, the AVRISP mkII seems to stall the second
+   * time we try to connect to it.  This is not necessary on
+   * FreeBSD.
+   */
+  libusb_reset_device(udev);
+#endif
+
+  libusb_close(udev);
+  fd->usb.handle = NULL;
+
+  if (ctx != NULL)
+  {
+    libusb_exit(ctx);
+    ctx = NULL;
+  }
+}
+
+#else  /* USE_LIBUSB_1_0 */
+
+static void usbdev_close(union filedescriptor *fd)
+{
   usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
 
   if (udev == NULL)
@@ -327,10 +689,17 @@
   usb_close(udev);
 }
 
+#endif  /* USE_LIBUSB_1_0 */
 
+
 static int usbdev_send(union filedescriptor *fd, const unsigned char *bp, size_t mlen)
 {
+#ifdef USE_LIBUSB_1_0
+  libusb_device_handle *udev = (libusb_device_handle *)fd->usb.handle;
+  int errcode;
+#else
   usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
+#endif
   int rv;
   int i = mlen;
   const unsigned char * p = bp;
@@ -348,7 +717,20 @@
    */
   do {
     tx_size = (mlen < fd->usb.max_xfer)? mlen: fd->usb.max_xfer;
+#ifdef USE_LIBUSB_1_0
+    rv = 0;
     if (fd->usb.use_interrupt_xfer)
+      errcode = libusb_interrupt_transfer(udev, fd->usb.wep, (char *)bp, tx_size, &rv, 10000);
+    else
+      errcode = libusb_bulk_transfer(udev, fd->usb.wep, (char *)bp, tx_size, &rv, 10000);
+    if (errcode < LIBUSB_SUCCESS || rv != tx_size)
+    {
+        avrdude_message(MSG_INFO, "%s: usbdev_send(): wrote %d out of %d bytes, err = %s\n",
+                progname, rv, tx_size, libusb_strerror(errcode));
+        return -1;
+    }
+#else
+    if (fd->usb.use_interrupt_xfer)
       rv = usb_interrupt_write(udev, fd->usb.wep, (char *)bp, tx_size, 10000);
     else
       rv = usb_bulk_write(udev, fd->usb.wep, (char *)bp, tx_size, 10000);
@@ -358,6 +740,7 @@
                 progname, rv, tx_size, usb_strerror());
         return -1;
     }
+#endif  /* USE_LIBUSB_1_0 */
     bp += tx_size;
     mlen -= tx_size;
   } while (mlen > 0);
@@ -393,11 +776,31 @@
  * empty and more data are requested.
  */
 static int
-usb_fill_buf(usb_dev_handle *udev, int maxsize, int ep, int use_interrupt_xfer)
+usb_fill_buf(void *handle, int maxsize, int ep, int use_interrupt_xfer)
 {
+#ifdef USE_LIBUSB_1_0
+  libusb_device_handle *udev = (libusb_device_handle *)handle;
+  int errcode;
+#else
+  usb_dev_handle *udev = (usb_dev_handle *)handle;
+#endif
   int rv;
 
+#ifdef USE_LIBUSB_1_0
+  rv = 0;
   if (use_interrupt_xfer)
+    errcode = libusb_interrupt_transfer(udev, ep, usbbuf, maxsize, &rv, 10000);
+  else
+    errcode = libusb_bulk_transfer(udev, ep, usbbuf, maxsize, &rv, 10000);
+  if (errcode < LIBUSB_SUCCESS)
+  {
+    avrdude_message(MSG_NOTICE2, "%s: usb_fill_buf(): usb_%s_read() error %s\n",
+      progname, (use_interrupt_xfer? "interrupt": "bulk"),
+      libusb_strerror(errcode));
+    return -1;
+  }
+#else
+  if (use_interrupt_xfer)
     rv = usb_interrupt_read(udev, ep, usbbuf, maxsize, 10000);
   else
     rv = usb_bulk_read(udev, ep, usbbuf, maxsize, 10000);
@@ -408,6 +811,7 @@
 		usb_strerror());
       return -1;
     }
+#endif  /* USE_LIBUSB_1_0 */
 
   buflen = rv;
   bufptr = 0;
@@ -417,11 +821,11 @@
 
 static int usbdev_recv(union filedescriptor *fd, unsigned char *buf, size_t nbytes)
 {
-  usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
+  void *handle = fd->usb.handle;
   int i, amnt;
   unsigned char * p = buf;
 
-  if (udev == NULL)
+  if (handle == NULL)
     return -1;
 
   for (i = 0; nbytes > 0;)
@@ -428,7 +832,7 @@
     {
       if (buflen <= bufptr)
 	{
-	  if (usb_fill_buf(udev, fd->usb.max_xfer, fd->usb.rep, fd->usb.use_interrupt_xfer) < 0)
+	  if (usb_fill_buf(handle, fd->usb.max_xfer, fd->usb.rep, fd->usb.use_interrupt_xfer) < 0)
 	    return -1;
 	}
       amnt = buflen - bufptr > nbytes? nbytes: buflen - bufptr;
@@ -472,7 +876,12 @@
  */
 static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_t nbytes)
 {
+#ifdef USE_LIBUSB_1_0
+  libusb_device_handle *udev = (libusb_device_handle *)fd->usb.handle;
+  int errcode;
+#else
   usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
+#endif
   int rv, n;
   int i;
   unsigned char * p = buf;
@@ -483,8 +892,14 @@
   /* If there's an event EP, and it has data pending, return it first. */
   if (fd->usb.eep != 0)
   {
+#ifdef USE_LIBUSB_1_0
+      rv = 0;
+      errcode = libusb_bulk_transfer(udev, fd->usb.eep, usbbuf,
+                         fd->usb.max_xfer, &rv, 1);
+#else
       rv = usb_bulk_read(udev, fd->usb.eep, usbbuf,
                          fd->usb.max_xfer, 1);
+#endif
       if (rv > 4)
       {
 	  memcpy(buf, usbbuf, rv);
@@ -502,7 +917,23 @@
   n = 0;
   do
     {
+#ifdef USE_LIBUSB_1_0
+      rv = 0;
       if (fd->usb.use_interrupt_xfer)
+        errcode = libusb_interrupt_transfer(udev, fd->usb.rep, usbbuf,
+               fd->usb.max_xfer, &rv, 10000);
+      else
+        errcode = libusb_bulk_transfer(udev, fd->usb.rep, usbbuf,
+               fd->usb.max_xfer, &rv, 10000);
+      if (errcode < LIBUSB_SUCCESS)
+      {
+        avrdude_message(MSG_NOTICE2, "%s: usbdev_recv_frame(): usb_%s_read(): %s\n",
+          progname, (fd->usb.use_interrupt_xfer? "interrupt": "bulk"),
+          libusb_strerror(errcode));
+        return -1;
+      }
+#else
+      if (fd->usb.use_interrupt_xfer)
 	rv = usb_interrupt_read(udev, fd->usb.rep, usbbuf,
 				fd->usb.max_xfer, 10000);
       else
@@ -515,7 +946,7 @@
 		    usb_strerror());
 	  return -1;
 	}
-
+#endif  /* USE_LIBUSB_1_0 */
       if (rv <= nbytes)
 	{
 	  memcpy (buf, usbbuf, rv);
@@ -534,7 +965,7 @@
 /*
  this ends when the buffer is completly filled (nbytes=0) or was too small (nbytes< 0)
  or a short packet is found.
- however we cannot say for nbytes=0 that there was really a packet completed, 
+ however we cannot say for nbytes=0 that there was really a packet completed,
  we had to check the last rv value than for a short packet,
  but what happens if the packet does not end with a short packet?
  and what if the buffer is filled without the packet was completed?
@@ -612,4 +1043,4 @@
   .flags = SERDEV_FL_NONE,
 };
 
-#endif  /* HAVE_LIBUSB */
+#endif  /* HAVE_LIBUSB || HAVE_LIBUSB_1_0 */

@mcuee
Copy link
Collaborator

mcuee commented Apr 9, 2023

From the direction given by @dl8dtl in the following issue, avrdude will probably continue using libusb-0.1 API in the foreseable future. The main advantage of libusb-1.0 vs libusb-0.1 API is the support of asynchronous API. But it may not bring too much speed improvement for avrdude. And then the above patch does not use asynchronous API at all.

@mcuee
Copy link
Collaborator

mcuee commented Jun 2, 2023

I will close this one for now.

@mcuee mcuee closed this as completed Jun 2, 2023
@mcuee mcuee closed this as not planned Won't fix, can't repro, duplicate, stale Jun 2, 2023
@avrdudes avrdudes locked and limited conversation to collaborators Jun 24, 2023
@mcuee mcuee converted this issue into discussion #1436 Jun 24, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants