diff --git a/ChangeLog b/ChangeLog index 86b20a25..3250d64f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2005-06-19 Joerg Wunsch + + * 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 * avrdude.conf.in: The AT90CAN128 has AllowFullPageBitstream = no. diff --git a/Makefile.am b/Makefile.am index 8221f36b..9ca2895e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -94,7 +94,8 @@ avrdude_SOURCES = \ stk500v2.h \ stk500v2_private.h \ term.c \ - term.h + term.h \ + usb_libusb.c man_MANS = avrdude.1 diff --git a/avrdude.1 b/avrdude.1 index d92716ae..ba7f6e78 100644 --- a/avrdude.1 +++ b/avrdude.1 @@ -303,6 +303,23 @@ serial port, the .Pa /dev/cuaa0 port is the default. If you need to use a different parallel or 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 Disable (or quell) output of the progress bar while reading or writing to the device. diff --git a/configure.ac b/configure.ac index dd378141..62f1550b 100644 --- a/configure.ac +++ b/configure.ac @@ -44,6 +44,7 @@ AM_PROG_LEX AC_CHECK_LIB([termcap], [tputs]) AC_CHECK_LIB([ncurses], [tputs]) AC_CHECK_LIB([readline], [readline]) +AC_CHECK_LIB([usb], [usb_open]) # Checks for header files. AC_HEADER_STDC diff --git a/doc/avrdude.texi b/doc/avrdude.texi index afd61ab6..375ebe87 100644 --- a/doc/avrdude.texi +++ b/doc/avrdude.texi @@ -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 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 Disable (or quell) output of the progress bar while reading or writing to the device. @@ -594,6 +603,7 @@ should not be used. @end table +@page @c @c Node @c @@ -642,6 +652,7 @@ avrdude done. Thank you. @end cartouche @end example +@page @noindent Upload the flash memory from the ATmega128 connected to the STK500 programmer and save it in raw binary format in the file named @@ -670,6 +681,7 @@ avrdude done. Thank you. @end cartouche @end example +@page @noindent Using the default programmer, download the file @code{diag.hex} to flash, @code{eeprom.hex} to EEPROM, and set the Extended, High, and Low @@ -718,6 +730,29 @@ avrdude done. Thank you. @end cartouche @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 diff --git a/jtagmkII.c b/jtagmkII.c index b8f81b32..ea7fe2a7 100644 --- a/jtagmkII.c +++ b/jtagmkII.c @@ -1047,6 +1047,15 @@ static int jtagmkII_open(PROGRAMMER * pgm, char * port) if (verbose >= 2) 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); /* * The JTAG ICE mkII always starts with a baud rate of 19200 Bd upon diff --git a/ser_posix.c b/ser_posix.c index b8b6986e..47f2ab5c 100644 --- a/ser_posix.c +++ b/ser_posix.c @@ -38,6 +38,8 @@ #include #include +#include "serial.h" + extern char *progname; extern int verbose; @@ -78,7 +80,7 @@ static speed_t serial_baud_lookup(long baud) exit(1); } -int serial_setspeed(int fd, long baud) +static int ser_setspeed(int fd, long baud) { int rc; struct termios termios; @@ -92,7 +94,7 @@ int serial_setspeed(int fd, long baud) */ rc = tcgetattr(fd, &termios); if (rc < 0) { - fprintf(stderr, "%s: serial_setspeed(): tcgetattr() failed, %s", + fprintf(stderr, "%s: ser_setspeed(): tcgetattr() failed, %s", progname, strerror(errno)); return -errno; } @@ -110,7 +112,7 @@ int serial_setspeed(int fd, long baud) rc = tcsetattr(fd, TCSANOW, &termios); if (rc < 0) { - fprintf(stderr, "%s: serial_setspeed(): tcsetattr() failed, %s", + fprintf(stderr, "%s: ser_setspeed(): tcsetattr() failed, %s", progname, strerror(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 fd; @@ -137,7 +139,7 @@ int serial_open(char * port, int baud) */ fd = open(port, O_RDWR | O_NOCTTY /*| O_NONBLOCK*/); 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)); exit(1); } @@ -145,10 +147,10 @@ int serial_open(char * port, int baud) /* * set serial line attributes */ - rc = serial_setspeed(fd, baud); + rc = ser_setspeed(fd, baud); if (rc) { 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); 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. */ @@ -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; fd_set wfds; @@ -212,7 +214,7 @@ int serial_send(int fd, char * buf, size_t buflen) if (nfds == 0) { if (verbose >= 1) fprintf(stderr, - "%s: serial_send(): programmer is not responding\n", + "%s: ser_send(): programmer is not responding\n", progname); exit(1); } @@ -221,7 +223,7 @@ int serial_send(int fd, char * buf, size_t buflen) goto reselect; } else { - fprintf(stderr, "%s: serial_send(): select(): %s\n", + fprintf(stderr, "%s: ser_send(): select(): %s\n", progname, strerror(errno)); exit(1); } @@ -229,7 +231,7 @@ int serial_send(int fd, char * buf, size_t buflen) rc = write(fd, p, (len > 1024) ? 1024 : len); if (rc < 0) { - fprintf(stderr, "%s: serial_send(): write error: %s\n", + fprintf(stderr, "%s: ser_send(): write error: %s\n", progname, strerror(errno)); 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; fd_set rfds; @@ -264,19 +266,19 @@ int serial_recv(int fd, char * buf, size_t buflen) if (nfds == 0) { if (verbose > 1) fprintf(stderr, - "%s: serial_recv(): programmer is not responding\n", + "%s: ser_recv(): programmer is not responding\n", progname); return -1; } else if (nfds == -1) { if (errno == EINTR || errno == EAGAIN) { fprintf(stderr, - "%s: serial_recv(): programmer is not responding,reselecting\n", + "%s: ser_recv(): programmer is not responding,reselecting\n", progname); goto reselect; } else { - fprintf(stderr, "%s: serial_recv(): select(): %s\n", + fprintf(stderr, "%s: ser_recv(): select(): %s\n", progname, strerror(errno)); 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); if (rc < 0) { - fprintf(stderr, "%s: serial_recv(): read error: %s\n", + fprintf(stderr, "%s: ser_recv(): read error: %s\n", progname, strerror(errno)); 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; fd_set rfds; @@ -351,7 +353,7 @@ int serial_drain(int fd, int display) goto reselect; } else { - fprintf(stderr, "%s: serial_drain(): select(): %s\n", + fprintf(stderr, "%s: ser_drain(): select(): %s\n", progname, strerror(errno)); exit(1); } @@ -359,7 +361,7 @@ int serial_drain(int fd, int display) rc = read(fd, &buf, 1); if (rc < 0) { - fprintf(stderr, "%s: serial_drain(): read error: %s\n", + fprintf(stderr, "%s: ser_drain(): read error: %s\n", progname, strerror(errno)); exit(1); } @@ -371,4 +373,16 @@ int serial_drain(int fd, int display) 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 */ diff --git a/ser_win32.c b/ser_win32.c index 2bd72ef5..3b21a2aa 100644 --- a/ser_win32.c +++ b/ser_win32.c @@ -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; ZeroMemory (&ctmo, sizeof(COMMTIMEOUTS)); @@ -83,7 +83,7 @@ BOOL serial_w32SetTimeOut(HANDLE hComPort, DWORD timeout) // in ms return SetCommTimeouts(hComPort, &ctmo); } -int serial_setspeed(int fd, long baud) +static int ser_setspeed(int fd, long baud) { DCB dcb; 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; HANDLE 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); */ @@ -129,7 +129,7 @@ int serial_open(char * port, long baud) (LPTSTR) &lpMsgBuf, 0, 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); LocalFree( lpMsgBuf ); exit(1); @@ -138,16 +138,16 @@ int serial_open(char * port, long baud) if (!SetupComm(hComPort, W32SERBUFSIZE, W32SERBUFSIZE)) { 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); exit(1); } - if (serial_setspeed((int)hComPort, baud) != 0) + if (ser_setspeed((int)hComPort, baud) != 0) { 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); exit(1); } @@ -155,7 +155,7 @@ int serial_open(char * port, long baud) if (!serial_w32SetTimeOut(hComPort,0)) { 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); 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; 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; unsigned char c='\0'; @@ -183,7 +183,7 @@ int serial_send(int fd, char * buf, size_t buflen) HANDLE hComPort=(HANDLE)fd; if (hComPort == INVALID_HANDLE_VALUE) { - fprintf(stderr, "%s: serial_send(): port not open\n", + fprintf(stderr, "%s: ser_send(): port not open\n", progname); exit(1); } @@ -213,13 +213,13 @@ int serial_send(int fd, char * buf, size_t buflen) serial_w32SetTimeOut(hComPort,500); 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 exit(1); } if (written != buflen) { - fprintf(stderr, "%s: serial_send(): size/send mismatch\n", + fprintf(stderr, "%s: ser_send(): size/send mismatch\n", progname); 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; char * p = buf; @@ -238,7 +238,7 @@ int serial_recv(int fd, char * buf, size_t buflen) HANDLE hComPort=(HANDLE)fd; if (hComPort == INVALID_HANDLE_VALUE) { - fprintf(stderr, "%s: serial_read(): port not open\n", + fprintf(stderr, "%s: ser_read(): port not open\n", progname); exit(1); } @@ -257,7 +257,7 @@ int serial_recv(int fd, char * buf, size_t buflen) (LPTSTR) &lpMsgBuf, 0, NULL ); - fprintf(stderr, "%s: serial_recv(): read error: %s\n", + fprintf(stderr, "%s: ser_recv(): read error: %s\n", progname, (char*)lpMsgBuf); LocalFree( lpMsgBuf ); 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; unsigned char buf[10]; @@ -298,7 +298,7 @@ int serial_drain(int fd, int display) HANDLE hComPort=(HANDLE)fd; if (hComPort == INVALID_HANDLE_VALUE) { - fprintf(stderr, "%s: serial_drain(): port not open\n", + fprintf(stderr, "%s: ser_drain(): port not open\n", progname); exit(1); } @@ -323,7 +323,7 @@ int serial_drain(int fd, int display) (LPTSTR) &lpMsgBuf, 0, NULL ); - fprintf(stderr, "%s: serial_drain(): read error: %s\n", + fprintf(stderr, "%s: ser_drain(): read error: %s\n", progname, (char*)lpMsgBuf); LocalFree( lpMsgBuf ); exit(1); @@ -340,4 +340,16 @@ int serial_drain(int fd, int display) 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 */ diff --git a/serial.h b/serial.h index c3071d74..5dc8d745 100644 --- a/serial.h +++ b/serial.h @@ -32,12 +32,25 @@ extern long serial_recv_timeout; -extern int serial_open(char * port, long baud); -extern int serial_setspeed(int fd, long baud); -extern void serial_close(int fd); +struct serial_device +{ + 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); -extern int serial_recv(int fd, char * buf, size_t buflen); -extern int serial_drain(int fd, int display); + int (*send)(int fd, char * buf, size_t buflen); + int (*recv)(int fd, char * buf, size_t buflen); + 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__ */ diff --git a/usb_libusb.c b/usb_libusb.c new file mode 100644 index 00000000..11d493b8 --- /dev/null +++ b/usb_libusb.c @@ -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 +#include +#include +#include +#include +#include +#include + +#include + +#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 */