2005-06-19 21:38:03 +00:00
|
|
|
/*
|
|
|
|
* avrdude - A Downloader/Uploader for AVR device programmers
|
2006-01-12 23:13:50 +00:00
|
|
|
* Copyright (C) 2005,2006 Joerg Wunsch
|
2006-01-12 23:24:35 +00:00
|
|
|
* Copyright (C) 2006 David Moore
|
2005-06-19 21:38:03 +00:00
|
|
|
*
|
|
|
|
* 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$ */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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>
|
|
|
|
|
|
|
|
#include <usb.h>
|
|
|
|
|
|
|
|
#include "serial.h"
|
2006-01-12 23:13:50 +00:00
|
|
|
#include "usbdevs.h"
|
2005-06-19 21:38:03 +00:00
|
|
|
|
|
|
|
extern char *progname;
|
|
|
|
extern int verbose;
|
|
|
|
|
2006-01-12 23:13:50 +00:00
|
|
|
static char usbbuf[USBDEV_MAX_XFER];
|
2005-06-19 21:38:03 +00:00
|
|
|
static int buflen = -1, bufptr;
|
|
|
|
|
2005-09-26 12:19:01 +00:00
|
|
|
static int usb_interface;
|
|
|
|
|
2006-01-12 23:13:50 +00:00
|
|
|
/*
|
|
|
|
* The "baud" parameter is meaningless for USB devices, so we reuse it
|
|
|
|
* to pass the desired USB device ID.
|
|
|
|
*/
|
2005-06-19 21:38:03 +00:00
|
|
|
static int usbdev_open(char * port, long baud)
|
|
|
|
{
|
|
|
|
char string[256];
|
2006-01-12 23:13:50 +00:00
|
|
|
char product[256];
|
2005-06-19 21:38:03 +00:00
|
|
|
struct usb_bus *bus;
|
|
|
|
struct usb_device *dev;
|
|
|
|
usb_dev_handle *udev;
|
|
|
|
char *serno, *cp2;
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: usbdev_open(): invalid serial number \"%s\"\n",
|
|
|
|
progname, serno);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
usb_init();
|
|
|
|
|
|
|
|
usb_find_busses();
|
|
|
|
usb_find_devices();
|
|
|
|
|
2005-09-26 12:19:01 +00:00
|
|
|
for (bus = usb_get_busses(); bus; bus = bus->next)
|
2005-06-19 21:38:03 +00:00
|
|
|
{
|
|
|
|
for (dev = bus->devices; dev; dev = dev->next)
|
|
|
|
{
|
|
|
|
udev = usb_open(dev);
|
|
|
|
if (udev)
|
|
|
|
{
|
|
|
|
if (dev->descriptor.idVendor == USB_VENDOR_ATMEL &&
|
2006-01-12 23:13:50 +00:00
|
|
|
dev->descriptor.idProduct == (unsigned short)baud)
|
2005-06-19 21:38:03 +00:00
|
|
|
{
|
|
|
|
/* yeah, we found something */
|
|
|
|
if (usb_get_string_simple(udev,
|
|
|
|
dev->descriptor.iSerialNumber,
|
|
|
|
string, sizeof(string)) < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: usb_open(): cannot read serial number \"%s\"\n",
|
|
|
|
progname, usb_strerror());
|
2005-07-25 19:52:20 +00:00
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
exit(1); /* no chance */
|
|
|
|
else
|
|
|
|
strcpy(string, "[unknown]");
|
2005-06-19 21:38:03 +00:00
|
|
|
}
|
|
|
|
|
2006-01-12 23:13:50 +00:00
|
|
|
if (usb_get_string_simple(udev,
|
|
|
|
dev->descriptor.iProduct,
|
|
|
|
product, sizeof(product)) < 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: usb_open(): cannot read product name \"%s\"\n",
|
|
|
|
progname, usb_strerror());
|
|
|
|
strcpy(product, "[unnamed product]");
|
|
|
|
}
|
|
|
|
|
2005-06-19 21:38:03 +00:00
|
|
|
if (verbose)
|
|
|
|
fprintf(stderr,
|
2006-01-12 23:13:50 +00:00
|
|
|
"%s: usbdev_open(): Found %s, serno: %s\n",
|
|
|
|
progname, product, string);
|
2005-06-19 21:38:03 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
if (verbose > 2)
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: usbdev_open(): serial number doesn't match\n",
|
|
|
|
progname);
|
|
|
|
usb_close(udev);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-26 12:19:01 +00:00
|
|
|
if (dev->config == NULL)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: usbdev_open(): USB device has no configuration\n",
|
|
|
|
progname);
|
|
|
|
goto trynext;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (usb_set_configuration(udev, dev->config[0].bConfigurationValue))
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: usbdev_open(): error setting configuration %d: %s\n",
|
|
|
|
progname, dev->config[0].bConfigurationValue,
|
|
|
|
usb_strerror());
|
|
|
|
goto trynext;
|
|
|
|
}
|
|
|
|
|
|
|
|
usb_interface = dev->config[0].interface[0].altsetting[0].bInterfaceNumber;
|
|
|
|
if (usb_claim_interface(udev, usb_interface))
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: usbdev_open(): error claiming interface %d: %s\n",
|
|
|
|
progname, usb_interface, usb_strerror());
|
|
|
|
goto trynext;
|
|
|
|
}
|
|
|
|
|
2005-06-19 21:38:03 +00:00
|
|
|
return (int)udev;
|
|
|
|
}
|
2005-09-26 12:19:01 +00:00
|
|
|
trynext:
|
2005-06-19 21:38:03 +00:00
|
|
|
usb_close(udev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "%s: usbdev_open(): did not find any%s USB device \"%s\"\n",
|
|
|
|
progname, serno? " (matching)": "", port);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void usbdev_close(int fd)
|
|
|
|
{
|
|
|
|
usb_dev_handle *udev = (usb_dev_handle *)fd;
|
|
|
|
|
2005-09-26 12:19:01 +00:00
|
|
|
(void)usb_release_interface(udev, usb_interface);
|
2006-01-12 23:13:50 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Without this reset, the AVRISP mkII seems to stall the second
|
|
|
|
* time we try to connect to it.
|
|
|
|
*/
|
|
|
|
usb_reset(udev);
|
|
|
|
|
2005-06-19 21:38:03 +00:00
|
|
|
usb_close(udev);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-30 04:44:29 +00:00
|
|
|
static int usbdev_send(int fd, unsigned char *bp, size_t mlen)
|
2005-06-19 21:38:03 +00:00
|
|
|
{
|
|
|
|
usb_dev_handle *udev = (usb_dev_handle *)fd;
|
2005-09-26 12:19:01 +00:00
|
|
|
size_t rv;
|
2006-01-12 23:13:50 +00:00
|
|
|
int i = mlen;
|
|
|
|
unsigned char * p = bp;
|
|
|
|
int tx_size;
|
2005-06-19 21:38:03 +00:00
|
|
|
|
2006-01-12 23:13:50 +00:00
|
|
|
/*
|
|
|
|
* 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 < USBDEV_MAX_XFER)? mlen: USBDEV_MAX_XFER;
|
|
|
|
rv = usb_bulk_write(udev, USBDEV_BULK_EP_WRITE, (char *)bp, tx_size, 5000);
|
|
|
|
if (rv != tx_size)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "%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 (tx_size == USBDEV_MAX_XFER);
|
|
|
|
|
|
|
|
if (verbose > 3)
|
2005-09-26 12:19:01 +00:00
|
|
|
{
|
2006-01-12 23:13:50 +00:00
|
|
|
fprintf(stderr, "%s: Sent: ", progname);
|
|
|
|
|
|
|
|
while (i) {
|
|
|
|
unsigned char c = *p;
|
|
|
|
if (isprint(c)) {
|
|
|
|
fprintf(stderr, "%c ", c);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fprintf(stderr, ". ");
|
|
|
|
}
|
|
|
|
fprintf(stderr, "[%02x] ", c);
|
|
|
|
|
|
|
|
p++;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
2005-09-26 12:19:01 +00:00
|
|
|
}
|
|
|
|
return 0;
|
2005-06-19 21:38:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 rv;
|
|
|
|
|
2006-01-12 23:13:50 +00:00
|
|
|
rv = usb_bulk_read(udev, USBDEV_BULK_EP_READ, usbbuf, USBDEV_MAX_XFER, 5000);
|
2005-06-19 21:38:03 +00:00
|
|
|
if (rv < 0)
|
|
|
|
{
|
|
|
|
if (verbose > 1)
|
|
|
|
fprintf(stderr, "%s: usb_fill_buf(): usb_bulk_read() error %s\n",
|
|
|
|
progname, usb_strerror());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
buflen = rv;
|
|
|
|
bufptr = 0;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-08-30 04:44:29 +00:00
|
|
|
static int usbdev_recv(int fd, unsigned char *buf, size_t nbytes)
|
2005-06-19 21:38:03 +00:00
|
|
|
{
|
|
|
|
usb_dev_handle *udev = (usb_dev_handle *)fd;
|
|
|
|
int i, amnt;
|
2005-08-30 04:44:29 +00:00
|
|
|
unsigned char * p = buf;
|
2005-06-19 21:38:03 +00:00
|
|
|
|
|
|
|
for (i = 0; nbytes > 0;)
|
|
|
|
{
|
|
|
|
if (buflen <= bufptr)
|
|
|
|
{
|
|
|
|
if (usb_fill_buf(udev) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
amnt = buflen - bufptr > nbytes? nbytes: buflen - bufptr;
|
|
|
|
memcpy(buf + i, usbbuf + bufptr, amnt);
|
|
|
|
bufptr += amnt;
|
|
|
|
nbytes -= amnt;
|
|
|
|
i += amnt;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verbose > 3)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "%s: Recv: ", progname);
|
|
|
|
|
|
|
|
while (i) {
|
|
|
|
unsigned char c = *p;
|
|
|
|
if (isprint(c)) {
|
|
|
|
fprintf(stderr, "%c ", c);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fprintf(stderr, ". ");
|
|
|
|
}
|
|
|
|
fprintf(stderr, "[%02x] ", c);
|
|
|
|
|
|
|
|
p++;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-01-12 23:13:50 +00:00
|
|
|
/*
|
|
|
|
* 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(int fd, unsigned char *buf, size_t nbytes)
|
|
|
|
{
|
|
|
|
usb_dev_handle *udev = (usb_dev_handle *)fd;
|
|
|
|
int rv, n;
|
|
|
|
int i;
|
|
|
|
unsigned char * p = buf;
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
rv = usb_bulk_read(udev, USBDEV_BULK_EP_READ, usbbuf,
|
|
|
|
USBDEV_MAX_XFER, 10000);
|
|
|
|
if (rv < 0)
|
|
|
|
{
|
|
|
|
if (verbose > 1)
|
|
|
|
fprintf(stderr, "%s: usbdev_recv_frame(): usb_bulk_read(): %s\n",
|
|
|
|
progname, usb_strerror());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rv <= nbytes)
|
|
|
|
{
|
|
|
|
memcpy (buf, usbbuf, rv);
|
|
|
|
buf += rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
n += rv;
|
|
|
|
nbytes -= rv;
|
|
|
|
}
|
|
|
|
while (rv == USBDEV_MAX_XFER);
|
|
|
|
|
|
|
|
if (nbytes < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (verbose > 3)
|
|
|
|
{
|
|
|
|
i = n;
|
|
|
|
fprintf(stderr, "%s: Recv: ", progname);
|
|
|
|
|
|
|
|
while (i) {
|
|
|
|
unsigned char c = *p;
|
|
|
|
if (isprint(c)) {
|
|
|
|
fprintf(stderr, "%c ", c);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
fprintf(stderr, ". ");
|
|
|
|
}
|
|
|
|
fprintf(stderr, "[%02x] ", c);
|
|
|
|
|
|
|
|
p++;
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
2005-06-19 21:38:03 +00:00
|
|
|
|
|
|
|
static int usbdev_drain(int fd, int display)
|
|
|
|
{
|
2005-09-16 15:01:52 +00:00
|
|
|
usb_dev_handle *udev = (usb_dev_handle *)fd;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
do {
|
2006-01-12 23:13:50 +00:00
|
|
|
rv = usb_bulk_read(udev, USBDEV_BULK_EP_READ, usbbuf, USBDEV_MAX_XFER, 100);
|
2005-09-16 15:01:52 +00:00
|
|
|
if (rv > 0 && verbose >= 4)
|
|
|
|
fprintf(stderr, "%s: usbdev_drain(): flushed %d characters\n",
|
|
|
|
progname, rv);
|
|
|
|
} while (rv > 0);
|
|
|
|
|
2005-06-19 21:38:03 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-01-12 23:13:50 +00:00
|
|
|
/*
|
|
|
|
* Device descriptor for the JTAG ICE mkII.
|
|
|
|
*/
|
2005-06-19 21:38:03 +00:00
|
|
|
struct serial_device usb_serdev =
|
|
|
|
{
|
|
|
|
.open = usbdev_open,
|
|
|
|
.close = usbdev_close,
|
|
|
|
.send = usbdev_send,
|
|
|
|
.recv = usbdev_recv,
|
|
|
|
.drain = usbdev_drain,
|
2006-10-27 08:45:47 +00:00
|
|
|
.flags = SERDEV_FL_NONE,
|
2005-06-19 21:38:03 +00:00
|
|
|
};
|
|
|
|
|
2006-01-12 23:13:50 +00:00
|
|
|
/*
|
|
|
|
* 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,
|
2006-10-27 08:45:47 +00:00
|
|
|
.flags = SERDEV_FL_NONE,
|
2006-01-12 23:13:50 +00:00
|
|
|
};
|
|
|
|
|
2005-06-19 21:38:03 +00:00
|
|
|
#endif /* HAVE_LIBUSB */
|