Implement the Atmel EDBG/CMSIS-DAP driver protocol for JTAGICE3

(running firmware 3.x) and XplainedPro boards.


git-svn-id: svn://svn.savannah.nongnu.org/avrdude/trunk/avrdude@1278 81a1dc3b-b13d-400b-aceb-764788c761c2
This commit is contained in:
Joerg Wunsch 2014-02-26 17:54:32 +00:00
parent 7f2079731b
commit e59df50eeb
9 changed files with 537 additions and 54 deletions

View File

@ -1,3 +1,15 @@
2014-02-26 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
* jtag3_private.h: Add EDBG/CMSIS-DAP specific constants.
* jtag3.c: Add EDBG/CMSIS-DAP protocol implementation.
* serial.h: (Dito.)
* usbdevs.h: (Dito.)
* usb_libusb.c: (Dito.)
* configure.ac: (Dito.)
* avrdude.conf.in: Add JTAGICE3 and XplainedPro entries using
EDBG.
* configure.ac: Bump version date.
2014-02-22 Joerg Wunsch <j.gnu@uriah.heep.sax.de>
* usb_libusb.c (usbdev_recv_frame): Fix a bug where a new recv

2
NEWS
View File

@ -8,7 +8,7 @@ Approximate change log for AVRDUDE by version.
Current:
* Major changes compared to the previous version:
- ...
- Atmel EDBG protocol support added (JTAGICE3, XplainedPro)
* New devices supported:
- ...

View File

@ -994,6 +994,7 @@ programmer
desc = "Atmel AVR JTAGICE3 in JTAG mode";
type = "jtagice3";
connection_type = usb;
usbpid = 0x2110;
;
programmer
@ -1001,6 +1002,7 @@ programmer
desc = "Atmel AVR JTAGICE3 in PDI mode";
type = "jtagice3_pdi";
connection_type = usb;
usbpid = 0x2110;
;
programmer
@ -1008,6 +1010,7 @@ programmer
desc = "Atmel AVR JTAGICE3 in debugWIRE mode";
type = "jtagice3_dw";
connection_type = usb;
usbpid = 0x2110;
;
programmer
@ -1015,6 +1018,47 @@ programmer
desc = "Atmel AVR JTAGICE3 in ISP mode";
type = "jtagice3_isp";
connection_type = usb;
usbpid = 0x2110;
;
programmer
id = "jtag3edbg";
desc = "Atmel AVR JTAGICE3 in JTAG mode, EDBG protocol";
type = "jtagice3";
connection_type = usb;
usbpid = 0x2140;
;
programmer
id = "jtag3pdi_edbg";
desc = "Atmel AVR JTAGICE3 in PDI mode, EDBG protocol";
type = "jtagice3_pdi";
connection_type = usb;
usbpid = 0x2140;
;
programmer
id = "jtag3dw_edbg";
desc = "Atmel AVR JTAGICE3 in debugWIRE mode, EDBG protocol";
type = "jtagice3_dw";
connection_type = usb;
usbpid = 0x2140;
;
programmer
id = "jtag3isp_edbg";
desc = "Atmel AVR JTAGICE3 in ISP mode, EDBG protocol";
type = "jtagice3_isp";
connection_type = usb;
usbpid = 0x2140;
;
programmer
id = "xplainedpro";
desc = "Atmel AVR XplainedPro in JTAG mode";
type = "jtagice3";
connection_type = usb;
usbpid = 0x2111;
;

View File

@ -23,7 +23,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.60)
AC_INIT(avrdude, 6.1-svn-20131205, avrdude-dev@nongnu.org)
AC_INIT(avrdude, 6.1-svn-20140226, avrdude-dev@nongnu.org)
AC_CANONICAL_BUILD
AC_CANONICAL_HOST

329
jtag3.c
View File

@ -84,8 +84,13 @@ struct pdata
#define PGM_FL_IS_DW (0x0001)
#define PGM_FL_IS_PDI (0x0002)
#define PGM_FL_IS_JTAG (0x0004)
#define PGM_FL_IS_EDBG (0x0008)
static int jtag3_open(PROGRAMMER * pgm, char * port);
static int jtag3_edbg_prepare(PROGRAMMER * pgm);
static int jtag3_edbg_signoff(PROGRAMMER * pgm);
static int jtag3_edbg_send(PROGRAMMER * pgm, unsigned char * data, size_t len);
static int jtag3_edbg_recv_frame(PROGRAMMER * pgm, unsigned char **msg);
static int jtag3_initialize(PROGRAMMER * pgm, AVRPART * p);
static int jtag3_chip_erase(PROGRAMMER * pgm, AVRPART * p);
@ -399,6 +404,9 @@ int jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
{
unsigned char *buf;
if (pgm->flag & PGM_FL_IS_EDBG)
return jtag3_edbg_send(pgm, data, len);
if (verbose >= 3)
fprintf(stderr, "\n%s: jtag3_send(): sending %lu bytes\n",
progname, (unsigned long)len);
@ -419,7 +427,7 @@ int jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
fprintf(stderr,
"%s: jtag3_send(): failed to send command to serial port\n",
progname);
exit(1);
return -1;
}
free(buf);
@ -427,6 +435,193 @@ int jtag3_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
return 0;
}
static int jtag3_edbg_send(PROGRAMMER * pgm, unsigned char * data, size_t len)
{
unsigned char buf[USBDEV_MAX_XFER_3];
unsigned char status[USBDEV_MAX_XFER_3];
int rv;
if (verbose >= 4)
{
memset(buf, 0, pgm->fd.usb.max_xfer);
memset(status, 0, pgm->fd.usb.max_xfer);
}
if (verbose >= 3)
fprintf(stderr, "\n%s: jtag3_edbg_send(): sending %lu bytes\n",
progname, (unsigned long)len);
if (len + 8 > pgm->fd.usb.max_xfer)
{
fprintf(stderr,
"%s: jtag3_edbg_send(): Fragmentation not (yet) implemented!\n",
progname);
return -1;
}
buf[0] = EDBG_VENDOR_AVR_CMD;
buf[1] = (1 << 4) | 1; /* first out of a total of 1 fragments */
buf[2] = (len + 4) >> 8;
buf[3] = (len + 4) & 0xff;
buf[4] = TOKEN;
buf[5] = 0; /* dummy */
u16_to_b2(buf + 6, PDATA(pgm)->command_sequence);
memcpy(buf + 8, data, len);
if (serial_send(&pgm->fd, buf, pgm->fd.usb.max_xfer) != 0) {
fprintf(stderr,
"%s: jtag3_edbg_send(): failed to send command to serial port\n",
progname);
return -1;
}
rv = serial_recv(&pgm->fd, status, pgm->fd.usb.max_xfer);
if (rv < 0) {
/* timeout in receive */
if (verbose > 1)
fprintf(stderr,
"%s: jtag3_edbg_send(): Timeout receiving packet\n",
progname);
return -1;
}
if (status[0] != EDBG_VENDOR_AVR_CMD || status[1] != 0x01)
{
/* what to do in this case? */
fprintf(stderr,
"%s: jtag3_edbg_send(): Unexpected response 0x%02x, 0x%02x\n",
progname, status[0], status[1]);
}
return 0;
}
/*
* Send out all the CMSIS-DAP stuff needed to prepare the ICE.
*/
static int jtag3_edbg_prepare(PROGRAMMER * pgm)
{
unsigned char buf[USBDEV_MAX_XFER_3];
unsigned char status[USBDEV_MAX_XFER_3];
int rv;
if (verbose >= 3)
fprintf(stderr, "\n%s: jtag3_edbg_prepare()\n",
progname);
if (verbose >= 4)
memset(buf, 0, USBDEV_MAX_XFER_3);
buf[0] = CMSISDAP_CMD_CONNECT;
buf[1] = CMSISDAP_CONN_SWD;
if (serial_send(&pgm->fd, buf, USBDEV_MAX_XFER_3) != 0) {
fprintf(stderr,
"%s: jtag3_edbg_prepare(): failed to send command to serial port\n",
progname);
return -1;
}
rv = serial_recv(&pgm->fd, status, USBDEV_MAX_XFER_3);
if (rv != USBDEV_MAX_XFER_3) {
fprintf(stderr,
"%s: jtag3_edbg_prepare(): failed to read from serial port (%d)\n",
progname, rv);
return -1;
}
if (status[0] != CMSISDAP_CMD_CONNECT ||
status[1] == 0)
fprintf(stderr,
"%s: jtag3_edbg_prepare(): unexpected response 0x%02x, 0x%02x\n",
progname, status[0], status[1]);
if (verbose >= 2)
fprintf(stderr,
"%s: jtag3_edbg_prepare(): connection status 0x%02x\n",
progname, status[1]);
buf[0] = CMSISDAP_CMD_LED;
buf[1] = CMSISDAP_LED_CONNECT;
buf[2] = 1;
if (serial_send(&pgm->fd, buf, USBDEV_MAX_XFER_3) != 0) {
fprintf(stderr,
"%s: jtag3_edbg_prepare(): failed to send command to serial port\n",
progname);
return -1;
}
rv = serial_recv(&pgm->fd, status, USBDEV_MAX_XFER_3);
if (rv != USBDEV_MAX_XFER_3) {
fprintf(stderr,
"%s: jtag3_edbg_prepare(): failed to read from serial port (%d)\n",
progname, rv);
return -1;
}
if (status[0] != CMSISDAP_CMD_LED ||
status[1] != 0)
fprintf(stderr,
"%s: jtag3_edbg_prepare(): unexpected response 0x%02x, 0x%02x\n",
progname, status[0], status[1]);
return 0;
}
/*
* Send out all the CMSIS-DAP stuff when signing off.
*/
static int jtag3_edbg_signoff(PROGRAMMER * pgm)
{
unsigned char buf[USBDEV_MAX_XFER_3];
unsigned char status[USBDEV_MAX_XFER_3];
int rv;
if (verbose >= 3)
fprintf(stderr, "\n%s: jtag3_edbg_signoff()\n",
progname);
if (verbose >= 4)
memset(buf, 0, USBDEV_MAX_XFER_3);
buf[0] = CMSISDAP_CMD_LED;
buf[1] = CMSISDAP_LED_CONNECT;
buf[2] = 0;
if (serial_send(&pgm->fd, buf, USBDEV_MAX_XFER_3) != 0) {
fprintf(stderr,
"%s: jtag3_edbg_signoff(): failed to send command to serial port\n",
progname);
return -1;
}
rv = serial_recv(&pgm->fd, status, USBDEV_MAX_XFER_3);
if (rv != USBDEV_MAX_XFER_3) {
fprintf(stderr,
"%s: jtag3_edbg_signoff(): failed to read from serial port (%d)\n",
progname, rv);
return -1;
}
if (status[0] != CMSISDAP_CMD_LED ||
status[1] != 0)
fprintf(stderr,
"%s: jtag3_edbg_signoff(): unexpected response 0x%02x, 0x%02x\n",
progname, status[0], status[1]);
buf[0] = CMSISDAP_CMD_DISCONNECT;
if (serial_send(&pgm->fd, buf, USBDEV_MAX_XFER_3) != 0) {
fprintf(stderr,
"%s: jtag3_edbg_signoff(): failed to send command to serial port\n",
progname);
return -1;
}
rv = serial_recv(&pgm->fd, status, USBDEV_MAX_XFER_3);
if (rv != USBDEV_MAX_XFER_3) {
fprintf(stderr,
"%s: jtag3_edbg_signoff(): failed to read from serial port (%d)\n",
progname, rv);
return -1;
}
if (status[0] != CMSISDAP_CMD_DISCONNECT ||
status[1] != 0)
fprintf(stderr,
"%s: jtag3_edbg_signoff(): unexpected response 0x%02x, 0x%02x\n",
progname, status[0], status[1]);
return 0;
}
static int jtag3_drain(PROGRAMMER * pgm, int display)
{
@ -446,6 +641,9 @@ static int jtag3_recv_frame(PROGRAMMER * pgm, unsigned char **msg) {
int rv;
unsigned char *buf = NULL;
if (pgm->flag & PGM_FL_IS_EDBG)
return jtag3_edbg_recv_frame(pgm, msg);
if (verbose >= 4)
fprintf(stderr, "%s: jtag3_recv():\n", progname);
@ -454,6 +652,8 @@ static int jtag3_recv_frame(PROGRAMMER * pgm, unsigned char **msg) {
progname);
return -1;
}
if (verbose >= 4)
memset(buf, 0, pgm->fd.usb.max_xfer);
rv = serial_recv(&pgm->fd, buf, pgm->fd.usb.max_xfer);
@ -472,6 +672,62 @@ static int jtag3_recv_frame(PROGRAMMER * pgm, unsigned char **msg) {
return rv;
}
static int jtag3_edbg_recv_frame(PROGRAMMER * pgm, unsigned char **msg) {
int rv, len;
unsigned char *buf = NULL;
if (verbose >= 4)
fprintf(stderr, "%s: jtag3_edbg_recv():\n", progname);
if ((buf = malloc(pgm->fd.usb.max_xfer)) == NULL) {
fprintf(stderr, "%s: jtag3_edbg_recv(): out of memory\n",
progname);
return -1;
}
buf[0] = EDBG_VENDOR_AVR_RSP;
if (serial_send(&pgm->fd, buf, pgm->fd.usb.max_xfer) != 0) {
fprintf(stderr,
"%s: jtag3_edbg_recv(): error sending CMSIS-DAP vendor command\n",
progname);
return -1;
}
rv = serial_recv(&pgm->fd, buf, pgm->fd.usb.max_xfer);
if (rv < 0) {
/* timeout in receive */
if (verbose > 1)
fprintf(stderr,
"%s: jtag3_edbg_recv(): Timeout receiving packet\n",
progname);
free(buf);
return -1;
}
if (buf[0] != EDBG_VENDOR_AVR_RSP ||
buf[1] != ((1 << 4) | 1)) {
fprintf(stderr,
"%s: jtag3_edbg_recv(): Unexpected response 0x%02x, 0x%02x\n",
progname, buf[0], buf[1]);
return -1;
}
/* calculate length from response; CMSIS-DAP response might be larger */
len = (buf[2] << 8) | buf[3];
if (len > rv + 4) {
fprintf(stderr,
"%s: jtag3_edbg_recv(): Unexpected length value (%d > %d)\n",
progname, len, rv + 4);
len = rv + 4;
}
memmove(buf, buf + 4, len);
*msg = buf;
return rv;
}
int jtag3_recv(PROGRAMMER * pgm, unsigned char **msg) {
unsigned short r_seqno;
int rv;
@ -562,6 +818,11 @@ int jtag3_getsync(PROGRAMMER * pgm, int mode) {
if (verbose >= 3)
fprintf(stderr, "%s: jtag3_getsync()\n", progname);
if (pgm->flag & PGM_FL_IS_EDBG) {
if (jtag3_edbg_prepare(pgm) < 0)
return -1;
}
/* Get the sign-on information. */
buf[0] = SCOPE_GENERAL;
buf[1] = CMD3_SIGN_ON;
@ -1034,9 +1295,15 @@ static int jtag3_open(PROGRAMMER * pgm, char * port)
if (strncmp(port, "usb", 3) == 0) {
#if defined(HAVE_LIBUSB)
serdev = &usb_serdev_frame;
pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
if (pgm->usbvid)
pinfo.usbinfo.vid = pgm->usbvid;
else
pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
pinfo.usbinfo.flags = 0;
pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
if (pgm->usbpid)
pinfo.usbinfo.pid = pgm->usbpid;
else
pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
pgm->fd.usb.max_xfer = USBDEV_MAX_XFER_3;
pgm->fd.usb.rep = USBDEV_BULK_EP_READ_3;
pgm->fd.usb.wep = USBDEV_BULK_EP_WRITE_3;
@ -1052,6 +1319,17 @@ static int jtag3_open(PROGRAMMER * pgm, char * port)
return -1;
}
if (pgm->fd.usb.eep == 0)
{
/* The event EP has been deleted by usb_open(), so we are
running on a CMSIS-DAP device, using EDBG protocol */
pgm->flag |= PGM_FL_IS_EDBG;
if (verbose)
fprintf(stderr,
"%s: Found CMSIS-DAP compliant device, using EDBG protocol\n",
progname);
}
/*
* drain any extraneous input
*/
@ -1078,9 +1356,15 @@ static int jtag3_open_dw(PROGRAMMER * pgm, char * port)
if (strncmp(port, "usb", 3) == 0) {
#if defined(HAVE_LIBUSB)
serdev = &usb_serdev_frame;
pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
if (pgm->usbvid)
pinfo.usbinfo.vid = pgm->usbvid;
else
pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
pinfo.usbinfo.flags = 0;
pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
if (pgm->usbpid)
pinfo.usbinfo.pid = pgm->usbpid;
else
pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
pgm->fd.usb.max_xfer = USBDEV_MAX_XFER_3;
pgm->fd.usb.rep = USBDEV_BULK_EP_READ_3;
pgm->fd.usb.wep = USBDEV_BULK_EP_WRITE_3;
@ -1096,6 +1380,17 @@ static int jtag3_open_dw(PROGRAMMER * pgm, char * port)
return -1;
}
if (pgm->fd.usb.eep == 0)
{
/* The event EP has been deleted by usb_open(), so we are
running on a CMSIS-DAP device, using EDBG protocol */
pgm->flag |= PGM_FL_IS_EDBG;
if (verbose)
fprintf(stderr,
"%s: Found CMSIS-DAP compliant device, using EDBG protocol\n",
progname);
}
/*
* drain any extraneous input
*/
@ -1122,9 +1417,15 @@ static int jtag3_open_pdi(PROGRAMMER * pgm, char * port)
if (strncmp(port, "usb", 3) == 0) {
#if defined(HAVE_LIBUSB)
serdev = &usb_serdev_frame;
pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
if (pgm->usbvid)
pinfo.usbinfo.vid = pgm->usbvid;
else
pinfo.usbinfo.vid = USB_VENDOR_ATMEL;
pinfo.usbinfo.flags = 0;
pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
if (pgm->usbpid)
pinfo.usbinfo.pid = pgm->usbpid;
else
pinfo.usbinfo.pid = USB_DEVICE_JTAGICE3;
pgm->fd.usb.max_xfer = USBDEV_MAX_XFER_3;
pgm->fd.usb.rep = USBDEV_BULK_EP_READ_3;
pgm->fd.usb.wep = USBDEV_BULK_EP_WRITE_3;
@ -1140,6 +1441,17 @@ static int jtag3_open_pdi(PROGRAMMER * pgm, char * port)
return -1;
}
if (pgm->fd.usb.eep == 0)
{
/* The event EP has been deleted by usb_open(), so we are
running on a CMSIS-DAP device, using EDBG protocol */
pgm->flag |= PGM_FL_IS_EDBG;
if (verbose)
fprintf(stderr,
"%s: Found CMSIS-DAP compliant device, using EDBG protocol\n",
progname);
}
/*
* drain any extraneous input
*/
@ -1172,6 +1484,9 @@ void jtag3_close(PROGRAMMER * pgm)
if (jtag3_command(pgm, buf, 4, &resp, "sign-off") >= 0)
free(resp);
if (pgm->flag & PGM_FL_IS_EDBG)
jtag3_edbg_signoff(pgm);
serial_close(&pgm->fd);
pgm->fd.ifd = -1;
}

View File

@ -222,6 +222,47 @@
#define XMEGA_ERASE_EEPROM_PAGE 0x06
#define XMEGA_ERASE_USERSIG 0x07
/* EDBG vendor commands */
#define EDBG_VENDOR_AVR_CMD 0x80
#define EDBG_VENDOR_AVR_RSP 0x81
#define EDBG_VENDOR_AVR_EVT 0x82
/* CMSIS-DAP commands */
#define CMSISDAP_CMD_INFO 0x00 /* get info, followed by INFO byte */
# define CMSISDAP_INFO_VID 0x01 /* vendor ID (string) */
# define CMSISDAP_INFO_PID 0x02 /* product ID (string) */
# define CMSISDAP_INFO_SERIAL 0x03 /* serial number (string) */
# define CMSISDAP_INFO_FIRMWARE 0x04 /* firmware version (string) */
# define CMSISDAP_INFO_TARGET_VENDOR 0x05 /* target device vendor (string) */
# define CMSISDAP_INFO_TARGET_NAME 0x06 /* target device name (string) */
# define CMSISDAP_INFO_CAPABILITIES 0xF0 /* debug unit capabilities (byte) */
# define CMSISDAP_INFO_PACKET_COUNT 0xFE /* packet count (byte) (which packets, anyway?) */
# define CMSISDAP_INFO_PACKET_SIZE 0xFF /* packet size (short) */
#define CMSISDAP_CMD_LED 0x01 /* LED control, followed by LED number and on/off byte */
# define CMSISDAP_LED_CONNECT 0x00 /* connect LED */
# define CMSISDAP_LED_RUNNING 0x01 /* running LED */
#define CMSISDAP_CMD_CONNECT 0x02 /* connect to target, followed by DAP mode */
# define CMSISDAP_CONN_DEFAULT 0x00
# define CMSISDAP_CONN_SWD 0x01 /* serial wire debug */
# define CMSISDAP_CONN_JTAG 0x02 /* JTAG mode */
#define CMSISDAP_CMD_DISCONNECT 0x03 /* disconnect from target */
#define CMSISDAP_XFR_CONFIGURE 0x04 /* configure transfers; idle cycles (byte);
wait retry (short); match retry (short) */
#define CMSISDAP_CMD_WRITEAPBORT 0x08 /* write to CoreSight ABORT register of target */
#define CMSISDAP_CMD_DELAY 0x09 /* delay for number of microseconds (short) */
#define CMSISDAP_CMD_RESET 0x0A /* reset target */
#define CMSISDAP_CMD_SWJ_CLOCK 0x11 /* SWD/JTAG clock, (word) */
#define CMSISDAP_CMD_SWD_CONFIGURE 0x13 /* configure SWD protocol; (byte) */
#if !defined(JTAG3_PRIVATE_EXPORTED)
struct mega_device_desc {

View File

@ -41,6 +41,7 @@ union filedescriptor
int wep; /* bulk write endpoint */
int eep; /* event read endpoint */
int max_xfer; /* max transfer size */
int use_interrupt_xfer; /* device uses interrupt transfers */
} usb;
};
@ -52,6 +53,7 @@ union pinfo
unsigned short vid;
unsigned short pid;
unsigned short flags;
#define PINFO_FL_USEHID 0x0001
} usbinfo;
};

View File

@ -70,6 +70,7 @@ static int usbdev_open(char * port, union pinfo pinfo, union filedescriptor *fd)
usb_dev_handle *udev;
char *serno, *cp2;
int i;
int iface;
size_t x;
/*
@ -151,6 +152,21 @@ static int usbdev_open(char * port, union pinfo pinfo, union filedescriptor *fd)
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 (verbose)
fprintf(stderr,
@ -186,66 +202,102 @@ static int usbdev_open(char * port, union pinfo pinfo, union filedescriptor *fd)
if (usb_set_configuration(udev, dev->config[0].bConfigurationValue))
{
fprintf(stderr,
"%s: usbdev_open(): error setting configuration %d: %s\n",
"%s: usbdev_open(): WARNING: failed to set configuration %d: %s\n",
progname, dev->config[0].bConfigurationValue,
usb_strerror());
goto trynext;
/* let's hope it has already been configured */
// goto trynext;
}
usb_interface = dev->config[0].interface[0].altsetting[0].bInterfaceNumber;
if (usb_claim_interface(udev, usb_interface))
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))
{
fprintf(stderr,
"%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)
{
fprintf(stderr,
"%s: usbdev_open(): error claiming interface %d: %s\n",
progname, usb_interface, usb_strerror());
"%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[0].altsetting[0].bNumEndpoints; i++)
{
int possible_ep = dev->config[0].interface[0].altsetting[0].
endpoint[i].bEndpointAddress;
/* 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)
{
if (verbose > 1)
if ((possible_ep & USB_ENDPOINT_DIR_MASK) != 0)
{
if (verbose > 1)
{
fprintf(stderr,
"%s: usbdev_open(): using read endpoint 0x%02x\n",
progname, possible_ep);
}
fd->usb.rep = possible_ep;
break;
}
}
if (fd->usb.rep == 0)
{
fprintf(stderr,
"%s: usbdev_open(): using read endpoint 0x%02x\n",
progname, possible_ep);
"%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;
}
fd->usb.rep = possible_ep;
break;
}
}
if (fd->usb.rep == 0)
for (i = 0; i < dev->config[0].interface[iface].altsetting[0].bNumEndpoints; i++)
{
fprintf(stderr,
"%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[0].altsetting[0].bNumEndpoints; i++)
{
if ((dev->config[0].interface[0].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.rep ||
dev->config[0].interface[0].altsetting[0].endpoint[i].bEndpointAddress == fd->usb.wep) &&
dev->config[0].interface[0].altsetting[0].endpoint[i].wMaxPacketSize < fd->usb.max_xfer)
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)
{
if (verbose != 0)
fprintf(stderr,
"%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[0].altsetting[0].endpoint[i].wMaxPacketSize,
dev->config[0].interface[0].altsetting[0].endpoint[i].bEndpointAddress);
fd->usb.max_xfer = dev->config[0].interface[0].altsetting[0].endpoint[i].wMaxPacketSize;
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)
fprintf(stderr, "%s: usbdev_open(): SET_IDLE failed\n", progname);
}
return 0;
trynext:
usb_close(udev);
@ -299,7 +351,10 @@ static int usbdev_send(union filedescriptor *fd, unsigned char *bp, size_t mlen)
*/
do {
tx_size = (mlen < fd->usb.max_xfer)? mlen: fd->usb.max_xfer;
rv = usb_bulk_write(udev, fd->usb.wep, (char *)bp, tx_size, 10000);
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)
{
fprintf(stderr, "%s: usbdev_send(): wrote %d out of %d bytes, err = %s\n",
@ -341,16 +396,20 @@ static int usbdev_send(union filedescriptor *fd, unsigned char *bp, size_t mlen)
* empty and more data are requested.
*/
static int
usb_fill_buf(usb_dev_handle *udev, int maxsize, int ep)
usb_fill_buf(usb_dev_handle *udev, int maxsize, int ep, int use_interrupt_xfer)
{
int rv;
rv = usb_bulk_read(udev, ep, usbbuf, maxsize, 10000);
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)
{
if (verbose > 1)
fprintf(stderr, "%s: usb_fill_buf(): usb_bulk_read() error %s\n",
progname, usb_strerror());
fprintf(stderr, "%s: usb_fill_buf(): usb_%s_read() error %s\n",
progname, (use_interrupt_xfer? "interrupt": "bulk"),
usb_strerror());
return -1;
}
@ -370,7 +429,7 @@ static int usbdev_recv(union filedescriptor *fd, unsigned char *buf, size_t nbyt
{
if (buflen <= bufptr)
{
if (usb_fill_buf(udev, fd->usb.max_xfer, fd->usb.rep) < 0)
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;
@ -441,13 +500,18 @@ static int usbdev_recv_frame(union filedescriptor *fd, unsigned char *buf, size_
n = 0;
do
{
rv = usb_bulk_read(udev, fd->usb.rep, usbbuf,
fd->usb.max_xfer, 10000);
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)
{
if (verbose > 1)
fprintf(stderr, "%s: usbdev_recv_frame(): usb_bulk_read(): %s\n",
progname, usb_strerror());
fprintf(stderr, "%s: usbdev_recv_frame(): usb_%s_read(): %s\n",
progname, (fd->usb.use_interrupt_xfer? "interrupt": "bulk"),
usb_strerror());
return -1;
}
@ -495,7 +559,10 @@ static int usbdev_drain(union filedescriptor *fd, int display)
int rv;
do {
rv = usb_bulk_read(udev, fd->usb.rep, usbbuf, fd->usb.max_xfer, 100);
if (fd->usb.use_interrupt_xfer)
rv = usb_interrupt_read(udev, fd->usb.rep, usbbuf, fd->usb.max_xfer, 100);
else
rv = usb_bulk_read(udev, fd->usb.rep, usbbuf, fd->usb.max_xfer, 100);
if (rv > 0 && verbose >= 4)
fprintf(stderr, "%s: usbdev_drain(): flushed %d characters\n",
progname, rv);

View File

@ -31,6 +31,8 @@
#define USB_DEVICE_STK600 0x2106
#define USB_DEVICE_AVRDRAGON 0x2107
#define USB_DEVICE_JTAGICE3 0x2110
#define USB_DEVICE_XPLAINEDPRO 0x2111
#define USB_DEVICE_JTAG3_EDBG 0x2140
/* JTAGICEmkII, AVRISPmkII */
#define USBDEV_BULK_EP_WRITE_MKII 0x02