PrusaSlicer-NonPlainar/src/avrdude/usb_libusb.c
bubnikv 0558b53493 WIP: Moved sources int src/, separated most of the source code from Perl.
The XS was left only for the unit / integration tests, and it links
libslic3r only. No wxWidgets are allowed to be used from Perl starting
from now.
2018-09-19 11:02:24 +02:00

616 lines
17 KiB
C

/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2005,2006 Joerg Wunsch
* Copyright (C) 2006 David Moore
*
* 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$ */
/*
* USB interface via libusb for avrdude.
*/
#include "ac_cfg.h"
#if defined(HAVE_LIBUSB)
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#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
#include "avrdude.h"
#include "libavrdude.h"
#include "usbdevs.h"
#if defined(WIN32NATIVE)
/* someone has defined "interface" to "struct" in Cygwin */
# undef interface
#endif
static char usbbuf[USBDEV_MAX_XFER_3];
static int buflen = -1, bufptr;
static int usb_interface;
/*
* 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;
char *serno, *cp2;
int i;
int iface;
size_t x;
/*
* 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;
usb_init();
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 == pinfo.usbinfo.vid &&
dev->descriptor.idProduct == pinfo.usbinfo.pid)
{
udev = usb_open(dev);
if (udev)
{
/* yeah, we found something */
if (usb_get_string_simple(udev,
dev->descriptor.iSerialNumber,
string, sizeof(string)) < 0)
{
avrdude_message(MSG_INFO, "%s: usb_open(): cannot read serial number \"%s\"\n",
progname, usb_strerror());
/*
* 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)
return -1; /* no chance */
else
strcpy(string, "[unknown]");
}
if (usb_get_string_simple(udev,
dev->descriptor.iProduct,
product, sizeof(product)) < 0)
{
avrdude_message(MSG_INFO, "%s: usb_open(): cannot read product name \"%s\"\n",
progname, usb_strerror());
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);
usb_close(udev);
continue;
}
}
if (dev->config == NULL)
{
avrdude_message(MSG_INFO, "%s: usbdev_open(): USB device has no configuration\n",
progname);
goto trynext;
}
if (usb_set_configuration(udev, dev->config[0].bConfigurationValue))
{
avrdude_message(MSG_INFO, "%s: usbdev_open(): WARNING: failed to set configuration %d: %s\n",
progname, dev->config[0].bConfigurationValue,
usb_strerror());
/* let's hope it has already been configured */
// goto trynext;
}
for (iface = 0; iface < dev->config[0].bNumInterfaces; iface++)
{
usb_interface = dev->config[0].interface[iface].altsetting[0].bInterfaceNumber;
#ifdef LIBUSB_HAS_GET_DRIVER_NP
/*
* 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)usb_detach_kernel_driver_np(udev, usb_interface);
#endif
if (usb_claim_interface(udev, usb_interface))
{
avrdude_message(MSG_INFO, "%s: usbdev_open(): error claiming interface %d: %s\n",
progname, usb_interface, usb_strerror());
}
else
{
if (pinfo.usbinfo.flags & PINFO_FL_USEHID)
{
/* only consider an interface that is of class HID */
if (dev->config[0].interface[iface].altsetting[0].bInterfaceClass !=
USB_CLASS_HID)
continue;
fd->usb.use_interrupt_xfer = 1;
}
break;
}
}
if (iface == dev->config[0].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 < dev->config[0].interface[iface].altsetting[0].bNumEndpoints; i++)
{
int possible_ep = dev->config[0].interface[iface].altsetting[0].
endpoint[i].bEndpointAddress;
if ((possible_ep & USB_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 < dev->config[0].interface[iface].altsetting[0].bNumEndpoints; i++)
{
if ((dev->config[0].interface[iface].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.rep ||
dev->config[0].interface[iface].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.wep) &&
dev->config[0].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,
dev->config[0].interface[iface].altsetting[0].endpoint[i].wMaxPacketSize,
dev->config[0].interface[iface].altsetting[0].endpoint[i].bEndpointAddress);
fd->usb.max_xfer = dev->config[0].interface[iface].altsetting[0].endpoint[i].wMaxPacketSize;
}
}
if (pinfo.usbinfo.flags & PINFO_FL_USEHID)
{
if (usb_control_msg(udev, 0x21, 0x0a /* SET_IDLE */, 0, 0, NULL, 0, 100) < 0)
avrdude_message(MSG_INFO, "%s: usbdev_open(): SET_IDLE failed\n", progname);
}
return 0;
trynext:
usb_close(udev);
}
else
avrdude_message(MSG_INFO, "%s: usbdev_open(): cannot open device: %s\n",
progname, usb_strerror());
}
}
}
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;
}
static void usbdev_close(union filedescriptor *fd)
{
usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
if (udev == NULL)
return;
(void)usb_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.
*/
usb_reset(udev);
#endif
usb_close(udev);
}
static int usbdev_send(union filedescriptor *fd, const unsigned char *bp, size_t mlen)
{
usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
int rv;
int i = mlen;
const unsigned char * p = bp;
int tx_size;
if (udev == NULL)
return -1;
/*
* Split the frame into multiple packets. It's important to make
* sure we finish with a short packet, or else the device won't know
* the frame is finished. For example, if we need to send 64 bytes,
* we must send a packet of length 64 followed by a packet of length
* 0.
*/
do {
tx_size = (mlen < fd->usb.max_xfer)? mlen: fd->usb.max_xfer;
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);
if (rv != tx_size)
{
avrdude_message(MSG_INFO, "%s: usbdev_send(): wrote %d out of %d bytes, err = %s\n",
progname, rv, tx_size, usb_strerror());
return -1;
}
bp += tx_size;
mlen -= tx_size;
} while (mlen > 0);
if (verbose > 3)
{
avrdude_message(MSG_TRACE, "%s: Sent: ", progname);
while (i) {
unsigned char c = *p;
if (isprint(c)) {
avrdude_message(MSG_TRACE, "%c ", c);
}
else {
avrdude_message(MSG_TRACE, ". ");
}
avrdude_message(MSG_TRACE, "[%02x] ", c);
p++;
i--;
}
avrdude_message(MSG_TRACE, "\n");
}
return 0;
}
/*
* As calls to usb_bulk_read() result in exactly one USB request, we
* have to buffer the read results ourselves, so the single-char read
* requests performed by the upper layers will be handled. In order
* to do this, we maintain a private buffer of what we've got so far,
* and transparently issue another USB read request if the buffer is
* empty and more data are requested.
*/
static int
usb_fill_buf(usb_dev_handle *udev, int maxsize, int ep, int use_interrupt_xfer)
{
int rv;
if (use_interrupt_xfer)
rv = usb_interrupt_read(udev, ep, usbbuf, maxsize, 10000);
else
rv = usb_bulk_read(udev, ep, usbbuf, maxsize, 10000);
if (rv < 0)
{
avrdude_message(MSG_NOTICE2, "%s: usb_fill_buf(): usb_%s_read() error %s\n",
progname, (use_interrupt_xfer? "interrupt": "bulk"),
usb_strerror());
return -1;
}
buflen = rv;
bufptr = 0;
return 0;
}
static int usbdev_recv(union filedescriptor *fd, unsigned char *buf, size_t nbytes)
{
usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
int i, amnt;
unsigned char * p = buf;
if (udev == NULL)
return -1;
for (i = 0; nbytes > 0;)
{
if (buflen <= bufptr)
{
if (usb_fill_buf(udev, fd->usb.max_xfer, fd->usb.rep, fd->usb.use_interrupt_xfer) < 0)
return -1;
}
amnt = buflen - bufptr > nbytes? nbytes: buflen - bufptr;
memcpy(buf + i, usbbuf + bufptr, amnt);
bufptr += amnt;
nbytes -= amnt;
i += amnt;
}
if (verbose > 4)
{
avrdude_message(MSG_TRACE2, "%s: Recv: ", progname);
while (i) {
unsigned char c = *p;
if (isprint(c)) {
avrdude_message(MSG_TRACE2, "%c ", c);
}
else {
avrdude_message(MSG_TRACE2, ". ");
}
avrdude_message(MSG_TRACE2, "[%02x] ", c);
p++;
i--;
}
avrdude_message(MSG_TRACE2, "\n");
}
return 0;
}
/*
* This version of recv keeps reading packets until we receive a short
* packet. Then, the entire frame is assembled and returned to the
* user. The length will be unknown in advance, so we return the
* length as the return value of this function, or -1 in case of an
* error.
*
* This is used for the AVRISP mkII device.
*/
static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_t nbytes)
{
usb_dev_handle *udev = (usb_dev_handle *)fd->usb.handle;
int rv, n;
int i;
unsigned char * p = buf;
if (udev == NULL)
return -1;
/* If there's an event EP, and it has data pending, return it first. */
if (fd->usb.eep != 0)
{
rv = usb_bulk_read(udev, fd->usb.eep, usbbuf,
fd->usb.max_xfer, 1);
if (rv > 4)
{
memcpy(buf, usbbuf, rv);
n = rv;
n |= USB_RECV_FLAG_EVENT;
goto printout;
}
else if (rv > 0)
{
avrdude_message(MSG_INFO, "Short event len = %d, ignored.\n", rv);
/* fallthrough */
}
}
n = 0;
do
{
if (fd->usb.use_interrupt_xfer)
rv = usb_interrupt_read(udev, fd->usb.rep, usbbuf,
fd->usb.max_xfer, 10000);
else
rv = usb_bulk_read(udev, fd->usb.rep, usbbuf,
fd->usb.max_xfer, 10000);
if (rv < 0)
{
avrdude_message(MSG_NOTICE2, "%s: usbdev_recv_frame(): usb_%s_read(): %s\n",
progname, (fd->usb.use_interrupt_xfer? "interrupt": "bulk"),
usb_strerror());
return -1;
}
if (rv <= nbytes)
{
memcpy (buf, usbbuf, rv);
buf += rv;
}
else
{
return -1; // buffer overflow
}
n += rv;
nbytes -= rv;
}
while (nbytes > 0 && rv == fd->usb.max_xfer);
/*
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,
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?
preconditions:
expected packet is not a multiple of usb.max_xfer. (prevents further waiting)
expected packet is shorter than the provided buffer (so it cannot filled completely)
or buffer size is not a multiple of usb.max_xfer. (so it can clearly detected if the buffer was overflown.)
*/
printout:
if (verbose > 3)
{
i = n & USB_RECV_LENGTH_MASK;
avrdude_message(MSG_TRACE, "%s: Recv: ", progname);
while (i) {
unsigned char c = *p;
if (isprint(c)) {
avrdude_message(MSG_TRACE, "%c ", c);
}
else {
avrdude_message(MSG_TRACE, ". ");
}
avrdude_message(MSG_TRACE, "[%02x] ", c);
p++;
i--;
}
avrdude_message(MSG_TRACE, "\n");
}
return n;
}
static int usbdev_drain(union filedescriptor *fd, int display)
{
/*
* There is not much point in trying to flush any data
* on an USB endpoint, as the endpoint is supposed to
* start afresh after being configured from the host.
*
* As trying to flush the data here caused strange effects
* in some situations (see
* https://savannah.nongnu.org/bugs/index.php?43268 )
* better avoid it.
*/
return 0;
}
/*
* Device descriptor for the JTAG ICE mkII.
*/
struct serial_device usb_serdev =
{
.open = usbdev_open,
.close = usbdev_close,
.send = usbdev_send,
.recv = usbdev_recv,
.drain = usbdev_drain,
.flags = SERDEV_FL_NONE,
};
/*
* Device descriptor for the AVRISP mkII.
*/
struct serial_device usb_serdev_frame =
{
.open = usbdev_open,
.close = usbdev_close,
.send = usbdev_send,
.recv = usbdev_recv_frame,
.drain = usbdev_drain,
.flags = SERDEV_FL_NONE,
};
#endif /* HAVE_LIBUSB */