Implement and document a libusb-based USB transport for the JTAG ICE

mkII.

The serial transport methods have been moved out into a record of
function pointers for that purpose, defaulting to the actual serial
connection that natively applies to the hosting system.  Iff inside
the JTAG ICE mkII handler a port name starting with "usb" has been
detected, the record of function pointers is switched to USB.
Optionally, a serial number might be specified, so only the JTAG ICE
mkII matching the given serial number will be opened.  The match is
done right-to-left, so only the least significant bytes of the serial
number need to be given.

In order to make the change as least intrusive to existing drivers as
possible, the entire naming scheme of the serial_foo() function entry
points has been maintained as access macros that encapsulate these
into the respective indirect function calls via serdev->foo().


git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@478 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
Joerg Wunsch 2005-06-19 21:38:03 +00:00
parent fcd9cf2e09
commit f5882fc781
10 changed files with 430 additions and 47 deletions

View File

@ -1,3 +1,16 @@
2005-06-19 Joerg Wunsch <j@uriah.heep.sax.de>
* Makefile.am: Implement libusb-base USB transport for the
JTAG ICE mkII.
* configure.ac: ditto.
* jtagmkII.c: ditto.
* ser_posix.c: ditto.
* ser_win32.c: ditto.
* serial.h: ditto.
* usb_libusb.c: ditto (New file).
* avrdude.1: document the USB transport.
* doc/avrdude.texi: ditto.
2005-06-15 Joerg Wunsch <j@uriah.heep.sax.de> 2005-06-15 Joerg Wunsch <j@uriah.heep.sax.de>
* avrdude.conf.in: The AT90CAN128 has AllowFullPageBitstream = no. * avrdude.conf.in: The AT90CAN128 has AllowFullPageBitstream = no.

View File

@ -94,7 +94,8 @@ avrdude_SOURCES = \
stk500v2.h \ stk500v2.h \
stk500v2_private.h \ stk500v2_private.h \
term.c \ term.c \
term.h term.h \
usb_libusb.c
man_MANS = avrdude.1 man_MANS = avrdude.1

View File

@ -303,6 +303,23 @@ serial port, the
.Pa /dev/cuaa0 .Pa /dev/cuaa0
port is the default. If you need to use a different parallel or port is the default. If you need to use a different parallel or
serial port, use this option to specify the alternate port name. serial port, use this option to specify the alternate port name.
.Pp
For the JTAG ICE mkII, if
.Nm
has been configured with libusb support,
.Ar port
can alternatively be specified as
.Ar usb Ns Op \&: Ns Ar serialno .
This will cause
.Nm
to search a JTAG ICE mkII on USB.
If
.Ar serialno
is also specified, it will be matched against the serial number read
from any JTAG ICE mkII found on USB.
The match is done after stripping any existing colons from the given
serial number, and right-to-left, so only the least significant bytes
from the serial number need to be given.
.It Fl q .It Fl q
Disable (or quell) output of the progress bar while reading or writing Disable (or quell) output of the progress bar while reading or writing
to the device. to the device.

View File

@ -44,6 +44,7 @@ AM_PROG_LEX
AC_CHECK_LIB([termcap], [tputs]) AC_CHECK_LIB([termcap], [tputs])
AC_CHECK_LIB([ncurses], [tputs]) AC_CHECK_LIB([ncurses], [tputs])
AC_CHECK_LIB([readline], [readline]) AC_CHECK_LIB([readline], [readline])
AC_CHECK_LIB([usb], [usb_open])
# Checks for header files. # Checks for header files.
AC_HEADER_STDC AC_HEADER_STDC

View File

@ -488,6 +488,15 @@ used. See Appendix A, Platform Dependent Information, to find out the
default port names for your platform. If you need to use a different default port names for your platform. If you need to use a different
parallel or serial port, use this option to specify the alternate port name. parallel or serial port, use this option to specify the alternate port name.
For the JTAG ICE mkII, if AVRDUDE has been built with libusb support,
@var{port} may alternatively be specified as
@var{usb}[:@var{serialno}]. In that case, the JTAG ICE mkII will be
looked up on USB. If @var{serialno} is also specified, it will be
matched against the serial number read from any JTAG ICE mkII found on
USB. The match is done after stripping any existing colons from the
given serial number, and right-to-left, so only the least significant
bytes from the serial number need to be given.
@item -q @item -q
Disable (or quell) output of the progress bar while reading or writing Disable (or quell) output of the progress bar while reading or writing
to the device. to the device.
@ -594,6 +603,7 @@ should not be used.
@end table @end table
@page
@c @c
@c Node @c Node
@c @c
@ -642,6 +652,7 @@ avrdude done. Thank you.
@end cartouche @end cartouche
@end example @end example
@page
@noindent @noindent
Upload the flash memory from the ATmega128 connected to the STK500 Upload the flash memory from the ATmega128 connected to the STK500
programmer and save it in raw binary format in the file named programmer and save it in raw binary format in the file named
@ -670,6 +681,7 @@ avrdude done. Thank you.
@end cartouche @end cartouche
@end example @end example
@page
@noindent @noindent
Using the default programmer, download the file @code{diag.hex} to Using the default programmer, download the file @code{diag.hex} to
flash, @code{eeprom.hex} to EEPROM, and set the Extended, High, and Low flash, @code{eeprom.hex} to EEPROM, and set the Extended, High, and Low
@ -718,6 +730,29 @@ avrdude done. Thank you.
@end cartouche @end cartouche
@end example @end example
@page
@noindent
Connect to the JTAG ICE mkII which serial number ends up in 1C37 via
USB, and enter terminal mode:
@example
@cartouche
% avrdude -c jtag2 -p m649 -P usb:1c:37 -t
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.03s
avrdude: Device signature = 0x1e9603
[ ... terminal mode output skipped for brevity ... ]
avrdude done. Thank you.
@end cartouche
@end example
@c @c

View File

@ -1047,6 +1047,15 @@ static int jtagmkII_open(PROGRAMMER * pgm, char * port)
if (verbose >= 2) if (verbose >= 2)
fprintf(stderr, "%s: jtagmkII_open()\n", progname); fprintf(stderr, "%s: jtagmkII_open()\n", progname);
#if defined(HAVE_LIBUSB)
/*
* If the port name starts with "usb", divert the serial routines
* to the USB ones.
*/
if (strncmp(port, "usb", 3) == 0)
serdev = &usb_serdev;
#endif
strcpy(pgm->port, port); strcpy(pgm->port, port);
/* /*
* The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon

View File

@ -38,6 +38,8 @@
#include <termios.h> #include <termios.h>
#include <unistd.h> #include <unistd.h>
#include "serial.h"
extern char *progname; extern char *progname;
extern int verbose; extern int verbose;
@ -78,7 +80,7 @@ static speed_t serial_baud_lookup(long baud)
exit(1); exit(1);
} }
int serial_setspeed(int fd, long baud) static int ser_setspeed(int fd, long baud)
{ {
int rc; int rc;
struct termios termios; struct termios termios;
@ -92,7 +94,7 @@ int serial_setspeed(int fd, long baud)
*/ */
rc = tcgetattr(fd, &termios); rc = tcgetattr(fd, &termios);
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "%s: serial_setspeed(): tcgetattr() failed, %s", fprintf(stderr, "%s: ser_setspeed(): tcgetattr() failed, %s",
progname, strerror(errno)); progname, strerror(errno));
return -errno; return -errno;
} }
@ -110,7 +112,7 @@ int serial_setspeed(int fd, long baud)
rc = tcsetattr(fd, TCSANOW, &termios); rc = tcsetattr(fd, TCSANOW, &termios);
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "%s: serial_setspeed(): tcsetattr() failed, %s", fprintf(stderr, "%s: ser_setspeed(): tcsetattr() failed, %s",
progname, strerror(errno)); progname, strerror(errno));
return -errno; return -errno;
} }
@ -127,7 +129,7 @@ int serial_setspeed(int fd, long baud)
} }
int serial_open(char * port, int baud) static int ser_open(char * port, long baud)
{ {
int rc; int rc;
int fd; int fd;
@ -137,7 +139,7 @@ int serial_open(char * port, int baud)
*/ */
fd = open(port, O_RDWR | O_NOCTTY /*| O_NONBLOCK*/); fd = open(port, O_RDWR | O_NOCTTY /*| O_NONBLOCK*/);
if (fd < 0) { if (fd < 0) {
fprintf(stderr, "%s: serial_open(): can't open device \"%s\": %s\n", fprintf(stderr, "%s: ser_open(): can't open device \"%s\": %s\n",
progname, port, strerror(errno)); progname, port, strerror(errno));
exit(1); exit(1);
} }
@ -145,10 +147,10 @@ int serial_open(char * port, int baud)
/* /*
* set serial line attributes * set serial line attributes
*/ */
rc = serial_setspeed(fd, baud); rc = ser_setspeed(fd, baud);
if (rc) { if (rc) {
fprintf(stderr, fprintf(stderr,
"%s: serial_open(): can't set attributes for device \"%s\"\n", "%s: ser_open(): can't set attributes for device \"%s\"\n",
progname, port); progname, port);
exit(1); exit(1);
} }
@ -157,7 +159,7 @@ int serial_open(char * port, int baud)
} }
void serial_close(int fd) static void ser_close(int fd)
{ {
/* FIXME: Should really restore the terminal to original state here. */ /* FIXME: Should really restore the terminal to original state here. */
@ -165,7 +167,7 @@ void serial_close(int fd)
} }
int serial_send(int fd, char * buf, size_t buflen) static int ser_send(int fd, char * buf, size_t buflen)
{ {
struct timeval timeout, to2; struct timeval timeout, to2;
fd_set wfds; fd_set wfds;
@ -212,7 +214,7 @@ int serial_send(int fd, char * buf, size_t buflen)
if (nfds == 0) { if (nfds == 0) {
if (verbose >= 1) if (verbose >= 1)
fprintf(stderr, fprintf(stderr,
"%s: serial_send(): programmer is not responding\n", "%s: ser_send(): programmer is not responding\n",
progname); progname);
exit(1); exit(1);
} }
@ -221,7 +223,7 @@ int serial_send(int fd, char * buf, size_t buflen)
goto reselect; goto reselect;
} }
else { else {
fprintf(stderr, "%s: serial_send(): select(): %s\n", fprintf(stderr, "%s: ser_send(): select(): %s\n",
progname, strerror(errno)); progname, strerror(errno));
exit(1); exit(1);
} }
@ -229,7 +231,7 @@ int serial_send(int fd, char * buf, size_t buflen)
rc = write(fd, p, (len > 1024) ? 1024 : len); rc = write(fd, p, (len > 1024) ? 1024 : len);
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "%s: serial_send(): write error: %s\n", fprintf(stderr, "%s: ser_send(): write error: %s\n",
progname, strerror(errno)); progname, strerror(errno));
exit(1); exit(1);
} }
@ -241,7 +243,7 @@ int serial_send(int fd, char * buf, size_t buflen)
} }
int serial_recv(int fd, char * buf, size_t buflen) static int ser_recv(int fd, char * buf, size_t buflen)
{ {
struct timeval timeout, to2; struct timeval timeout, to2;
fd_set rfds; fd_set rfds;
@ -264,19 +266,19 @@ int serial_recv(int fd, char * buf, size_t buflen)
if (nfds == 0) { if (nfds == 0) {
if (verbose > 1) if (verbose > 1)
fprintf(stderr, fprintf(stderr,
"%s: serial_recv(): programmer is not responding\n", "%s: ser_recv(): programmer is not responding\n",
progname); progname);
return -1; return -1;
} }
else if (nfds == -1) { else if (nfds == -1) {
if (errno == EINTR || errno == EAGAIN) { if (errno == EINTR || errno == EAGAIN) {
fprintf(stderr, fprintf(stderr,
"%s: serial_recv(): programmer is not responding,reselecting\n", "%s: ser_recv(): programmer is not responding,reselecting\n",
progname); progname);
goto reselect; goto reselect;
} }
else { else {
fprintf(stderr, "%s: serial_recv(): select(): %s\n", fprintf(stderr, "%s: ser_recv(): select(): %s\n",
progname, strerror(errno)); progname, strerror(errno));
exit(1); exit(1);
} }
@ -284,7 +286,7 @@ int serial_recv(int fd, char * buf, size_t buflen)
rc = read(fd, p, (buflen - len > 1024) ? 1024 : buflen - len); rc = read(fd, p, (buflen - len > 1024) ? 1024 : buflen - len);
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "%s: serial_recv(): read error: %s\n", fprintf(stderr, "%s: ser_recv(): read error: %s\n",
progname, strerror(errno)); progname, strerror(errno));
exit(1); exit(1);
} }
@ -318,7 +320,7 @@ int serial_recv(int fd, char * buf, size_t buflen)
} }
int serial_drain(int fd, int display) static int ser_drain(int fd, int display)
{ {
struct timeval timeout; struct timeval timeout;
fd_set rfds; fd_set rfds;
@ -351,7 +353,7 @@ int serial_drain(int fd, int display)
goto reselect; goto reselect;
} }
else { else {
fprintf(stderr, "%s: serial_drain(): select(): %s\n", fprintf(stderr, "%s: ser_drain(): select(): %s\n",
progname, strerror(errno)); progname, strerror(errno));
exit(1); exit(1);
} }
@ -359,7 +361,7 @@ int serial_drain(int fd, int display)
rc = read(fd, &buf, 1); rc = read(fd, &buf, 1);
if (rc < 0) { if (rc < 0) {
fprintf(stderr, "%s: serial_drain(): read error: %s\n", fprintf(stderr, "%s: ser_drain(): read error: %s\n",
progname, strerror(errno)); progname, strerror(errno));
exit(1); exit(1);
} }
@ -371,4 +373,16 @@ int serial_drain(int fd, int display)
return 0; return 0;
} }
struct serial_device serial_serdev =
{
.open = ser_open,
.setspeed = ser_setspeed,
.close = ser_close,
.send = ser_send,
.recv = ser_recv,
.drain = ser_drain,
};
struct serial_device *serdev = &serial_serdev;
#endif /* WIN32NATIVE */ #endif /* WIN32NATIVE */

View File

@ -72,7 +72,7 @@ static DWORD serial_baud_lookup(long baud)
} }
BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms static BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms
{ {
COMMTIMEOUTS ctmo; COMMTIMEOUTS ctmo;
ZeroMemory (&ctmo, sizeof(COMMTIMEOUTS)); ZeroMemory (&ctmo, sizeof(COMMTIMEOUTS));
@ -83,7 +83,7 @@ BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms
return SetCommTimeouts(hComPort, &ctmo); return SetCommTimeouts(hComPort, &ctmo);
} }
int serial_setspeed(int fd, long baud) static int ser_setspeed(int fd, long baud)
{ {
DCB dcb; DCB dcb;
HANDLE hComPort = (HANDLE)fd; HANDLE hComPort = (HANDLE)fd;
@ -105,13 +105,13 @@ int serial_setspeed(int fd, long baud)
} }
int serial_open(char * port, long baud) static int ser_open(char * port, long baud)
{ {
LPVOID lpMsgBuf; LPVOID lpMsgBuf;
HANDLE hComPort=INVALID_HANDLE_VALUE; HANDLE hComPort=INVALID_HANDLE_VALUE;
/* if (hComPort!=INVALID_HANDLE_VALUE) /* if (hComPort!=INVALID_HANDLE_VALUE)
fprintf(stderr, "%s: serial_open(): \"%s\" is already open\n", fprintf(stderr, "%s: ser_open(): \"%s\" is already open\n",
progname, port); progname, port);
*/ */
@ -129,7 +129,7 @@ int serial_open(char * port, long baud)
(LPTSTR) &lpMsgBuf, (LPTSTR) &lpMsgBuf,
0, 0,
NULL); NULL);
fprintf(stderr, "%s: serial_open(): can't open device \"%s\": %s\n", fprintf(stderr, "%s: ser_open(): can't open device \"%s\": %s\n",
progname, port, (char*)lpMsgBuf); progname, port, (char*)lpMsgBuf);
LocalFree( lpMsgBuf ); LocalFree( lpMsgBuf );
exit(1); exit(1);
@ -138,16 +138,16 @@ int serial_open(char * port, long baud)
if (!SetupComm(hComPort, W32SERBUFSIZE, W32SERBUFSIZE)) if (!SetupComm(hComPort, W32SERBUFSIZE, W32SERBUFSIZE))
{ {
CloseHandle(hComPort); CloseHandle(hComPort);
fprintf(stderr, "%s: serial_open(): can't set buffers for \"%s\"\n", fprintf(stderr, "%s: ser_open(): can't set buffers for \"%s\"\n",
progname, port); progname, port);
exit(1); exit(1);
} }
if (serial_setspeed((int)hComPort, baud) != 0) if (ser_setspeed((int)hComPort, baud) != 0)
{ {
CloseHandle(hComPort); CloseHandle(hComPort);
fprintf(stderr, "%s: serial_open(): can't set com-state for \"%s\"\n", fprintf(stderr, "%s: ser_open(): can't set com-state for \"%s\"\n",
progname, port); progname, port);
exit(1); exit(1);
} }
@ -155,7 +155,7 @@ int serial_open(char * port, long baud)
if (!serial_w32SetTimeOut(hComPort,0)) if (!serial_w32SetTimeOut(hComPort,0))
{ {
CloseHandle(hComPort); CloseHandle(hComPort);
fprintf(stderr, "%s: serial_open(): can't set initial timeout for \"%s\"\n", fprintf(stderr, "%s: ser_open(): can't set initial timeout for \"%s\"\n",
progname, port); progname, port);
exit(1); exit(1);
} }
@ -164,7 +164,7 @@ int serial_open(char * port, long baud)
} }
void serial_close(int fd) static void ser_close(int fd)
{ {
HANDLE hComPort=(HANDLE)fd; HANDLE hComPort=(HANDLE)fd;
if (hComPort != INVALID_HANDLE_VALUE) if (hComPort != INVALID_HANDLE_VALUE)
@ -174,7 +174,7 @@ void serial_close(int fd)
} }
int serial_send(int fd, char * buf, size_t buflen) static int ser_send(int fd, char * buf, size_t buflen)
{ {
size_t len = buflen; size_t len = buflen;
unsigned char c='\0'; unsigned char c='\0';
@ -183,7 +183,7 @@ int serial_send(int fd, char * buf, size_t buflen)
HANDLE hComPort=(HANDLE)fd; HANDLE hComPort=(HANDLE)fd;
if (hComPort == INVALID_HANDLE_VALUE) { if (hComPort == INVALID_HANDLE_VALUE) {
fprintf(stderr, "%s: serial_send(): port not open\n", fprintf(stderr, "%s: ser_send(): port not open\n",
progname); progname);
exit(1); exit(1);
} }
@ -213,13 +213,13 @@ int serial_send(int fd, char * buf, size_t buflen)
serial_w32SetTimeOut(hComPort,500); serial_w32SetTimeOut(hComPort,500);
if (!WriteFile (hComPort, buf, buflen, &written, NULL)) { if (!WriteFile (hComPort, buf, buflen, &written, NULL)) {
fprintf(stderr, "%s: serial_send(): write error: %s\n", fprintf(stderr, "%s: ser_send(): write error: %s\n",
progname, "sorry no info avail"); // TODO progname, "sorry no info avail"); // TODO
exit(1); exit(1);
} }
if (written != buflen) { if (written != buflen) {
fprintf(stderr, "%s: serial_send(): size/send mismatch\n", fprintf(stderr, "%s: ser_send(): size/send mismatch\n",
progname); progname);
exit(1); exit(1);
} }
@ -228,7 +228,7 @@ int serial_send(int fd, char * buf, size_t buflen)
} }
int serial_recv(int fd, char * buf, size_t buflen) static int ser_recv(int fd, char * buf, size_t buflen)
{ {
unsigned char c; unsigned char c;
char * p = buf; char * p = buf;
@ -238,7 +238,7 @@ int serial_recv(int fd, char * buf, size_t buflen)
HANDLE hComPort=(HANDLE)fd; HANDLE hComPort=(HANDLE)fd;
if (hComPort == INVALID_HANDLE_VALUE) { if (hComPort == INVALID_HANDLE_VALUE) {
fprintf(stderr, "%s: serial_read(): port not open\n", fprintf(stderr, "%s: ser_read(): port not open\n",
progname); progname);
exit(1); exit(1);
} }
@ -257,7 +257,7 @@ int serial_recv(int fd, char * buf, size_t buflen)
(LPTSTR) &lpMsgBuf, (LPTSTR) &lpMsgBuf,
0, 0,
NULL ); NULL );
fprintf(stderr, "%s: serial_recv(): read error: %s\n", fprintf(stderr, "%s: ser_recv(): read error: %s\n",
progname, (char*)lpMsgBuf); progname, (char*)lpMsgBuf);
LocalFree( lpMsgBuf ); LocalFree( lpMsgBuf );
exit(1); exit(1);
@ -288,7 +288,7 @@ int serial_recv(int fd, char * buf, size_t buflen)
} }
int serial_drain(int fd, int display) static int ser_drain(int fd, int display)
{ {
// int rc; // int rc;
unsigned char buf[10]; unsigned char buf[10];
@ -298,7 +298,7 @@ int serial_drain(int fd, int display)
HANDLE hComPort=(HANDLE)fd; HANDLE hComPort=(HANDLE)fd;
if (hComPort == INVALID_HANDLE_VALUE) { if (hComPort == INVALID_HANDLE_VALUE) {
fprintf(stderr, "%s: serial_drain(): port not open\n", fprintf(stderr, "%s: ser_drain(): port not open\n",
progname); progname);
exit(1); exit(1);
} }
@ -323,7 +323,7 @@ int serial_drain(int fd, int display)
(LPTSTR) &lpMsgBuf, (LPTSTR) &lpMsgBuf,
0, 0,
NULL ); NULL );
fprintf(stderr, "%s: serial_drain(): read error: %s\n", fprintf(stderr, "%s: ser_drain(): read error: %s\n",
progname, (char*)lpMsgBuf); progname, (char*)lpMsgBuf);
LocalFree( lpMsgBuf ); LocalFree( lpMsgBuf );
exit(1); exit(1);
@ -340,4 +340,16 @@ int serial_drain(int fd, int display)
return 0; return 0;
} }
struct serial_device serial_serdev =
{
.open = ser_open,
.setspeed = ser_setspeed,
.close = ser_close,
.send = ser_send,
.recv = ser_recv,
.drain = ser_drain,
};
struct serial_device *serdev = &serial_serdev;
#endif /* WIN32NATIVE */ #endif /* WIN32NATIVE */

View File

@ -32,12 +32,25 @@
extern long serial_recv_timeout; extern long serial_recv_timeout;
extern int serial_open(char * port, long baud); struct serial_device
extern int serial_setspeed(int fd, long baud); {
extern void serial_close(int fd); int (*open)(char * port, long baud);
int (*setspeed)(int fd, long baud);
void (*close)(int fd);
extern int serial_send(int fd, char * buf, size_t buflen); int (*send)(int fd, char * buf, size_t buflen);
extern int serial_recv(int fd, char * buf, size_t buflen); int (*recv)(int fd, char * buf, size_t buflen);
extern int serial_drain(int fd, int display); int (*drain)(int fd, int display);
};
extern struct serial_device *serdev;
extern struct serial_device serial_serdev, usb_serdev;
#define serial_open (serdev->open)
#define serial_setspeed (serdev->setspeed)
#define serial_close (serdev->close)
#define serial_send (serdev->send)
#define serial_recv (serdev->recv)
#define serial_drain (serdev->drain)
#endif /* __serial_h__ */ #endif /* __serial_h__ */

268
usb_libusb.c Normal file
View File

@ -0,0 +1,268 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2005 Joerg Wunsch
*
* 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"
extern char *progname;
extern int verbose;
#define USB_VENDOR_ATMEL 1003
#define USB_DEVICE_JTAGICEMKII 0x2103
/*
* Should we query the endpoint number and max transfer size from USB?
* After all, the JTAG ICE mkII docs document these values.
*/
#define JTAGICE_BULK_EP 2
#define JTAGICE_MAX_XFER 64
static char usbbuf[JTAGICE_MAX_XFER];
static int buflen = -1, bufptr;
static int usbdev_open(char * port, long baud)
{
char string[256];
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();
for (bus = usb_busses; bus; bus = bus->next)
{
if (bus->root_dev)
continue;
for (dev = bus->devices; dev; dev = dev->next)
{
udev = usb_open(dev);
if (udev)
{
if (dev->descriptor.idVendor == USB_VENDOR_ATMEL &&
dev->descriptor.idProduct == USB_DEVICE_JTAGICEMKII)
{
/* 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());
exit(1);
}
if (verbose)
fprintf(stderr,
"%s: usb_open(): Found JTAG ICE, serno: %s\n",
progname, 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)
{
if (verbose > 2)
fprintf(stderr,
"%s: usbdev_open(): serial number doesn't match\n",
progname);
usb_close(udev);
continue;
}
}
return (int)udev;
}
usb_close(udev);
}
}
}
fprintf(stderr, "%s: usbdev_open(): did not find any%s USB device \"%s\"\n",
progname, serno? " (matching)": "", port);
exit(1);
}
static int usbdev_setspeed(int fd, long baud)
{
return 0;
}
static void usbdev_close(int fd)
{
usb_dev_handle *udev = (usb_dev_handle *)fd;
usb_close(udev);
}
static int usbdev_send(int fd, char *bp, size_t mlen)
{
usb_dev_handle *udev = (usb_dev_handle *)fd;
return usb_bulk_write(udev, JTAGICE_BULK_EP, (char *)bp, mlen, 5000) != mlen;
}
/*
* 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;
rv = usb_bulk_read(udev, JTAGICE_BULK_EP, usbbuf, JTAGICE_MAX_XFER, 5000);
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;
}
static int usbdev_recv(int fd, char *buf, size_t nbytes)
{
usb_dev_handle *udev = (usb_dev_handle *)fd;
int i, amnt;
char * p = buf;
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;
}
static int usbdev_drain(int fd, int display)
{
return 0;
}
struct serial_device usb_serdev =
{
.open = usbdev_open,
.setspeed = usbdev_setspeed,
.close = usbdev_close,
.send = usbdev_send,
.recv = usbdev_recv,
.drain = usbdev_drain,
};
#endif /* HAVE_LIBUSB */