aboutsummaryrefslogtreecommitdiff
path: root/src/jtag/drivers/libjaylink/libjaylink
diff options
context:
space:
mode:
Diffstat (limited to 'src/jtag/drivers/libjaylink/libjaylink')
m---------src/jtag/drivers/libjaylink0
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/Makefile.am62
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/buffer.c140
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/core.c219
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/device.c1707
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/discovery.c106
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/discovery_tcp.c349
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/discovery_usb.c280
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/emucom.c287
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/error.c118
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/fileio.c499
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/jtag.c259
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/libjaylink-internal.h320
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/libjaylink.h589
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/list.c115
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/log.c266
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/socket.c257
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/strutil.c66
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/swd.c148
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/swo.c453
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/target.c533
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/transport.c309
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/transport_tcp.c601
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/transport_usb.c620
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/util.c56
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/version.c128
-rw-r--r--src/jtag/drivers/libjaylink/libjaylink/version.h.in53
27 files changed, 8540 insertions, 0 deletions
diff --git a/src/jtag/drivers/libjaylink b/src/jtag/drivers/libjaylink
deleted file mode 160000
-Subproject 8645845c1abebd004e991ba9a7f808f4fd0c608
diff --git a/src/jtag/drivers/libjaylink/libjaylink/Makefile.am b/src/jtag/drivers/libjaylink/libjaylink/Makefile.am
new file mode 100644
index 0000000..62c5489
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/Makefile.am
@@ -0,0 +1,62 @@
+##
+## This file is part of the libjaylink project.
+##
+## Copyright (C) 2014-2015 Marc Schink <jaylink-dev@marcschink.de>
+##
+## 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/>.
+##
+
+if SUBPROJECT_BUILD
+noinst_LTLIBRARIES = libjaylink.la
+else
+lib_LTLIBRARIES = libjaylink.la
+
+library_includedir = $(includedir)/libjaylink
+library_include_HEADERS = libjaylink.h
+nodist_library_include_HEADERS = version.h
+endif
+
+libjaylink_la_SOURCES = \
+ buffer.c \
+ core.c \
+ device.c \
+ discovery.c \
+ discovery_tcp.c \
+ emucom.c \
+ error.c \
+ fileio.c \
+ jtag.c \
+ list.c \
+ log.c \
+ socket.c \
+ strutil.c \
+ swd.c \
+ swo.c \
+ target.c \
+ transport.c \
+ transport_tcp.c \
+ util.c \
+ version.c
+
+libjaylink_la_CFLAGS = $(JAYLINK_CFLAGS)
+libjaylink_la_LDFLAGS = $(JAYLINK_LDFLAGS) -no-undefined
+libjaylink_la_LIBADD = $(JAYLINK_LIBS)
+
+if HAVE_LIBUSB
+libjaylink_la_SOURCES += discovery_usb.c transport_usb.c
+libjaylink_la_CFLAGS += $(libusb_CFLAGS)
+libjaylink_la_LIBADD += $(libusb_LIBS)
+endif
+
+noinst_HEADERS = libjaylink-internal.h
diff --git a/src/jtag/drivers/libjaylink/libjaylink/buffer.c b/src/jtag/drivers/libjaylink/libjaylink/buffer.c
new file mode 100644
index 0000000..527c25e
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/buffer.c
@@ -0,0 +1,140 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdint.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Buffer helper functions.
+ */
+
+/**
+ * Write a 16-bit unsigned integer value to a buffer.
+ *
+ * The value is stored in the buffer in device byte order.
+ *
+ * @param[out] buffer Buffer to write the value into.
+ * @param[in] value Value to write into the buffer in host byte order.
+ * @param[in] offset Offset of the value within the buffer in bytes.
+ */
+JAYLINK_PRIV void buffer_set_u16(uint8_t *buffer, uint16_t value,
+ size_t offset)
+{
+ /*
+ * Store the value in the buffer and swap byte order depending on the
+ * host byte order.
+ */
+#ifdef WORDS_BIGENDIAN
+ buffer[offset + 0] = value;
+ buffer[offset + 1] = value >> 8;
+#else
+ memcpy(buffer + offset, &value, sizeof(value));
+#endif
+}
+
+/**
+ * Read a 16-bit unsigned integer value from a buffer.
+ *
+ * The value in the buffer is expected to be stored in device byte order.
+ *
+ * @param[in] buffer Buffer to read the value from.
+ * @param[in] offset Offset of the value within the buffer in bytes.
+ *
+ * @return The value read from the buffer in host byte order.
+ */
+JAYLINK_PRIV uint16_t buffer_get_u16(const uint8_t *buffer, size_t offset)
+{
+ uint16_t value;
+
+ /*
+ * Read the value from the buffer and swap byte order depending on the
+ * host byte order.
+ */
+#ifdef WORDS_BIGENDIAN
+ value = (((uint16_t)buffer[offset + 1])) | \
+ (((uint16_t)buffer[offset + 0]) << 8);
+#else
+ memcpy(&value, buffer + offset, sizeof(value));
+#endif
+
+ return value;
+}
+
+/**
+ * Write a 32-bit unsigned integer value to a buffer.
+ *
+ * The value is stored in the buffer in device byte order.
+ *
+ * @param[out] buffer Buffer to write the value into.
+ * @param[in] value Value to write into the buffer in host byte order.
+ * @param[in] offset Offset of the value within the buffer in bytes.
+ */
+JAYLINK_PRIV void buffer_set_u32(uint8_t *buffer, uint32_t value,
+ size_t offset)
+{
+ /*
+ * Store the value in the buffer and swap byte order depending on the
+ * host byte order.
+ */
+#ifdef WORDS_BIGENDIAN
+ buffer[offset + 0] = value;
+ buffer[offset + 1] = value >> 8;
+ buffer[offset + 2] = value >> 16;
+ buffer[offset + 3] = value >> 24;
+#else
+ memcpy(buffer + offset, &value, sizeof(value));
+#endif
+}
+
+/**
+ * Read a 32-bit unsigned integer value from a buffer.
+ *
+ * The value in the buffer is expected to be stored in device byte order.
+ *
+ * @param[in] buffer Buffer to read the value from.
+ * @param[in] offset Offset of the value within the buffer in bytes.
+ *
+ * @return The value read from the buffer in host byte order.
+ */
+JAYLINK_PRIV uint32_t buffer_get_u32(const uint8_t *buffer, size_t offset)
+{
+ uint32_t value;
+
+ /*
+ * Read the value from the buffer and swap byte order depending on the
+ * host byte order.
+ */
+#ifdef WORDS_BIGENDIAN
+ value = (((uint32_t)buffer[offset + 3])) | \
+ (((uint32_t)buffer[offset + 2]) << 8) | \
+ (((uint32_t)buffer[offset + 1]) << 16) | \
+ (((uint32_t)buffer[offset + 0]) << 24);
+#else
+ memcpy(&value, buffer + offset, sizeof(value));
+#endif
+
+ return value;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/core.c b/src/jtag/drivers/libjaylink/libjaylink/core.c
new file mode 100644
index 0000000..509b89d
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/core.c
@@ -0,0 +1,219 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2016 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdbool.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#endif
+#ifdef HAVE_LIBUSB
+#include <libusb.h>
+#endif
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @mainpage
+ *
+ * @section sec_intro Introduction
+ *
+ * This document describes the API of libjaylink.
+ *
+ * libjaylink is a shared library written in C to access SEGGER J-Link and
+ * compatible devices.
+ *
+ * @section sec_error Error handling
+ *
+ * The libjaylink functions which can fail use the return value to indicate an
+ * error. The functions typically return an error code of #jaylink_error.
+ * For each function, all possible error codes and their detailed descriptions
+ * are documented. As the possible error codes returned by a function may
+ * change it is recommended to also always cover unexpected values when
+ * checking for error codes to be compatible with later versions of libjaylink.
+ *
+ * There are a few exceptions where a function directly returns the result
+ * instead of an error code because it is more convenient from an API
+ * perspective and because there is only a single reason for failure which is
+ * clearly distinguishable from the result.
+ *
+ * @section sec_license Copyright and license
+ *
+ * libjaylink is licensed under the terms of the GNU General Public
+ * License (GPL), version 2 or later.
+ *
+ * @section sec_website Website
+ *
+ * <a href="http://git.zapb.de/libjaylink.git">git.zapb.de/libjaylink.git</a>
+ */
+
+/**
+ * @file
+ *
+ * Core library functions.
+ */
+
+/**
+ * Initialize libjaylink.
+ *
+ * This function must be called before any other libjaylink function is called.
+ *
+ * @param[out] ctx Newly allocated libjaylink context on success, and undefined
+ * on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_MALLOC Memory allocation error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_init(struct jaylink_context **ctx)
+{
+ int ret;
+ struct jaylink_context *context;
+#ifdef _WIN32
+ WSADATA wsa_data;
+#endif
+
+ if (!ctx)
+ return JAYLINK_ERR_ARG;
+
+ context = malloc(sizeof(struct jaylink_context));
+
+ if (!context)
+ return JAYLINK_ERR_MALLOC;
+
+#ifdef HAVE_LIBUSB
+ if (libusb_init(&context->usb_ctx) != LIBUSB_SUCCESS) {
+ free(context);
+ return JAYLINK_ERR;
+ }
+#endif
+
+#ifdef _WIN32
+ ret = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+
+ if (ret != 0) {
+#ifdef HAVE_LIBUSB
+ libusb_exit(context->usb_ctx);
+#endif
+ free(context);
+ return JAYLINK_ERR;
+ }
+
+ if (LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) {
+#ifdef HAVE_LIBUSB
+ libusb_exit(context->usb_ctx);
+#endif
+ free(context);
+ return JAYLINK_ERR;
+ }
+#endif
+
+ context->devs = NULL;
+ context->discovered_devs = NULL;
+
+ /* Show error and warning messages by default. */
+ context->log_level = JAYLINK_LOG_LEVEL_WARNING;
+
+ context->log_callback = &log_vprintf;
+ context->log_callback_data = NULL;
+
+ ret = jaylink_log_set_domain(context, JAYLINK_LOG_DOMAIN_DEFAULT);
+
+ if (ret != JAYLINK_OK) {
+#ifdef HAVE_LIBUSB
+ libusb_exit(context->usb_ctx);
+#endif
+#ifdef _WIN32
+ WSACleanup();
+#endif
+ free(context);
+ return ret;
+ }
+
+ *ctx = context;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Shutdown libjaylink.
+ *
+ * @param[in,out] ctx libjaylink context.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_exit(struct jaylink_context *ctx)
+{
+ struct list *item;
+
+ if (!ctx)
+ return JAYLINK_ERR_ARG;
+
+ item = ctx->discovered_devs;
+
+ while (item) {
+ jaylink_unref_device((struct jaylink_device *)item->data);
+ item = item->next;
+ }
+
+ list_free(ctx->discovered_devs);
+ list_free(ctx->devs);
+
+#ifdef HAVE_LIBUSB
+ libusb_exit(ctx->usb_ctx);
+#endif
+#ifdef _WIN32
+ WSACleanup();
+#endif
+ free(ctx);
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Check for a capability of libjaylink.
+ *
+ * @param[in] cap Capability to check for.
+ *
+ * @retval true Capability is supported.
+ * @retval false Capability is not supported or invalid argument.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API bool jaylink_library_has_cap(enum jaylink_capability cap)
+{
+ switch (cap) {
+#ifdef HAVE_LIBUSB
+ case JAYLINK_CAP_HIF_USB:
+ return true;
+#endif
+ default:
+ return false;
+ }
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/device.c b/src/jtag/drivers/libjaylink/libjaylink/device.c
new file mode 100644
index 0000000..a3bddf6
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/device.c
@@ -0,0 +1,1707 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2016 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_LIBUSB
+#include <libusb.h>
+#endif
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Device enumeration and handling.
+ */
+
+/** @cond PRIVATE */
+#define CMD_GET_VERSION 0x01
+#define CMD_GET_HW_STATUS 0x07
+#define CMD_REGISTER 0x09
+#define CMD_GET_HW_INFO 0xc1
+#define CMD_GET_COUNTERS 0xc2
+#define CMD_GET_FREE_MEMORY 0xd4
+#define CMD_GET_CAPS 0xe8
+#define CMD_GET_EXT_CAPS 0xed
+#define CMD_GET_HW_VERSION 0xf0
+#define CMD_READ_CONFIG 0xf2
+#define CMD_WRITE_CONFIG 0xf3
+
+#define REG_CMD_REGISTER 0x64
+#define REG_CMD_UNREGISTER 0x65
+
+/** Size of the registration header in bytes. */
+#define REG_HEADER_SIZE 8
+/** Minimum registration information size in bytes. */
+#define REG_MIN_SIZE 0x4c
+/** Maximum registration information size in bytes. */
+#define REG_MAX_SIZE 0x200
+/** Size of a connection entry in bytes. */
+#define REG_CONN_INFO_SIZE 16
+/** @endcond */
+
+/** @private */
+JAYLINK_PRIV struct jaylink_device *device_allocate(
+ struct jaylink_context *ctx)
+{
+ struct jaylink_device *dev;
+ struct list *list;
+
+ dev = malloc(sizeof(struct jaylink_device));
+
+ if (!dev)
+ return NULL;
+
+ list = list_prepend(ctx->devs, dev);
+
+ if (!list) {
+ free(dev);
+ return NULL;
+ }
+
+ ctx->devs = list;
+
+ dev->ctx = ctx;
+ dev->ref_count = 1;
+
+ return dev;
+}
+
+static struct jaylink_device **allocate_device_list(size_t length)
+{
+ struct jaylink_device **list;
+
+ list = malloc(sizeof(struct jaylink_device *) * (length + 1));
+
+ if (!list)
+ return NULL;
+
+ list[length] = NULL;
+
+ return list;
+}
+
+/**
+ * Get available devices.
+ *
+ * @param[in,out] ctx libjaylink context.
+ * @param[out] devs Newly allocated array which contains instances of available
+ * devices on success, and undefined on failure. The array is
+ * NULL-terminated and must be free'd by the caller with
+ * jaylink_free_devices().
+ * @param[out] count Number of available devices on success, and undefined on
+ * failure. Can be NULL.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_MALLOC Memory allocation error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_discovery_scan()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_get_devices(struct jaylink_context *ctx,
+ struct jaylink_device ***devs, size_t *count)
+{
+ size_t num;
+ struct list *item;
+ struct jaylink_device **tmp;
+ struct jaylink_device *dev;
+ size_t i;
+
+ if (!ctx || !devs)
+ return JAYLINK_ERR_ARG;
+
+ num = list_length(ctx->discovered_devs);
+ tmp = allocate_device_list(num);
+
+ if (!tmp) {
+ log_err(ctx, "Failed to allocate device list.");
+ return JAYLINK_ERR_MALLOC;
+ }
+
+ item = ctx->discovered_devs;
+
+ for (i = 0; i < num; i++) {
+ dev = (struct jaylink_device *)item->data;
+ tmp[i] = jaylink_ref_device(dev);
+ item = item->next;
+ }
+
+ if (count)
+ *count = num;
+
+ *devs = tmp;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Free devices.
+ *
+ * @param[in,out] devs Array of device instances. Must be NULL-terminated.
+ * @param[in] unref Determines whether the device instances should be
+ * unreferenced.
+ *
+ * @see jaylink_get_devices()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API void jaylink_free_devices(struct jaylink_device **devs, bool unref)
+{
+ size_t i;
+
+ if (!devs)
+ return;
+
+ if (unref) {
+ for (i = 0; devs[i]; i++)
+ jaylink_unref_device(devs[i]);
+ }
+
+ free(devs);
+}
+
+/**
+ * Get the host interface of a device.
+ *
+ * @param[in] dev Device instance.
+ * @param[out] iface Host interface of the device on success, and undefined on
+ * failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_device_get_host_interface(
+ const struct jaylink_device *dev,
+ enum jaylink_host_interface *iface)
+{
+ if (!dev || !iface)
+ return JAYLINK_ERR_ARG;
+
+ *iface = dev->iface;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Get the serial number of a device.
+ *
+ * @note This serial number is for enumeration purpose only and might differ
+ * from the real serial number of the device.
+ *
+ * @param[in] dev Device instance.
+ * @param[out] serial_number Serial number of the device on success, and
+ * undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_NOT_AVAILABLE Serial number is not available.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_device_get_serial_number(
+ const struct jaylink_device *dev, uint32_t *serial_number)
+{
+ if (!dev || !serial_number)
+ return JAYLINK_ERR_ARG;
+
+ if (!dev->valid_serial_number)
+ return JAYLINK_ERR_NOT_AVAILABLE;
+
+ *serial_number = dev->serial_number;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Get the USB address of a device.
+ *
+ * @note Identification of a device with the USB address is deprecated and the
+ * serial number should be used instead.
+ *
+ * @param[in] dev Device instance.
+ * @param[out] address USB address of the device on success, and undefined on
+ * failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_NOT_SUPPORTED Supported for devices with host interface
+ * #JAYLINK_HIF_USB only.
+ *
+ * @see jaylink_device_get_serial_number()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_device_get_usb_address(
+ const struct jaylink_device *dev,
+ enum jaylink_usb_address *address)
+{
+ if (!dev || !address)
+ return JAYLINK_ERR_ARG;
+
+ if (dev->iface != JAYLINK_HIF_USB)
+ return JAYLINK_ERR_NOT_SUPPORTED;
+
+#ifdef HAVE_LIBUSB
+ *address = dev->usb_address;
+
+ return JAYLINK_OK;
+#else
+ return JAYLINK_ERR_NOT_SUPPORTED;
+#endif
+}
+
+/**
+ * Get the IPv4 address string of a device.
+ *
+ * @param[in] dev Device instance.
+ * @param[out] address IPv4 address string in quad-dotted decimal format of the
+ * device on success and undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_NOT_SUPPORTED Supported for devices with host interface
+ * #JAYLINK_HIF_TCP only.
+ *
+ * @since 0.2.0
+ */
+JAYLINK_API int jaylink_device_get_ipv4_address(
+ const struct jaylink_device *dev, char *address)
+{
+ if (!dev || !address)
+ return JAYLINK_ERR_ARG;
+
+ if (dev->iface != JAYLINK_HIF_TCP)
+ return JAYLINK_ERR_NOT_SUPPORTED;
+
+ memcpy(address, dev->ipv4_address, sizeof(dev->ipv4_address));
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Get the MAC address of a device.
+ *
+ * @param[in] dev Device instance.
+ * @param[out] address MAC address of the device on success and undefined on
+ * failure. The length of the MAC address is
+ * #JAYLINK_MAC_ADDRESS_LENGTH bytes.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_NOT_SUPPORTED Supported for devices with host interface
+ * #JAYLINK_HIF_TCP only.
+ * @retval JAYLINK_ERR_NOT_AVAILABLE MAC address is not available.
+ *
+ * @since 0.2.0
+ */
+JAYLINK_API int jaylink_device_get_mac_address(
+ const struct jaylink_device *dev, uint8_t *address)
+{
+ if (!dev || !address)
+ return JAYLINK_ERR_ARG;
+
+ if (dev->iface != JAYLINK_HIF_TCP)
+ return JAYLINK_ERR_NOT_SUPPORTED;
+
+ if (!dev->has_mac_address)
+ return JAYLINK_ERR_NOT_AVAILABLE;
+
+ memcpy(address, dev->mac_address, sizeof(dev->mac_address));
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Get the hardware version of a device.
+ *
+ * @note The hardware type can not be obtained by this function, use
+ * jaylink_get_hardware_version() instead.
+ *
+ * @param[in] dev Device instance.
+ * @param[out] version Hardware version of the device on success and undefined
+ * on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_NOT_SUPPORTED Supported for devices with host interface
+ * #JAYLINK_HIF_TCP only.
+ * @retval JAYLINK_ERR_NOT_AVAILABLE Hardware version is not available.
+ *
+ * @since 0.2.0
+ */
+JAYLINK_API int jaylink_device_get_hardware_version(
+ const struct jaylink_device *dev,
+ struct jaylink_hardware_version *version)
+{
+ if (!dev || !version)
+ return JAYLINK_ERR_ARG;
+
+ if (dev->iface != JAYLINK_HIF_TCP)
+ return JAYLINK_ERR_NOT_SUPPORTED;
+
+ if (!dev->has_hw_version)
+ return JAYLINK_ERR_NOT_AVAILABLE;
+
+ *version = dev->hw_version;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Get the product name of a device.
+ *
+ * @param[in] dev Device instance.
+ * @param[out] name Product name of the device on success and undefined on
+ * failure. The maximum length of the product name is
+ * #JAYLINK_PRODUCT_NAME_MAX_LENGTH bytes.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_NOT_SUPPORTED Supported for devices with host interface
+ * #JAYLINK_HIF_TCP only.
+ * @retval JAYLINK_ERR_NOT_AVAILABLE Product name is not available.
+ *
+ * @since 0.2.0
+ */
+JAYLINK_API int jaylink_device_get_product_name(
+ const struct jaylink_device *dev, char *name)
+{
+ if (!dev || !name)
+ return JAYLINK_ERR_ARG;
+
+ if (dev->iface != JAYLINK_HIF_TCP)
+ return JAYLINK_ERR_NOT_SUPPORTED;
+
+ if (!dev->has_product_name)
+ return JAYLINK_ERR_NOT_AVAILABLE;
+
+ memcpy(name, dev->product_name, sizeof(dev->product_name));
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Get the nickname of a device.
+ *
+ * @param[in] dev Device instance.
+ * @param[out] nickname Nickname of the device on success and undefined on
+ * failure. The maximum length of the nickname is
+ * #JAYLINK_NICKNAME_MAX_LENGTH bytes.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_NOT_SUPPORTED Supported for devices with host interface
+ * #JAYLINK_HIF_TCP only.
+ * @retval JAYLINK_ERR_NOT_AVAILABLE Nickname is not available.
+ *
+ * @since 0.2.0
+ */
+JAYLINK_API int jaylink_device_get_nickname(const struct jaylink_device *dev,
+ char *nickname)
+{
+ if (!dev || !nickname)
+ return JAYLINK_ERR_ARG;
+
+ if (dev->iface != JAYLINK_HIF_TCP)
+ return JAYLINK_ERR_NOT_SUPPORTED;
+
+ if (!dev->has_nickname)
+ return JAYLINK_ERR_NOT_AVAILABLE;
+
+ memcpy(nickname, dev->nickname, sizeof(dev->nickname));
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Increment the reference count of a device.
+ *
+ * @param[in,out] dev Device instance.
+ *
+ * @return The given device instance on success, or NULL on invalid argument.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API struct jaylink_device *jaylink_ref_device(
+ struct jaylink_device *dev)
+{
+ if (!dev)
+ return NULL;
+
+ dev->ref_count++;
+
+ return dev;
+}
+
+/**
+ * Decrement the reference count of a device.
+ *
+ * @param[in,out] dev Device instance.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API void jaylink_unref_device(struct jaylink_device *dev)
+{
+ struct jaylink_context *ctx;
+
+ if (!dev)
+ return;
+
+ dev->ref_count--;
+
+ if (!dev->ref_count) {
+ ctx = dev->ctx;
+ ctx->devs = list_remove(dev->ctx->devs, dev);
+
+ if (dev->iface == JAYLINK_HIF_USB) {
+#ifdef HAVE_LIBUSB
+ log_dbg(ctx, "Device destroyed (bus:address = "
+ "%03u:%03u).",
+ libusb_get_bus_number(dev->usb_dev),
+ libusb_get_device_address(dev->usb_dev));
+
+ libusb_unref_device(dev->usb_dev);
+#endif
+ } else if (dev->iface == JAYLINK_HIF_TCP) {
+ log_dbg(ctx, "Device destroyed (IPv4 address = %s).",
+ dev->ipv4_address);
+ } else {
+ log_err(ctx, "BUG: Invalid host interface: %u.",
+ dev->iface);
+ }
+
+ free(dev);
+ }
+}
+
+static struct jaylink_device_handle *allocate_device_handle(
+ struct jaylink_device *dev)
+{
+ struct jaylink_device_handle *devh;
+
+ devh = malloc(sizeof(struct jaylink_device_handle));
+
+ if (!devh)
+ return NULL;
+
+ devh->dev = jaylink_ref_device(dev);
+
+ return devh;
+}
+
+static void free_device_handle(struct jaylink_device_handle *devh)
+{
+ jaylink_unref_device(devh->dev);
+ free(devh);
+}
+
+/**
+ * Open a device.
+ *
+ * @param[in,out] dev Device instance.
+ * @param[out] devh Newly allocated handle for the opened device on success,
+ * and undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_MALLOC Memory allocation error.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_open(struct jaylink_device *dev,
+ struct jaylink_device_handle **devh)
+{
+ int ret;
+ struct jaylink_device_handle *handle;
+
+ if (!dev || !devh)
+ return JAYLINK_ERR_ARG;
+
+ handle = allocate_device_handle(dev);
+
+ if (!handle) {
+ log_err(dev->ctx, "Device handle malloc failed.");
+ return JAYLINK_ERR_MALLOC;
+ }
+
+ ret = transport_open(handle);
+
+ if (ret != JAYLINK_OK) {
+ free_device_handle(handle);
+ return ret;
+ }
+
+ *devh = handle;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Close a device.
+ *
+ * @param[in,out] devh Device instance.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_close(struct jaylink_device_handle *devh)
+{
+ int ret;
+
+ if (!devh)
+ return JAYLINK_ERR_ARG;
+
+ ret = transport_close(devh);
+ free_device_handle(devh);
+
+ return ret;
+}
+
+/**
+ * Get the device instance from a device handle.
+ *
+ * @note The reference count of the device instance is not increased.
+ *
+ * @param[in] devh Device handle.
+ *
+ * @return The device instance on success, or NULL on invalid argument.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API struct jaylink_device *jaylink_get_device(
+ struct jaylink_device_handle *devh)
+{
+ if (!devh)
+ return NULL;
+
+ return devh->dev;
+}
+
+/**
+ * Retrieve the firmware version of a device.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] version Newly allocated string which contains the firmware
+ * version on success, and undefined if @p length is zero
+ * or on failure. The string is null-terminated and must be
+ * free'd by the caller.
+ * @param[out] length Length of the firmware version string including trailing
+ * null-terminator on success, and undefined on failure.
+ * Zero if no firmware version string is available.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_MALLOC Memory allocation error.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_get_firmware_version(
+ struct jaylink_device_handle *devh, char **version,
+ size_t *length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[2];
+ uint16_t dummy;
+ char *tmp;
+
+ if (!devh || !version || !length)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 1, 2, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_GET_VERSION;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 2);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ dummy = buffer_get_u16(buf, 0);
+ *length = dummy;
+
+ if (!dummy)
+ return JAYLINK_OK;
+
+ ret = transport_start_read(devh, dummy);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ tmp = malloc(dummy);
+
+ if (!tmp) {
+ log_err(ctx, "Firmware version string malloc failed.");
+ return JAYLINK_ERR_MALLOC;
+ }
+
+ ret = transport_read(devh, (uint8_t *)tmp, dummy);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ free(tmp);
+ return ret;
+ }
+
+ /* Last byte is reserved for null-terminator. */
+ tmp[dummy - 1] = 0;
+ *version = tmp;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve the hardware information of a device.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_GET_HW_INFO capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] mask A bit field where each set bit represents hardware
+ * information to request. See #jaylink_hardware_info for a
+ * description of the hardware information and their bit
+ * positions.
+ * @param[out] info Array to store the hardware information on success. Its
+ * content is undefined on failure. The array must be large
+ * enough to contain at least as many elements as bits set in
+ * @a mask.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_get_hardware_info(struct jaylink_device_handle *devh,
+ uint32_t mask, uint32_t *info)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[5];
+ unsigned int i;
+ unsigned int num;
+ unsigned int length;
+
+ if (!devh || !mask || !info)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ num = 0;
+
+ for (i = 0; i < 32; i++) {
+ if (mask & (1 << i))
+ num++;
+ }
+
+ length = num * sizeof(uint32_t);
+
+ ret = transport_start_write_read(devh, 5, length, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_GET_HW_INFO;
+ buffer_set_u32(buf, mask, 1);
+
+ ret = transport_write(devh, buf, 5);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, (uint8_t *)info, length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ for (i = 0; i < num; i++)
+ info[i] = buffer_get_u32((uint8_t *)info,
+ i * sizeof(uint32_t));
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve the counter values of a device.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_GET_COUNTERS capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] mask A bit field where each set bit represents a counter value to
+ * request. See #jaylink_counter for a description of the
+ * counters and their bit positions.
+ * @param[out] values Array to store the counter values on success. Its content
+ * is undefined on failure. The array must be large enough
+ * to contain at least as many elements as bits set in @p
+ * mask.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.2.0
+ */
+JAYLINK_API int jaylink_get_counters(struct jaylink_device_handle *devh,
+ uint32_t mask, uint32_t *values)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[5];
+ unsigned int i;
+ unsigned int num;
+ unsigned int length;
+
+ if (!devh || !mask || !values)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ num = 0;
+
+ for (i = 0; i < 32; i++) {
+ if (mask & (1 << i))
+ num++;
+ }
+
+ length = num * sizeof(uint32_t);
+ ret = transport_start_write_read(devh, 5, length, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_GET_COUNTERS;
+ buffer_set_u32(buf, mask, 1);
+
+ ret = transport_write(devh, buf, 5);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, (uint8_t *)values, length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ for (i = 0; i < num; i++)
+ values[i] = buffer_get_u32((uint8_t *)values,
+ i * sizeof(uint32_t));
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve the hardware version of a device.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_GET_HW_VERSION capability.
+ *
+ * @warning This function may return a value for @p version where
+ * #jaylink_hardware_version::type is not covered by
+ * #jaylink_hardware_type.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] version Hardware version on success, and undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_get_hardware_version(
+ struct jaylink_device_handle *devh,
+ struct jaylink_hardware_version *version)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[4];
+ uint32_t tmp;
+
+ if (!devh || !version)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 1, 4, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_GET_HW_VERSION;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ tmp = buffer_get_u32(buf, 0);
+
+ version->type = (tmp / 1000000) % 100;
+ version->major = (tmp / 10000) % 100;
+ version->minor = (tmp / 100) % 100;
+ version->revision = tmp % 100;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve the hardware status of a device.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] status Hardware status on success, and undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_get_hardware_status(struct jaylink_device_handle *devh,
+ struct jaylink_hardware_status *status)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[8];
+
+ if (!devh || !status)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 1, 8, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_GET_HW_STATUS;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 8);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ status->target_voltage = buffer_get_u16(buf, 0);
+ status->tck = buf[2];
+ status->tdi = buf[3];
+ status->tdo = buf[4];
+ status->tms = buf[5];
+ status->tres = buf[6];
+ status->trst = buf[7];
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve the capabilities of a device.
+ *
+ * The capabilities are stored in a 32-bit bit array consisting of
+ * #JAYLINK_DEV_CAPS_SIZE bytes where each individual bit represents a
+ * capability. The first bit of this array is the least significant bit of the
+ * first byte and the following bits are sequentially numbered in order of
+ * increasing bit significance and byte index. A set bit indicates a supported
+ * capability. See #jaylink_device_capability for a description of the
+ * capabilities and their bit positions.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] caps Buffer to store capabilities on success. Its content is
+ * undefined on failure. The buffer must be large enough to
+ * contain at least #JAYLINK_DEV_CAPS_SIZE bytes.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_get_extended_caps()
+ * @see jaylink_has_cap()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_get_caps(struct jaylink_device_handle *devh,
+ uint8_t *caps)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[1];
+
+ if (!devh || !caps)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 1, JAYLINK_DEV_CAPS_SIZE, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_GET_CAPS;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, caps, JAYLINK_DEV_CAPS_SIZE);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve the extended capabilities of a device.
+ *
+ * The extended capabilities are stored in a 256-bit bit array consisting of
+ * #JAYLINK_DEV_EXT_CAPS_SIZE bytes. See jaylink_get_caps() for a further
+ * description of how the capabilities are represented in this bit array. For a
+ * description of the capabilities and their bit positions, see
+ * #jaylink_device_capability.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_GET_EXT_CAPS capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] caps Buffer to store capabilities on success. Its content is
+ * undefined on failure. The buffer must be large enough to
+ * contain at least #JAYLINK_DEV_EXT_CAPS_SIZE bytes.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_get_caps()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_get_extended_caps(struct jaylink_device_handle *devh,
+ uint8_t *caps)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[1];
+
+ if (!devh || !caps)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 1, JAYLINK_DEV_EXT_CAPS_SIZE,
+ true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_GET_EXT_CAPS;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, caps, JAYLINK_DEV_EXT_CAPS_SIZE);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve the size of free memory of a device.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_GET_FREE_MEMORY capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] size Size of free memory in bytes on success, and undefined on
+ * failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_get_free_memory(struct jaylink_device_handle *devh,
+ uint32_t *size)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[4];
+
+ if (!devh || !size)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 1, 4, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_GET_FREE_MEMORY;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ *size = buffer_get_u32(buf, 0);
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Read the raw configuration data of a device.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_READ_CONFIG capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] config Buffer to store configuration data on success. Its
+ * content is undefined on failure. The buffer must be large
+ * enough to contain at least
+ * #JAYLINK_DEV_CONFIG_SIZE bytes.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_read_raw_config(struct jaylink_device_handle *devh,
+ uint8_t *config)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[1];
+
+ if (!devh || !config)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 1, JAYLINK_DEV_CONFIG_SIZE,
+ true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_READ_CONFIG;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, config, JAYLINK_DEV_CONFIG_SIZE);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Write the raw configuration data of a device.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_WRITE_CONFIG capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] config Buffer to write configuration data from. The size of the
+ * configuration data is expected to be
+ * #JAYLINK_DEV_CONFIG_SIZE bytes.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_write_raw_config(struct jaylink_device_handle *devh,
+ const uint8_t *config)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[1];
+
+ if (!devh || !config)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 1 + JAYLINK_DEV_CONFIG_SIZE, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_WRITE_CONFIG;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_write(devh, config, JAYLINK_DEV_CONFIG_SIZE);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
+
+static void parse_conn_table(struct jaylink_connection *conns,
+ const uint8_t *buffer, uint16_t num, uint16_t entry_size)
+{
+ unsigned int i;
+ size_t offset;
+ struct in_addr in;
+
+ offset = 0;
+
+ for (i = 0; i < num; i++) {
+ conns[i].pid = buffer_get_u32(buffer, offset);
+
+ in.s_addr = buffer_get_u32(buffer, offset + 4);
+ /*
+ * Use inet_ntoa() instead of inet_ntop() because the latter
+ * requires at least Windows Vista.
+ */
+ strcpy(conns[i].hid, inet_ntoa(in));
+
+ conns[i].iid = buffer[offset + 8];
+ conns[i].cid = buffer[offset + 9];
+ conns[i].handle = buffer_get_u16(buffer, offset + 10);
+ conns[i].timestamp = buffer_get_u32(buffer, offset + 12);
+ offset = offset + entry_size;
+ }
+}
+
+static bool _inet_pton(const char *str, struct in_addr *in)
+{
+#ifdef _WIN32
+ int ret;
+ struct sockaddr_in sock_in;
+ int length;
+
+ length = sizeof(sock_in);
+
+ /*
+ * Use WSAStringToAddress() instead of inet_pton() because the latter
+ * requires at least Windows Vista.
+ */
+ ret = WSAStringToAddress((LPTSTR)str, AF_INET, NULL,
+ (LPSOCKADDR)&sock_in, &length);
+
+ if (ret != 0)
+ return false;
+
+ *in = sock_in.sin_addr;
+#else
+ if (inet_pton(AF_INET, str, in) != 1)
+ return false;
+#endif
+
+ return true;
+}
+
+/**
+ * Register a connection on a device.
+ *
+ * A connection can be registered by using 0 as handle. Additional information
+ * about the connection can be attached whereby the timestamp is a read-only
+ * value and therefore ignored for registration. On success, a new handle
+ * greater than 0 is obtained from the device.
+ *
+ * However, if an obtained handle does not appear in the list of device
+ * connections, the connection was not registered because the maximum number of
+ * connections on the device is reached.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_REGISTER capability.
+ *
+ * Example code:
+ * @code{.c}
+ * static bool register_connection(struct jaylink_device_handle *devh,
+ * struct jaylink_connection *conn)
+ * {
+ * int ret;
+ * struct jaylink_connection conns[JAYLINK_MAX_CONNECTIONS];
+ * bool found_handle;
+ * size_t count;
+ * size_t i;
+ *
+ * conn->handle = 0;
+ * conn->pid = 0;
+ * strcpy(conn->hid, "0.0.0.0");
+ * conn->iid = 0;
+ * conn->cid = 0;
+ *
+ * ret = jaylink_register(devh, conn, conns, &count);
+ *
+ * if (ret != JAYLINK_OK) {
+ * printf("jaylink_register() failed: %s.\n",
+ * jaylink_strerror(ret));
+ * return false;
+ * }
+ *
+ * found_handle = false;
+ *
+ * for (i = 0; i < count; i++) {
+ * if (conns[i].handle == conn->handle) {
+ * found_handle = true;
+ * break;
+ * }
+ * }
+ *
+ * if (!found_handle) {
+ * printf("Maximum number of connections reached.\n");
+ * return false;
+ * }
+ *
+ * printf("Connection successfully registered.\n");
+ *
+ * return true;
+ * }
+ * @endcode
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in,out] connection Connection to register on the device.
+ * @param[out] connections Array to store device connections on success.
+ * Its content is undefined on failure. The array must
+ * be large enough to contain at least
+ * #JAYLINK_MAX_CONNECTIONS elements.
+ * @param[out] count Number of device connections on success, and undefined on
+ * failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_PROTO Protocol violation.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_unregister()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_register(struct jaylink_device_handle *devh,
+ struct jaylink_connection *connection,
+ struct jaylink_connection *connections, size_t *count)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[REG_MAX_SIZE];
+ uint16_t handle;
+ uint16_t num;
+ uint16_t entry_size;
+ uint32_t size;
+ uint32_t table_size;
+ uint16_t info_size;
+ struct in_addr in;
+
+ if (!devh || !connection || !connections || !count)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+
+ buf[0] = CMD_REGISTER;
+ buf[1] = REG_CMD_REGISTER;
+ buffer_set_u32(buf, connection->pid, 2);
+
+ if (!_inet_pton(connection->hid, &in))
+ return JAYLINK_ERR_ARG;
+
+ buffer_set_u32(buf, in.s_addr, 6);
+
+ buf[10] = connection->iid;
+ buf[11] = connection->cid;
+ buffer_set_u16(buf, connection->handle, 12);
+
+ ret = transport_start_write_read(devh, 14, REG_MIN_SIZE, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_write(devh, buf, 14);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, REG_MIN_SIZE);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ handle = buffer_get_u16(buf, 0);
+ num = buffer_get_u16(buf, 2);
+ entry_size = buffer_get_u16(buf, 4);
+ info_size = buffer_get_u16(buf, 6);
+
+ if (num > JAYLINK_MAX_CONNECTIONS) {
+ log_err(ctx, "Maximum number of device connections exceeded: "
+ "%u.", num);
+ return JAYLINK_ERR_PROTO;
+ }
+
+ if (entry_size != REG_CONN_INFO_SIZE) {
+ log_err(ctx, "Invalid connection entry size: %u bytes.",
+ entry_size);
+ return JAYLINK_ERR_PROTO;
+ }
+
+ table_size = num * entry_size;
+ size = REG_HEADER_SIZE + table_size + info_size;
+
+ if (size > REG_MAX_SIZE) {
+ log_err(ctx, "Maximum registration information size exceeded: "
+ "%u bytes.", size);
+ return JAYLINK_ERR_PROTO;
+ }
+
+ if (size > REG_MIN_SIZE) {
+ ret = transport_start_read(devh, size - REG_MIN_SIZE);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_read() failed: %s.",
+ jaylink_strerror(ret));
+ return JAYLINK_ERR;
+ }
+
+ ret = transport_read(devh, buf + REG_MIN_SIZE,
+ size - REG_MIN_SIZE);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return JAYLINK_ERR;
+ }
+ }
+
+ if (!handle) {
+ log_err(ctx, "Obtained invalid connection handle.");
+ return JAYLINK_ERR_PROTO;
+ }
+
+ connection->handle = handle;
+ parse_conn_table(connections, buf + REG_HEADER_SIZE, num, entry_size);
+
+ *count = num;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Unregister a connection from a device.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_REGISTER capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in,out] connection Connection to unregister from the device.
+ * @param[out] connections Array to store device connections on success.
+ * Its content is undefined on failure. The array must
+ * be large enough to contain at least
+ * #JAYLINK_MAX_CONNECTIONS elements.
+ * @param[out] count Number of device connections on success, and undefined on
+ * failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_PROTO Protocol violation.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_register()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_unregister(struct jaylink_device_handle *devh,
+ const struct jaylink_connection *connection,
+ struct jaylink_connection *connections, size_t *count)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[REG_MAX_SIZE];
+ uint16_t num;
+ uint16_t entry_size;
+ uint32_t size;
+ uint32_t table_size;
+ uint16_t info_size;
+ struct in_addr in;
+
+ if (!devh || !connection || !connections || !count)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+
+ buf[0] = CMD_REGISTER;
+ buf[1] = REG_CMD_UNREGISTER;
+ buffer_set_u32(buf, connection->pid, 2);
+
+ if (!_inet_pton(connection->hid, &in))
+ return JAYLINK_ERR_ARG;
+
+ buffer_set_u32(buf, in.s_addr, 6);
+
+ buf[10] = connection->iid;
+ buf[11] = connection->cid;
+ buffer_set_u16(buf, connection->handle, 12);
+
+ ret = transport_start_write_read(devh, 14, REG_MIN_SIZE, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_write(devh, buf, 14);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, REG_MIN_SIZE);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ num = buffer_get_u16(buf, 2);
+ entry_size = buffer_get_u16(buf, 4);
+ info_size = buffer_get_u16(buf, 6);
+
+ if (num > JAYLINK_MAX_CONNECTIONS) {
+ log_err(ctx, "Maximum number of device connections exceeded: "
+ "%u.", num);
+ return JAYLINK_ERR_PROTO;
+ }
+
+ if (entry_size != REG_CONN_INFO_SIZE) {
+ log_err(ctx, "Invalid connection entry size: %u bytes.",
+ entry_size);
+ return JAYLINK_ERR_PROTO;
+ }
+
+ table_size = num * entry_size;
+ size = REG_HEADER_SIZE + table_size + info_size;
+
+ if (size > REG_MAX_SIZE) {
+ log_err(ctx, "Maximum registration information size exceeded: "
+ "%u bytes.", size);
+ return JAYLINK_ERR_PROTO;
+ }
+
+ if (size > REG_MIN_SIZE) {
+ ret = transport_start_read(devh, size - REG_MIN_SIZE);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_read() failed: %s.",
+ jaylink_strerror(ret));
+ return JAYLINK_ERR;
+ }
+
+ ret = transport_read(devh, buf + REG_MIN_SIZE,
+ size - REG_MIN_SIZE);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return JAYLINK_ERR;
+ }
+ }
+
+ parse_conn_table(connections, buf + REG_HEADER_SIZE, num, entry_size);
+
+ *count = num;
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/discovery.c b/src/jtag/drivers/libjaylink/libjaylink/discovery.c
new file mode 100644
index 0000000..1ac96e7
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/discovery.c
@@ -0,0 +1,106 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2016 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Device discovery.
+ */
+
+static void clear_discovery_list(struct jaylink_context *ctx)
+{
+ struct list *item;
+ struct list *tmp;
+ struct jaylink_device *dev;
+
+ item = ctx->discovered_devs;
+
+ while (item) {
+ dev = (struct jaylink_device *)item->data;
+ jaylink_unref_device(dev);
+
+ tmp = item;
+ item = item->next;
+ free(tmp);
+ }
+
+ ctx->discovered_devs = NULL;
+}
+
+/**
+ * Scan for devices.
+ *
+ * @param[in,out] ctx libjaylink context.
+ * @param[in] ifaces Host interfaces to scan for devices. Use bitwise OR to
+ * specify multiple interfaces, or 0 to use all available
+ * interfaces. See #jaylink_host_interface for a description
+ * of the interfaces.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_get_devices()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_discovery_scan(struct jaylink_context *ctx,
+ uint32_t ifaces)
+{
+ int ret;
+
+ if (!ctx)
+ return JAYLINK_ERR_ARG;
+
+ if (!ifaces)
+ ifaces = JAYLINK_HIF_USB | JAYLINK_HIF_TCP;
+
+ clear_discovery_list(ctx);
+
+#ifdef HAVE_LIBUSB
+ if (ifaces & JAYLINK_HIF_USB) {
+ ret = discovery_usb_scan(ctx);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "USB device discovery failed.");
+ return ret;
+ }
+ }
+#endif
+
+ if (ifaces & JAYLINK_HIF_TCP) {
+ ret = discovery_tcp_scan(ctx);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "TCP/IP device discovery failed.");
+ return ret;
+ }
+ }
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/discovery_tcp.c b/src/jtag/drivers/libjaylink/libjaylink/discovery_tcp.c
new file mode 100644
index 0000000..002fa67
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/discovery_tcp.c
@@ -0,0 +1,349 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2015-2017 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Device discovery (TCP/IP).
+ */
+
+/** @cond PRIVATE */
+/** Size of the advertisement message in bytes. */
+#define ADV_MESSAGE_SIZE 128
+
+/** Device discovery port number. */
+#define DISC_PORT 19020
+
+/** Size of the discovery message in bytes. */
+#define DISC_MESSAGE_SIZE 64
+
+/** Discovery timeout in milliseconds. */
+#define DISC_TIMEOUT 20
+/** @endcond */
+
+static bool compare_devices(const void *a, const void *b)
+{
+ const struct jaylink_device *dev;
+ const struct jaylink_device *new_dev;
+
+ dev = a;
+ new_dev = b;
+
+ if (dev->iface != JAYLINK_HIF_TCP)
+ return false;
+
+ if (memcmp(dev->ipv4_address, new_dev->ipv4_address,
+ sizeof(dev->ipv4_address)) != 0)
+ return false;
+
+ if (dev->serial_number != new_dev->serial_number)
+ return false;
+
+ if (memcmp(dev->mac_address, new_dev->mac_address,
+ sizeof(dev->mac_address)) != 0)
+ return false;
+
+ if (strcmp(dev->product_name, new_dev->product_name) != 0)
+ return false;
+
+ if (strcmp(dev->nickname, new_dev->nickname) != 0)
+ return false;
+
+ if (dev->hw_version.type != new_dev->hw_version.type)
+ return false;
+
+ if (dev->hw_version.major != new_dev->hw_version.major)
+ return false;
+
+ if (dev->hw_version.minor != new_dev->hw_version.minor)
+ return false;
+
+ if (dev->hw_version.revision != new_dev->hw_version.revision)
+ return false;
+
+ return true;
+}
+
+static struct jaylink_device *find_device(struct list *list,
+ const struct jaylink_device *dev)
+{
+ struct list *item;
+
+ item = list_find_custom(list, &compare_devices, dev);
+
+ if (item)
+ return item->data;
+
+ return NULL;
+}
+
+static bool parse_adv_message(struct jaylink_device *dev,
+ const uint8_t *buffer)
+{
+ struct in_addr in;
+ uint32_t tmp;
+
+ if (memcmp(buffer, "Found", 5) != 0)
+ return false;
+
+ /*
+ * Use inet_ntoa() instead of inet_ntop() because the latter requires
+ * at least Windows Vista.
+ */
+ memcpy(&in, buffer + 16, 4);
+ memcpy(dev->ipv4_address, inet_ntoa(in), sizeof(dev->ipv4_address));
+
+ memcpy(dev->mac_address, buffer + 32, sizeof(dev->mac_address));
+ dev->has_mac_address = true;
+
+ dev->serial_number = buffer_get_u32(buffer, 48);
+ dev->valid_serial_number = true;
+
+ tmp = buffer_get_u32(buffer, 52);
+ dev->hw_version.type = (tmp / 1000000) % 100;
+ dev->hw_version.major = (tmp / 10000) % 100;
+ dev->hw_version.minor = (tmp / 100) % 100;
+ dev->hw_version.revision = tmp % 100;
+ dev->has_hw_version = true;
+
+ memcpy(dev->product_name, buffer + 64, sizeof(dev->product_name));
+ dev->product_name[JAYLINK_PRODUCT_NAME_MAX_LENGTH - 1] = '\0';
+ dev->has_product_name = isprint((unsigned char)dev->product_name[0]);
+
+ memcpy(dev->nickname, buffer + 96, sizeof(dev->nickname));
+ dev->nickname[JAYLINK_NICKNAME_MAX_LENGTH - 1] = '\0';
+ dev->has_nickname = isprint((unsigned char)dev->nickname[0]);
+
+ return true;
+}
+
+static struct jaylink_device *probe_device(struct jaylink_context *ctx,
+ struct sockaddr_in *addr, const uint8_t *buffer)
+{
+ struct jaylink_device tmp;
+ struct jaylink_device *dev;
+
+ /*
+ * Use inet_ntoa() instead of inet_ntop() because the latter requires
+ * at least Windows Vista.
+ */
+ log_dbg(ctx, "Received advertisement message (IPv4 address = %s).",
+ inet_ntoa(addr->sin_addr));
+
+ if (!parse_adv_message(&tmp, buffer)) {
+ log_dbg(ctx, "Received invalid advertisement message.");
+ return NULL;
+ }
+
+ log_dbg(ctx, "Found device (IPv4 address = %s).", tmp.ipv4_address);
+ log_dbg(ctx, "Device: MAC address = %02x:%02x:%02x:%02x:%02x:%02x.",
+ tmp.mac_address[0], tmp.mac_address[1], tmp.mac_address[2],
+ tmp.mac_address[3], tmp.mac_address[4], tmp.mac_address[5]);
+ log_dbg(ctx, "Device: Serial number = %u.", tmp.serial_number);
+
+ if (tmp.has_product_name)
+ log_dbg(ctx, "Device: Product = %s.", tmp.product_name);
+
+ if (tmp.has_nickname)
+ log_dbg(ctx, "Device: Nickname = %s.", tmp.nickname);
+
+ dev = find_device(ctx->discovered_devs, &tmp);
+
+ if (dev) {
+ log_dbg(ctx, "Ignoring already discovered device.");
+ return NULL;
+ }
+
+ dev = find_device(ctx->devs, &tmp);
+
+ if (dev) {
+ log_dbg(ctx, "Using existing device instance.");
+ return jaylink_ref_device(dev);
+ }
+
+ log_dbg(ctx, "Allocating new device instance.");
+
+ dev = device_allocate(ctx);
+
+ if (!dev) {
+ log_warn(ctx, "Device instance malloc failed.");
+ return NULL;
+ }
+
+ dev->iface = JAYLINK_HIF_TCP;
+
+ dev->serial_number = tmp.serial_number;
+ dev->valid_serial_number = tmp.valid_serial_number;
+
+ memcpy(dev->ipv4_address, tmp.ipv4_address, sizeof(dev->ipv4_address));
+
+ memcpy(dev->mac_address, tmp.mac_address, sizeof(dev->mac_address));
+ dev->has_mac_address = tmp.has_mac_address;
+
+ memcpy(dev->product_name, tmp.product_name, sizeof(dev->product_name));
+ dev->has_product_name = tmp.has_product_name;
+
+ memcpy(dev->nickname, tmp.nickname, sizeof(dev->nickname));
+ dev->has_nickname = tmp.has_nickname;
+
+ dev->hw_version = tmp.hw_version;
+ dev->has_hw_version = tmp.has_hw_version;
+
+ return dev;
+}
+
+/** @private */
+JAYLINK_PRIV int discovery_tcp_scan(struct jaylink_context *ctx)
+{
+ int ret;
+ int sock;
+ int opt_value;
+ fd_set rfds;
+ struct sockaddr_in addr;
+ size_t addr_length;
+ struct timeval timeout;
+ uint8_t buf[ADV_MESSAGE_SIZE];
+ struct jaylink_device *dev;
+ size_t length;
+ size_t num_devs;
+
+ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ if (sock < 0) {
+ log_err(ctx, "Failed to create discovery socket.");
+ return JAYLINK_ERR;
+ }
+
+ opt_value = true;
+
+ if (!socket_set_option(sock, SOL_SOCKET, SO_BROADCAST, &opt_value,
+ sizeof(opt_value))) {
+ log_err(ctx, "Failed to enable broadcast option for discovery "
+ "socket.");
+ socket_close(sock);
+ return JAYLINK_ERR;
+ }
+
+ memset(&addr, 0, sizeof(struct sockaddr_in));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(DISC_PORT);
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ if (!socket_bind(sock, (struct sockaddr *)&addr,
+ sizeof(struct sockaddr_in))) {
+ log_err(ctx, "Failed to bind discovery socket.");
+ socket_close(sock);
+ return JAYLINK_ERR;
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(DISC_PORT);
+ addr.sin_addr.s_addr = INADDR_BROADCAST;
+
+ memset(buf, 0, DISC_MESSAGE_SIZE);
+ memcpy(buf, "Discover", 8);
+
+ log_dbg(ctx, "Sending discovery message.");
+
+ length = DISC_MESSAGE_SIZE;
+
+ if (!socket_sendto(sock, (char *)buf, &length, 0,
+ (const struct sockaddr *)&addr, sizeof(addr))) {
+ log_err(ctx, "Failed to send discovery message.");
+ socket_close(sock);
+ return JAYLINK_ERR_IO;
+ }
+
+ if (length < DISC_MESSAGE_SIZE) {
+ log_err(ctx, "Only sent %zu bytes of discovery message.",
+ length);
+ socket_close(sock);
+ return JAYLINK_ERR_IO;
+ }
+
+ timeout.tv_sec = DISC_TIMEOUT / 1000;
+ timeout.tv_usec = (DISC_TIMEOUT % 1000) * 1000;
+
+ num_devs = 0;
+
+ while (true) {
+ FD_ZERO(&rfds);
+ FD_SET(sock, &rfds);
+
+ ret = select(sock + 1, &rfds, NULL, NULL, &timeout);
+
+ if (ret <= 0)
+ break;
+
+ if (!FD_ISSET(sock, &rfds))
+ continue;
+
+ length = ADV_MESSAGE_SIZE;
+ addr_length = sizeof(struct sockaddr_in);
+
+ if (!socket_recvfrom(sock, buf, &length, 0,
+ (struct sockaddr *)&addr, &addr_length)) {
+ log_warn(ctx, "Failed to receive advertisement "
+ "message.");
+ continue;
+ }
+
+ /*
+ * Filter out messages with an invalid size. This includes the
+ * broadcast message we sent before.
+ */
+ if (length != ADV_MESSAGE_SIZE)
+ continue;
+
+ dev = probe_device(ctx, &addr, buf);
+
+ if (dev) {
+ ctx->discovered_devs = list_prepend(
+ ctx->discovered_devs, dev);
+ num_devs++;
+ }
+ }
+
+ socket_close(sock);
+
+ if (ret < 0) {
+ log_err(ctx, "select() failed.");
+ return JAYLINK_ERR;
+ }
+
+ log_dbg(ctx, "Found %zu TCP/IP device(s).", num_devs);
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/discovery_usb.c b/src/jtag/drivers/libjaylink/libjaylink/discovery_usb.c
new file mode 100644
index 0000000..48d5322
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/discovery_usb.c
@@ -0,0 +1,280 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2016 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/*
+ * libusb.h includes windows.h and therefore must be included after anything
+ * that includes winsock2.h.
+ */
+#include <libusb.h>
+
+/**
+ * @file
+ *
+ * Device discovery (USB).
+ */
+
+/** @cond PRIVATE */
+/** USB Vendor ID (VID) of SEGGER products. */
+#define USB_VENDOR_ID 0x1366
+
+/* USB Product IDs (PID) and their corresponding USB addresses. */
+static const uint16_t pids[][2] = {
+ {0x0101, 0},
+ {0x0102, 1},
+ {0x0103, 2},
+ {0x0104, 3},
+ {0x0105, 0},
+ {0x0107, 0},
+ {0x0108, 0},
+ {0x1010, 0},
+ {0x1011, 0},
+ {0x1012, 0},
+ {0x1013, 0},
+ {0x1014, 0},
+ {0x1015, 0},
+ {0x1016, 0},
+ {0x1017, 0},
+ {0x1018, 0}
+};
+
+/** Maximum length of the USB string descriptor for the serial number. */
+#define USB_SERIAL_NUMBER_LENGTH 12
+
+/**
+ * Maximum number of digits in a serial number
+ *
+ * The serial number of a device consists of at most 9 digits but user defined
+ * serial numbers are allowed with up to 10 digits.
+ */
+#define MAX_SERIAL_NUMBER_DIGITS 10
+/** @endcond */
+
+static bool parse_serial_number(const char *str, uint32_t *serial_number)
+{
+ size_t length;
+
+ length = strlen(str);
+
+ /*
+ * Skip the first digits which are not part of a valid serial number.
+ * This is necessary because some devices erroneously use random digits
+ * instead of zeros for padding.
+ */
+ if (length > MAX_SERIAL_NUMBER_DIGITS)
+ str = str + (length - MAX_SERIAL_NUMBER_DIGITS);
+
+ if (jaylink_parse_serial_number(str, serial_number) != JAYLINK_OK)
+ return false;
+
+ return true;
+}
+
+static bool compare_devices(const void *a, const void *b)
+{
+ const struct jaylink_device *dev;
+ const struct libusb_device *usb_dev;
+
+ dev = a;
+ usb_dev = b;
+
+ if (dev->iface != JAYLINK_HIF_USB)
+ return false;
+
+ if (dev->usb_dev == usb_dev)
+ return true;
+
+ return false;
+}
+
+static struct jaylink_device *find_device(const struct jaylink_context *ctx,
+ const struct libusb_device *usb_dev)
+{
+ struct list *item;
+
+ item = list_find_custom(ctx->devs, &compare_devices, usb_dev);
+
+ if (item)
+ return item->data;
+
+ return NULL;
+}
+
+static struct jaylink_device *probe_device(struct jaylink_context *ctx,
+ struct libusb_device *usb_dev)
+{
+ int ret;
+ struct libusb_device_descriptor desc;
+ struct libusb_device_handle *usb_devh;
+ struct jaylink_device *dev;
+ char buf[USB_SERIAL_NUMBER_LENGTH + 1];
+ uint8_t usb_address;
+ uint32_t serial_number;
+ bool valid_serial_number;
+ bool found_device;
+ size_t i;
+
+ ret = libusb_get_device_descriptor(usb_dev, &desc);
+
+ if (ret != LIBUSB_SUCCESS) {
+ log_warn(ctx, "Failed to get device descriptor: %s.",
+ libusb_error_name(ret));
+ return NULL;
+ }
+
+ if (desc.idVendor != USB_VENDOR_ID)
+ return NULL;
+
+ found_device = false;
+
+ for (i = 0; i < sizeof(pids) / sizeof(pids[0]); i++) {
+ if (pids[i][0] == desc.idProduct) {
+ found_device = true;
+ usb_address = pids[i][1];
+ break;
+ }
+ }
+
+ if (!found_device)
+ return NULL;
+
+ log_dbg(ctx, "Found device (VID:PID = %04x:%04x, bus:address = "
+ "%03u:%03u).", desc.idVendor, desc.idProduct,
+ libusb_get_bus_number(usb_dev),
+ libusb_get_device_address(usb_dev));
+
+ /*
+ * Search for an already allocated device instance for this device and
+ * if found return a reference to it.
+ */
+ dev = find_device(ctx, usb_dev);
+
+ if (dev) {
+ log_dbg(ctx, "Device: USB address = %u.", dev->usb_address);
+
+ if (dev->valid_serial_number)
+ log_dbg(ctx, "Device: Serial number = %u.",
+ dev->serial_number);
+ else
+ log_dbg(ctx, "Device: Serial number = N/A.");
+
+ log_dbg(ctx, "Using existing device instance.");
+ return jaylink_ref_device(dev);
+ }
+
+ /* Open the device to be able to retrieve its serial number. */
+ ret = libusb_open(usb_dev, &usb_devh);
+
+ if (ret != LIBUSB_SUCCESS) {
+ log_warn(ctx, "Failed to open device: %s.",
+ libusb_error_name(ret));
+ return NULL;
+ }
+
+ serial_number = 0;
+ valid_serial_number = true;
+
+ ret = libusb_get_string_descriptor_ascii(usb_devh, desc.iSerialNumber,
+ (unsigned char *)buf, USB_SERIAL_NUMBER_LENGTH + 1);
+
+ libusb_close(usb_devh);
+
+ if (ret < 0) {
+ log_warn(ctx, "Failed to retrieve serial number: %s.",
+ libusb_error_name(ret));
+ valid_serial_number = false;
+ }
+
+ if (valid_serial_number) {
+ if (!parse_serial_number(buf, &serial_number)) {
+ log_warn(ctx, "Failed to parse serial number.");
+ return NULL;
+ }
+ }
+
+ log_dbg(ctx, "Device: USB address = %u.", usb_address);
+
+ if (valid_serial_number)
+ log_dbg(ctx, "Device: Serial number = %u.", serial_number);
+ else
+ log_dbg(ctx, "Device: Serial number = N/A.");
+
+ log_dbg(ctx, "Allocating new device instance.");
+
+ dev = device_allocate(ctx);
+
+ if (!dev) {
+ log_warn(ctx, "Device instance malloc failed.");
+ return NULL;
+ }
+
+ dev->iface = JAYLINK_HIF_USB;
+ dev->usb_dev = libusb_ref_device(usb_dev);
+ dev->usb_address = usb_address;
+ dev->serial_number = serial_number;
+ dev->valid_serial_number = valid_serial_number;
+
+ return dev;
+}
+
+JAYLINK_PRIV int discovery_usb_scan(struct jaylink_context *ctx)
+{
+ ssize_t ret;
+ struct libusb_device **devs;
+ struct jaylink_device *dev;
+ size_t num;
+ size_t i;
+
+ ret = libusb_get_device_list(ctx->usb_ctx, &devs);
+
+ if (ret == LIBUSB_ERROR_IO) {
+ log_err(ctx, "Failed to retrieve device list: input/output "
+ "error.");
+ return JAYLINK_ERR_IO;
+ } else if (ret < 0) {
+ log_err(ctx, "Failed to retrieve device list: %s.",
+ libusb_error_name(ret));
+ return JAYLINK_ERR;
+ }
+
+ num = 0;
+
+ for (i = 0; devs[i]; i++) {
+ dev = probe_device(ctx, devs[i]);
+
+ if (!dev)
+ continue;
+
+ ctx->discovered_devs = list_prepend(ctx->discovered_devs, dev);
+ num++;
+ }
+
+ libusb_free_device_list(devs, true);
+ log_dbg(ctx, "Found %zu USB device(s).", num);
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/emucom.c b/src/jtag/drivers/libjaylink/libjaylink/emucom.c
new file mode 100644
index 0000000..035cb99
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/emucom.c
@@ -0,0 +1,287 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2015-2016 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Emulator communication (EMUCOM).
+ */
+
+/** @cond PRIVATE */
+#define CMD_EMUCOM 0xee
+
+#define EMUCOM_CMD_READ 0x00
+#define EMUCOM_CMD_WRITE 0x01
+
+/** Bitmask for the error indication bit of an EMUCOM status code. */
+#define EMUCOM_ERR 0x80000000
+
+/** Error code indicating that the channel is not supported by the device. */
+#define EMUCOM_ERR_NOT_SUPPORTED 0x80000001
+
+/**
+ * Error code indicating that the channel is not available for the requested
+ * number of bytes to be read.
+ *
+ * The number of bytes available on this channel is encoded in the lower
+ * 24 bits of the EMUCOM status code.
+ *
+ * @see EMUCOM_AVAILABLE_BYTES_MASK
+ */
+#define EMUCOM_ERR_NOT_AVAILABLE 0x81000000
+
+/**
+ * Bitmask to extract the number of available bytes on a channel from an EMUCOM
+ * status code.
+ */
+#define EMUCOM_AVAILABLE_BYTES_MASK 0x00ffffff
+/** @endcond */
+
+/**
+ * Read from an EMUCOM channel.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_EMUCOM capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] channel Channel to read data from.
+ * @param[out] buffer Buffer to store read data on success. Its content is
+ * undefined on failure.
+ * @param[in,out] length Number of bytes to read. On success, the value gets
+ * updated with the actual number of bytes read. Unless
+ * otherwise specified, the value is undefined on
+ * failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_PROTO Protocol violation.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV_NOT_SUPPORTED Channel is not supported by the
+ * device.
+ * @retval JAYLINK_ERR_DEV_NOT_AVAILABLE Channel is not available for the
+ * requested amount of data. @p length is
+ * updated with the number of bytes
+ * available on this channel.
+ * @retval JAYLINK_ERR_DEV Unspecified device error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_emucom_read(struct jaylink_device_handle *devh,
+ uint32_t channel, uint8_t *buffer, uint32_t *length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[10];
+ uint32_t tmp;
+
+ if (!devh || !buffer || !length)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 10, 4, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_EMUCOM;
+ buf[1] = EMUCOM_CMD_READ;
+
+ buffer_set_u32(buf, channel, 2);
+ buffer_set_u32(buf, *length, 6);
+
+ ret = transport_write(devh, buf, 10);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ tmp = buffer_get_u32(buf, 0);
+
+ if (tmp == EMUCOM_ERR_NOT_SUPPORTED)
+ return JAYLINK_ERR_DEV_NOT_SUPPORTED;
+
+ if ((tmp & ~EMUCOM_AVAILABLE_BYTES_MASK) == EMUCOM_ERR_NOT_AVAILABLE) {
+ *length = tmp & EMUCOM_AVAILABLE_BYTES_MASK;
+ return JAYLINK_ERR_DEV_NOT_AVAILABLE;
+ }
+
+ if (tmp & EMUCOM_ERR) {
+ log_err(ctx, "Failed to read from channel 0x%x: 0x%x.",
+ channel, tmp);
+ return JAYLINK_ERR_DEV;
+ }
+
+ if (tmp > *length) {
+ log_err(ctx, "Requested at most %u bytes but device "
+ "returned %u bytes.", *length, tmp);
+ return JAYLINK_ERR_PROTO;
+ }
+
+ *length = tmp;
+
+ if (!tmp)
+ return JAYLINK_OK;
+
+ ret = transport_start_read(devh, tmp);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buffer, tmp);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Write to an EMUCOM channel.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_EMUCOM capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] channel Channel to write data to.
+ * @param[in] buffer Buffer to write data from.
+ * @param[in,out] length Number of bytes to write. On success, the value gets
+ * updated with the actual number of bytes written. The
+ * value is undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_PROTO Protocol violation.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV_NOT_SUPPORTED Channel is not supported by the
+ * device.
+ * @retval JAYLINK_ERR_DEV Unspecified device error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_emucom_write(struct jaylink_device_handle *devh,
+ uint32_t channel, const uint8_t *buffer, uint32_t *length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[10];
+ uint32_t tmp;
+
+ if (!devh || !buffer || !length)
+ return JAYLINK_ERR_ARG;
+
+ if (!*length)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 10, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_EMUCOM;
+ buf[1] = EMUCOM_CMD_WRITE;
+
+ buffer_set_u32(buf, channel, 2);
+ buffer_set_u32(buf, *length, 6);
+
+ ret = transport_write(devh, buf, 10);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_start_write_read(devh, *length, 4, false);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_write(devh, buffer, *length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ tmp = buffer_get_u32(buf, 0);
+
+ if (tmp == EMUCOM_ERR_NOT_SUPPORTED)
+ return JAYLINK_ERR_DEV_NOT_SUPPORTED;
+
+ if (tmp & EMUCOM_ERR) {
+ log_err(ctx, "Failed to write to channel 0x%x: 0x%x.",
+ channel, tmp);
+ return JAYLINK_ERR_DEV;
+ }
+
+ if (tmp > *length) {
+ log_err(ctx, "Only %u bytes were supposed to be written, but "
+ "the device reported %u written bytes.", *length, tmp);
+ return JAYLINK_ERR_PROTO;
+ }
+
+ *length = tmp;
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/error.c b/src/jtag/drivers/libjaylink/libjaylink/error.c
new file mode 100644
index 0000000..2c696fc
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/error.c
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include "libjaylink.h"
+
+/**
+ * @file
+ *
+ * Error handling.
+ */
+
+/**
+ * Return a human-readable description of a libjaylink error code.
+ *
+ * @param[in] error_code A libjaylink error code. See #jaylink_error for valid
+ * values.
+ *
+ * @return A string which describes the given error code, or the string
+ * <i>unknown error</i> if the error code is not known. The string is
+ * null-terminated and must not be free'd by the caller.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API const char *jaylink_strerror(int error_code)
+{
+ switch (error_code) {
+ case JAYLINK_OK:
+ return "no error";
+ case JAYLINK_ERR:
+ return "unspecified error";
+ case JAYLINK_ERR_ARG:
+ return "invalid argument";
+ case JAYLINK_ERR_MALLOC:
+ return "memory allocation error";
+ case JAYLINK_ERR_TIMEOUT:
+ return "timeout occurred";
+ case JAYLINK_ERR_PROTO:
+ return "protocol violation";
+ case JAYLINK_ERR_NOT_AVAILABLE:
+ return "entity not available";
+ case JAYLINK_ERR_NOT_SUPPORTED:
+ return "operation not supported";
+ case JAYLINK_ERR_IO:
+ return "input/output error";
+ case JAYLINK_ERR_DEV:
+ return "device: unspecified error";
+ case JAYLINK_ERR_DEV_NOT_SUPPORTED:
+ return "device: operation not supported";
+ case JAYLINK_ERR_DEV_NOT_AVAILABLE:
+ return "device: entity not available";
+ case JAYLINK_ERR_DEV_NO_MEMORY:
+ return "device: not enough memory to perform operation";
+ default:
+ return "unknown error";
+ }
+}
+
+/**
+ * Return the name of a libjaylink error code.
+ *
+ * @param[in] error_code A libjaylink error code. See #jaylink_error for valid
+ * values.
+ *
+ * @return A string which contains the name for the given error code, or the
+ * string <i>unknown error code</i> if the error code is not known. The
+ * string is null-terminated and must not be free'd by the caller.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API const char *jaylink_strerror_name(int error_code)
+{
+ switch (error_code) {
+ case JAYLINK_OK:
+ return "JAYLINK_OK";
+ case JAYLINK_ERR:
+ return "JAYLINK_ERR";
+ case JAYLINK_ERR_ARG:
+ return "JAYLINK_ERR_ARG";
+ case JAYLINK_ERR_MALLOC:
+ return "JAYLINK_ERR_MALLOC";
+ case JAYLINK_ERR_TIMEOUT:
+ return "JAYLINK_ERR_TIMEOUT";
+ case JAYLINK_ERR_PROTO:
+ return "JAYLINK_ERR_PROTO";
+ case JAYLINK_ERR_NOT_AVAILABLE:
+ return "JAYLINK_ERR_NOT_AVAILABLE";
+ case JAYLINK_ERR_NOT_SUPPORTED:
+ return "JAYLINK_ERR_NOT_SUPPORTED";
+ case JAYLINK_ERR_IO:
+ return "JAYLINK_ERR_IO";
+ case JAYLINK_ERR_DEV:
+ return "JAYLINK_ERR_DEV";
+ case JAYLINK_ERR_DEV_NOT_SUPPORTED:
+ return "JAYLINK_ERR_DEV_NOT_SUPPORTED";
+ case JAYLINK_ERR_DEV_NOT_AVAILABLE:
+ return "JAYLINK_ERR_DEV_NOT_AVAILABLE";
+ case JAYLINK_ERR_DEV_NO_MEMORY:
+ return "JAYLINK_ERR_DEV_NO_MEMORY";
+ default:
+ return "unknown error code";
+ }
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/fileio.c b/src/jtag/drivers/libjaylink/libjaylink/fileio.c
new file mode 100644
index 0000000..933c366
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/fileio.c
@@ -0,0 +1,499 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * File I/O functions.
+ */
+
+/** @cond PRIVATE */
+#define CMD_FILE_IO 0x1e
+
+#define FILE_IO_CMD_READ 0x64
+#define FILE_IO_CMD_WRITE 0x65
+#define FILE_IO_CMD_GET_SIZE 0x66
+#define FILE_IO_CMD_DELETE 0x67
+
+#define FILE_IO_PARAM_FILENAME 0x01
+#define FILE_IO_PARAM_OFFSET 0x02
+#define FILE_IO_PARAM_LENGTH 0x03
+
+#define FILE_IO_ERR 0x80000000
+/** @endcond */
+
+/**
+ * Read from a file.
+ *
+ * The maximum amount of data that can be read from a file at once is
+ * #JAYLINK_FILE_MAX_TRANSFER_SIZE bytes. Multiple reads in conjunction with
+ * the @p offset parameter are needed for larger files.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_FILE_IO capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] filename Name of the file to read from. The length of the name
+ * must not exceed #JAYLINK_FILE_NAME_MAX_LENGTH bytes.
+ * @param[out] buffer Buffer to store read data on success. Its content is
+ * undefined on failure
+ * @param[in] offset Offset in bytes relative to the beginning of the file from
+ * where to start reading.
+ * @param[in,out] length Number of bytes to read. On success, the value gets
+ * updated with the actual number of bytes read. The
+ * value is undefined on failure.
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV Unspecified device error, or the file was not found.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_file_read(struct jaylink_device_handle *devh,
+ const char *filename, uint8_t *buffer, uint32_t offset,
+ uint32_t *length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[18 + JAYLINK_FILE_NAME_MAX_LENGTH];
+ size_t filename_length;
+ uint32_t tmp;
+
+ if (!devh || !filename || !buffer || !length)
+ return JAYLINK_ERR_ARG;
+
+ if (!*length)
+ return JAYLINK_ERR_ARG;
+
+ if (*length > JAYLINK_FILE_MAX_TRANSFER_SIZE)
+ return JAYLINK_ERR_ARG;
+
+ filename_length = strlen(filename);
+
+ if (!filename_length)
+ return JAYLINK_ERR_ARG;
+
+ if (filename_length > JAYLINK_FILE_NAME_MAX_LENGTH)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 18 + filename_length, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_FILE_IO;
+ buf[1] = FILE_IO_CMD_READ;
+ buf[2] = 0x00;
+
+ buf[3] = filename_length;
+ buf[4] = FILE_IO_PARAM_FILENAME;
+ memcpy(buf + 5, filename, filename_length);
+
+ buf[filename_length + 5] = 0x04;
+ buf[filename_length + 6] = FILE_IO_PARAM_OFFSET;
+ buffer_set_u32(buf, offset, filename_length + 7);
+
+ buf[filename_length + 11] = 0x04;
+ buf[filename_length + 12] = FILE_IO_PARAM_LENGTH;
+ buffer_set_u32(buf, *length, filename_length + 13);
+
+ buf[filename_length + 17] = 0x00;
+
+ ret = transport_write(devh, buf, 18 + filename_length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_start_read(devh, *length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buffer, *length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_start_read(devh, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ tmp = buffer_get_u32(buf, 0);
+
+ if (tmp & FILE_IO_ERR)
+ return JAYLINK_ERR_DEV;
+
+ *length = tmp;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Write to a file.
+ *
+ * If a file does not exist, a new file is created.
+ *
+ * The maximum amount of data that can be written to a file at once is
+ * #JAYLINK_FILE_MAX_TRANSFER_SIZE bytes. Multiple writes in conjunction with
+ * the @p offset parameter are needed for larger files.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_FILE_IO capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] filename Name of the file to write to. The length of the name
+ * must not exceed #JAYLINK_FILE_NAME_MAX_LENGTH bytes.
+ * @param[in] buffer Buffer to write data from.
+ * @param[in] offset Offset in bytes relative to the beginning of the file from
+ * where to start writing.
+ * @param[in,out] length Number of bytes to write. On success, the value gets
+ * updated with the actual number of bytes written. The
+ * value is undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV Unspecified device error, or the file was not found.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_file_write(struct jaylink_device_handle *devh,
+ const char *filename, const uint8_t *buffer, uint32_t offset,
+ uint32_t *length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[18 + JAYLINK_FILE_NAME_MAX_LENGTH];
+ size_t filename_length;
+ uint32_t tmp;
+
+ if (!devh || !filename || !buffer || !length)
+ return JAYLINK_ERR_ARG;
+
+ if (!*length)
+ return JAYLINK_ERR_ARG;
+
+ if (*length > JAYLINK_FILE_MAX_TRANSFER_SIZE)
+ return JAYLINK_ERR_ARG;
+
+ filename_length = strlen(filename);
+
+ if (!filename_length)
+ return JAYLINK_ERR_ARG;
+
+ if (filename_length > JAYLINK_FILE_NAME_MAX_LENGTH)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 18 + filename_length, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_FILE_IO;
+ buf[1] = FILE_IO_CMD_WRITE;
+ buf[2] = 0x00;
+
+ buf[3] = filename_length;
+ buf[4] = FILE_IO_PARAM_FILENAME;
+ memcpy(buf + 5, filename, filename_length);
+
+ buf[filename_length + 5] = 0x04;
+ buf[filename_length + 6] = FILE_IO_PARAM_OFFSET;
+ buffer_set_u32(buf, offset, filename_length + 7);
+
+ buf[filename_length + 11] = 0x04;
+ buf[filename_length + 12] = FILE_IO_PARAM_LENGTH;
+ buffer_set_u32(buf, *length, filename_length + 13);
+
+ buf[filename_length + 17] = 0x00;
+
+ ret = transport_write(devh, buf, 18 + filename_length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_start_write(devh, *length, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_write(devh, buffer, *length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_start_read(devh, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ tmp = buffer_get_u32(buf, 0);
+
+ if (tmp & FILE_IO_ERR)
+ return JAYLINK_ERR_DEV;
+
+ *length = tmp;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve the size of a file.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_FILE_IO capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] filename Name of the file to retrieve the size of. The length
+ * of the name must not exceed
+ * #JAYLINK_FILE_NAME_MAX_LENGTH bytes.
+ * @param[out] size Size of the file in bytes on success, and undefined on
+ * failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV Unspecified device error, or the file was not found.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_file_get_size(struct jaylink_device_handle *devh,
+ const char *filename, uint32_t *size)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[6 + JAYLINK_FILE_NAME_MAX_LENGTH];
+ size_t length;
+ uint32_t tmp;
+
+ if (!devh || !filename || !size)
+ return JAYLINK_ERR_ARG;
+
+ length = strlen(filename);
+
+ if (!length)
+ return JAYLINK_ERR_ARG;
+
+ if (length > JAYLINK_FILE_NAME_MAX_LENGTH)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 6 + length, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_FILE_IO;
+ buf[1] = FILE_IO_CMD_GET_SIZE;
+ buf[2] = 0x00;
+
+ buf[3] = length;
+ buf[4] = FILE_IO_PARAM_FILENAME;
+ memcpy(buf + 5, filename, length);
+
+ buf[length + 5] = 0x00;
+
+ ret = transport_write(devh, buf, 6 + length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_start_read(devh, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ tmp = buffer_get_u32(buf, 0);
+
+ if (tmp & FILE_IO_ERR)
+ return JAYLINK_ERR_DEV;
+
+ *size = tmp;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Delete a file.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_FILE_IO capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] filename Name of the file to delete. The length of the name
+ * must not exceed #JAYLINK_FILE_NAME_MAX_LENGTH bytes.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV Unspecified device error, or the file was not found.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_file_delete(struct jaylink_device_handle *devh,
+ const char *filename)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[6 + JAYLINK_FILE_NAME_MAX_LENGTH];
+ size_t length;
+ uint32_t tmp;
+
+ if (!devh || !filename)
+ return JAYLINK_ERR_ARG;
+
+ length = strlen(filename);
+
+ if (!length)
+ return JAYLINK_ERR_ARG;
+
+ if (length > JAYLINK_FILE_NAME_MAX_LENGTH)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 6 + length, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_FILE_IO;
+ buf[1] = FILE_IO_CMD_DELETE;
+ buf[2] = 0x00;
+
+ buf[3] = length;
+ buf[4] = FILE_IO_PARAM_FILENAME;
+ memcpy(buf + 5, filename, length);
+
+ buf[length + 5] = 0x00;
+
+ ret = transport_write(devh, buf, 6 + length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_start_read(devh, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ tmp = buffer_get_u32(buf, 0);
+
+ if (tmp & FILE_IO_ERR)
+ return JAYLINK_ERR_DEV;
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/jtag.c b/src/jtag/drivers/libjaylink/libjaylink/jtag.c
new file mode 100644
index 0000000..c0c65de
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/jtag.c
@@ -0,0 +1,259 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * JTAG functions.
+ */
+
+/** @cond PRIVATE */
+#define CMD_JTAG_IO_V2 0xce
+#define CMD_JTAG_IO_V3 0xcf
+#define CMD_JTAG_CLEAR_TRST 0xde
+#define CMD_JTAG_SET_TRST 0xdf
+
+/**
+ * Error code indicating that there is not enough free memory on the device to
+ * perform the JTAG I/O operation.
+ */
+#define JTAG_IO_ERR_NO_MEMORY 0x06
+/** @endcond */
+
+/**
+ * Perform a JTAG I/O operation.
+ *
+ * @note This function must only be used if the #JAYLINK_TIF_JTAG interface is
+ * available and selected. Nevertheless, this function can be used if the
+ * device doesn't have the #JAYLINK_DEV_CAP_SELECT_TIF capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] tms Buffer to read TMS data from.
+ * @param[in] tdi Buffer to read TDI data from.
+ * @param[out] tdo Buffer to store TDO data on success. Its content is
+ * undefined on failure. The buffer must be large enough to
+ * contain at least the specified number of bits to transfer.
+ * @param[in] length Number of bits to transfer.
+ * @param[in] version Version of the JTAG command to use.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV_NO_MEMORY Not enough memory on the device to perform
+ * the operation.
+ * @retval JAYLINK_ERR_DEV Unspecified device error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_select_interface()
+ * @see jaylink_set_speed()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_jtag_io(struct jaylink_device_handle *devh,
+ const uint8_t *tms, const uint8_t *tdi, uint8_t *tdo,
+ uint16_t length, enum jaylink_jtag_version version)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[4];
+ uint16_t num_bytes;
+ uint16_t read_length;
+ uint8_t status;
+ uint8_t cmd;
+
+ if (!devh || !tms || !tdi || !tdo || !length)
+ return JAYLINK_ERR_ARG;
+
+ num_bytes = (length + 7) / 8;
+ read_length = num_bytes;
+
+ switch (version) {
+ case JAYLINK_JTAG_VERSION_2:
+ cmd = CMD_JTAG_IO_V2;
+ break;
+ case JAYLINK_JTAG_VERSION_3:
+ cmd = CMD_JTAG_IO_V3;
+ /* In this version, the response includes a status byte. */
+ read_length++;
+ break;
+ default:
+ return JAYLINK_ERR_ARG;
+ }
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 4 + 2 * num_bytes,
+ read_length, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = cmd;
+ buf[1] = 0x00;
+ buffer_set_u16(buf, length, 2);
+
+ ret = transport_write(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_write(devh, tms, num_bytes);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_write(devh, tdi, num_bytes);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, tdo, num_bytes);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ if (version == JAYLINK_JTAG_VERSION_2)
+ return JAYLINK_OK;
+
+ ret = transport_read(devh, &status, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ if (status == JTAG_IO_ERR_NO_MEMORY) {
+ return JAYLINK_ERR_DEV_NO_MEMORY;
+ } else if (status > 0) {
+ log_err(ctx, "JTAG I/O operation failed: 0x%x.", status);
+ return JAYLINK_ERR_DEV;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Clear the JTAG test reset (TRST) signal.
+ *
+ * @param[in,out] devh Device handle.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_jtag_clear_trst(struct jaylink_device_handle *devh)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[1];
+
+ if (!devh)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 1, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_JTAG_CLEAR_TRST;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Set the JTAG test reset (TRST) signal.
+ *
+ * @param[in,out] devh Device handle.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_jtag_set_trst(struct jaylink_device_handle *devh)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[1];
+
+ if (!devh)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 1, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_JTAG_SET_TRST;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/libjaylink-internal.h b/src/jtag/drivers/libjaylink/libjaylink/libjaylink-internal.h
new file mode 100644
index 0000000..f97ec14
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/libjaylink-internal.h
@@ -0,0 +1,320 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2016 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#ifndef LIBJAYLINK_LIBJAYLINK_INTERNAL_H
+#define LIBJAYLINK_LIBJAYLINK_INTERNAL_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifdef _WIN32
+#include <ws2tcpip.h>
+#else
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_LIBUSB
+#include <libusb.h>
+#endif
+
+#include "libjaylink.h"
+
+/**
+ * @file
+ *
+ * Internal libjaylink header file.
+ */
+
+/** Macro to mark private libjaylink symbol. */
+#if defined(_WIN32) || defined(__MSYS__) || defined(__CYGWIN__)
+#define JAYLINK_PRIV
+#else
+#define JAYLINK_PRIV __attribute__ ((visibility ("hidden")))
+#endif
+
+/** Calculate the minimum of two numeric values. */
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+struct jaylink_context {
+#ifdef HAVE_LIBUSB
+ /** libusb context. */
+ struct libusb_context *usb_ctx;
+#endif
+ /**
+ * List of allocated device instances.
+ *
+ * Used to prevent multiple device instances for the same device.
+ */
+ struct list *devs;
+ /** List of recently discovered devices. */
+ struct list *discovered_devs;
+ /** Current log level. */
+ enum jaylink_log_level log_level;
+ /** Log callback function. */
+ jaylink_log_callback log_callback;
+ /** User data to be passed to the log callback function. */
+ void *log_callback_data;
+ /** Log domain. */
+ char log_domain[JAYLINK_LOG_DOMAIN_MAX_LENGTH + 1];
+};
+
+struct jaylink_device {
+ /** libjaylink context. */
+ struct jaylink_context *ctx;
+ /** Number of references held on this device instance. */
+ size_t ref_count;
+ /** Host interface. */
+ enum jaylink_host_interface iface;
+ /**
+ * Serial number of the device.
+ *
+ * This number is for enumeration purpose only and can differ from the
+ * real serial number of the device.
+ */
+ uint32_t serial_number;
+ /** Indicates whether the serial number is valid. */
+ bool valid_serial_number;
+#ifdef HAVE_LIBUSB
+ /** libusb device instance. */
+ struct libusb_device *usb_dev;
+ /** USB address of the device. */
+ uint8_t usb_address;
+#endif
+ /**
+ * IPv4 address.
+ *
+ * The address is encoded as string in quad-dotted decimal format.
+ *
+ * This field is used for devices with host interface #JAYLINK_HIF_TCP
+ * only.
+ */
+ char ipv4_address[INET_ADDRSTRLEN];
+ /**
+ * Media Access Control (MAC) address.
+ *
+ * This field is used for devices with host interface #JAYLINK_HIF_TCP
+ * only.
+ */
+ uint8_t mac_address[JAYLINK_MAC_ADDRESS_LENGTH];
+ /** Indicates whether the MAC address is available. */
+ bool has_mac_address;
+ /**
+ * Product name.
+ *
+ * This field is used for devices with host interface #JAYLINK_HIF_TCP
+ * only.
+ */
+ char product_name[JAYLINK_PRODUCT_NAME_MAX_LENGTH];
+ /** Indicates whether the product name is available. */
+ bool has_product_name;
+ /**
+ * Nickname.
+ *
+ * This field is used for devices with host interface #JAYLINK_HIF_TCP
+ * only.
+ */
+ char nickname[JAYLINK_NICKNAME_MAX_LENGTH];
+ /** Indicates whether the nickname is available. */
+ bool has_nickname;
+ /**
+ * Hardware version.
+ *
+ * This field is used for devices with host interface #JAYLINK_HIF_TCP
+ * only.
+ */
+ struct jaylink_hardware_version hw_version;
+ /** Indicates whether the hardware version is available. */
+ bool has_hw_version;
+};
+
+struct jaylink_device_handle {
+ /** Device instance. */
+ struct jaylink_device *dev;
+ /**
+ * Buffer for write and read operations.
+ *
+ * Note that write and read operations are always processed
+ * consecutively and therefore the same buffer can be used for both.
+ */
+ uint8_t *buffer;
+ /** Buffer size. */
+ size_t buffer_size;
+ /** Number of bytes left for the read operation. */
+ size_t read_length;
+ /** Number of bytes available in the buffer to be read. */
+ size_t bytes_available;
+ /** Current read position in the buffer. */
+ size_t read_pos;
+ /**
+ * Number of bytes left to be written before the write operation will
+ * be performed.
+ */
+ size_t write_length;
+ /**
+ * Current write position in the buffer.
+ *
+ * This is equivalent to the number of bytes in the buffer and used for
+ * write operations only.
+ */
+ size_t write_pos;
+#ifdef HAVE_LIBUSB
+ /** libusb device handle. */
+ struct libusb_device_handle *usb_devh;
+ /** USB interface number of the device. */
+ uint8_t interface_number;
+ /** USB interface IN endpoint of the device. */
+ uint8_t endpoint_in;
+ /** USB interface OUT endpoint of the device. */
+ uint8_t endpoint_out;
+#endif
+ /**
+ * Socket descriptor.
+ *
+ * This field is used for devices with host interface #JAYLINK_HIF_TCP
+ * only.
+ */
+ int sock;
+};
+
+struct list {
+ void *data;
+ struct list *next;
+};
+
+typedef bool (*list_compare_callback)(const void *data, const void *user_data);
+
+/*--- buffer.c --------------------------------------------------------------*/
+
+JAYLINK_PRIV void buffer_set_u16(uint8_t *buffer, uint16_t value,
+ size_t offset);
+JAYLINK_PRIV uint16_t buffer_get_u16(const uint8_t *buffer, size_t offset);
+JAYLINK_PRIV void buffer_set_u32(uint8_t *buffer, uint32_t value,
+ size_t offset);
+JAYLINK_PRIV uint32_t buffer_get_u32(const uint8_t *buffer, size_t offset);
+
+/*--- device.c --------------------------------------------------------------*/
+
+JAYLINK_PRIV struct jaylink_device *device_allocate(
+ struct jaylink_context *ctx);
+
+/*--- discovery_tcp.c -------------------------------------------------------*/
+
+JAYLINK_PRIV int discovery_tcp_scan(struct jaylink_context *ctx);
+
+/*--- discovery_usb.c -------------------------------------------------------*/
+
+JAYLINK_PRIV int discovery_usb_scan(struct jaylink_context *ctx);
+
+/*--- list.c ----------------------------------------------------------------*/
+
+JAYLINK_PRIV struct list *list_prepend(struct list *list, void *data);
+JAYLINK_PRIV struct list *list_remove(struct list *list, const void *data);
+JAYLINK_PRIV struct list *list_find_custom(struct list *list,
+ list_compare_callback callback, const void *user_data);
+JAYLINK_PRIV size_t list_length(struct list *list);
+JAYLINK_PRIV void list_free(struct list *list);
+
+/*--- log.c -----------------------------------------------------------------*/
+
+JAYLINK_PRIV int log_vprintf(const struct jaylink_context *ctx,
+ enum jaylink_log_level level, const char *format, va_list args,
+ void *user_data);
+JAYLINK_PRIV void log_err(const struct jaylink_context *ctx,
+ const char *format, ...);
+JAYLINK_PRIV void log_warn(const struct jaylink_context *ctx,
+ const char *format, ...);
+JAYLINK_PRIV void log_info(const struct jaylink_context *ctx,
+ const char *format, ...);
+JAYLINK_PRIV void log_dbg(const struct jaylink_context *ctx,
+ const char *format, ...);
+JAYLINK_PRIV void log_dbgio(const struct jaylink_context *ctx,
+ const char *format, ...);
+
+/*--- socket.c --------------------------------------------------------------*/
+
+JAYLINK_PRIV bool socket_close(int sock);
+JAYLINK_PRIV bool socket_bind(int sock, const struct sockaddr *address,
+ size_t length);
+JAYLINK_PRIV bool socket_send(int sock, const void *buffer, size_t *length,
+ int flags);
+JAYLINK_PRIV bool socket_recv(int sock, void *buffer, size_t *length,
+ int flags);
+JAYLINK_PRIV bool socket_sendto(int sock, const void *buffer, size_t *length,
+ int flags, const struct sockaddr *address,
+ size_t address_length);
+JAYLINK_PRIV bool socket_recvfrom(int sock, void *buffer, size_t *length,
+ int flags, struct sockaddr *address, size_t *address_length);
+JAYLINK_PRIV bool socket_set_option(int sock, int level, int option,
+ const void *value, size_t length);
+
+/*--- transport.c -----------------------------------------------------------*/
+
+JAYLINK_PRIV int transport_open(struct jaylink_device_handle *devh);
+JAYLINK_PRIV int transport_close(struct jaylink_device_handle *devh);
+JAYLINK_PRIV int transport_start_write_read(struct jaylink_device_handle *devh,
+ size_t write_length, size_t read_length, bool has_command);
+JAYLINK_PRIV int transport_start_write(struct jaylink_device_handle *devh,
+ size_t length, bool has_command);
+JAYLINK_PRIV int transport_start_read(struct jaylink_device_handle *devh,
+ size_t length);
+JAYLINK_PRIV int transport_write(struct jaylink_device_handle *devh,
+ const uint8_t *buffer, size_t length);
+JAYLINK_PRIV int transport_read(struct jaylink_device_handle *devh,
+ uint8_t *buffer, size_t length);
+
+/*--- transport_usb.c -------------------------------------------------------*/
+
+JAYLINK_PRIV int transport_usb_open(struct jaylink_device_handle *devh);
+JAYLINK_PRIV int transport_usb_close(struct jaylink_device_handle *devh);
+JAYLINK_PRIV int transport_usb_start_write_read(
+ struct jaylink_device_handle *devh, size_t write_length,
+ size_t read_length, bool has_command);
+JAYLINK_PRIV int transport_usb_start_write(struct jaylink_device_handle *devh,
+ size_t length, bool has_command);
+JAYLINK_PRIV int transport_usb_start_read(struct jaylink_device_handle *devh,
+ size_t length);
+JAYLINK_PRIV int transport_usb_write(struct jaylink_device_handle *devh,
+ const uint8_t *buffer, size_t length);
+JAYLINK_PRIV int transport_usb_read(struct jaylink_device_handle *devh,
+ uint8_t *buffer, size_t length);
+
+/*--- transport_tcp.c -------------------------------------------------------*/
+
+JAYLINK_PRIV int transport_tcp_open(struct jaylink_device_handle *devh);
+JAYLINK_PRIV int transport_tcp_close(struct jaylink_device_handle *devh);
+JAYLINK_PRIV int transport_tcp_start_write_read(
+ struct jaylink_device_handle *devh, size_t write_length,
+ size_t read_length, bool has_command);
+JAYLINK_PRIV int transport_tcp_start_write(struct jaylink_device_handle *devh,
+ size_t length, bool has_command);
+JAYLINK_PRIV int transport_tcp_start_read(struct jaylink_device_handle *devh,
+ size_t length);
+JAYLINK_PRIV int transport_tcp_write(struct jaylink_device_handle *devh,
+ const uint8_t *buffer, size_t length);
+JAYLINK_PRIV int transport_tcp_read(struct jaylink_device_handle *devh,
+ uint8_t *buffer, size_t length);
+
+#endif /* LIBJAYLINK_LIBJAYLINK_INTERNAL_H */
diff --git a/src/jtag/drivers/libjaylink/libjaylink/libjaylink.h b/src/jtag/drivers/libjaylink/libjaylink/libjaylink.h
new file mode 100644
index 0000000..223aa84
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/libjaylink.h
@@ -0,0 +1,589 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2016 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#ifndef LIBJAYLINK_LIBJAYLINK_H
+#define LIBJAYLINK_LIBJAYLINK_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#ifdef _WIN32
+#include <ws2tcpip.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+/**
+ * @file
+ *
+ * Public libjaylink header file to be used by applications.
+ */
+
+/** Error codes returned by libjaylink functions. */
+enum jaylink_error {
+ /** No error. */
+ JAYLINK_OK = 0,
+ /** Unspecified error. */
+ JAYLINK_ERR = -1,
+ /** Invalid argument. */
+ JAYLINK_ERR_ARG = -2,
+ /** Memory allocation error. */
+ JAYLINK_ERR_MALLOC = -3,
+ /** Timeout occurred. */
+ JAYLINK_ERR_TIMEOUT = -4,
+ /** Protocol violation. */
+ JAYLINK_ERR_PROTO = -5,
+ /** Entity not available. */
+ JAYLINK_ERR_NOT_AVAILABLE = -6,
+ /** Operation not supported. */
+ JAYLINK_ERR_NOT_SUPPORTED = -7,
+ /** Input/output error. */
+ JAYLINK_ERR_IO = -8,
+ /** Device: unspecified error. */
+ JAYLINK_ERR_DEV = -1000,
+ /** Device: operation not supported. */
+ JAYLINK_ERR_DEV_NOT_SUPPORTED = -1001,
+ /** Device: entity not available. */
+ JAYLINK_ERR_DEV_NOT_AVAILABLE = -1002,
+ /** Device: not enough memory to perform operation. */
+ JAYLINK_ERR_DEV_NO_MEMORY = -1003
+};
+
+/** libjaylink log levels. */
+enum jaylink_log_level {
+ /** Output no messages. */
+ JAYLINK_LOG_LEVEL_NONE = 0,
+ /** Output error messages. */
+ JAYLINK_LOG_LEVEL_ERROR = 1,
+ /** Output warnings. */
+ JAYLINK_LOG_LEVEL_WARNING = 2,
+ /** Output informational messages. */
+ JAYLINK_LOG_LEVEL_INFO = 3,
+ /** Output debug messages. */
+ JAYLINK_LOG_LEVEL_DEBUG = 4,
+ /** Output I/O debug messages. */
+ JAYLINK_LOG_LEVEL_DEBUG_IO = 5
+};
+
+/** Default libjaylink log domain. */
+#define JAYLINK_LOG_DOMAIN_DEFAULT "jaylink: "
+
+/** Maximum length of a libjaylink log domain in bytes. */
+#define JAYLINK_LOG_DOMAIN_MAX_LENGTH 32
+
+/** libjaylink capabilities. */
+enum jaylink_capability {
+ /** Library supports USB as host interface. */
+ JAYLINK_CAP_HIF_USB = 0
+};
+
+/** Host interfaces. */
+enum jaylink_host_interface {
+ /** Universal Serial Bus (USB). */
+ JAYLINK_HIF_USB = (1 << 0),
+ /** Transmission Control Protocol (TCP). */
+ JAYLINK_HIF_TCP = (1 << 1)
+};
+
+/**
+ * USB addresses.
+ *
+ * The USB address is a way to identify USB devices and is related to the USB
+ * Product ID (PID) of a device.
+ */
+enum jaylink_usb_address {
+ /** USB address 0 (Product ID 0x0101). */
+ JAYLINK_USB_ADDRESS_0 = 0,
+ /** USB address 1 (Product ID 0x0102). */
+ JAYLINK_USB_ADDRESS_1 = 1,
+ /** USB address 2 (Product ID 0x0103). */
+ JAYLINK_USB_ADDRESS_2 = 2,
+ /** USB address 3 (Product ID 0x0104). */
+ JAYLINK_USB_ADDRESS_3 = 3
+};
+
+/** Device capabilities. */
+enum jaylink_device_capability {
+ /** Device supports retrieval of the hardware version. */
+ JAYLINK_DEV_CAP_GET_HW_VERSION = 1,
+ /** Device supports adaptive clocking. */
+ JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING = 3,
+ /** Device supports reading configuration data. */
+ JAYLINK_DEV_CAP_READ_CONFIG = 4,
+ /** Device supports writing configuration data. */
+ JAYLINK_DEV_CAP_WRITE_CONFIG = 5,
+ /** Device supports retrieval of target interface speeds. */
+ JAYLINK_DEV_CAP_GET_SPEEDS = 9,
+ /** Device supports retrieval of free memory size. */
+ JAYLINK_DEV_CAP_GET_FREE_MEMORY = 11,
+ /** Device supports retrieval of hardware information. */
+ JAYLINK_DEV_CAP_GET_HW_INFO = 12,
+ /** Device supports the setting of the target power supply. */
+ JAYLINK_DEV_CAP_SET_TARGET_POWER = 13,
+ /** Device supports target interface selection. */
+ JAYLINK_DEV_CAP_SELECT_TIF = 17,
+ /** Device supports retrieval of counter values. */
+ JAYLINK_DEV_CAP_GET_COUNTERS = 19,
+ /** Device supports capturing of SWO trace data. */
+ JAYLINK_DEV_CAP_SWO = 23,
+ /** Device supports file I/O operations. */
+ JAYLINK_DEV_CAP_FILE_IO = 26,
+ /** Device supports registration of connections. */
+ JAYLINK_DEV_CAP_REGISTER = 27,
+ /** Device supports retrieval of extended capabilities. */
+ JAYLINK_DEV_CAP_GET_EXT_CAPS = 31,
+ /** Device supports EMUCOM. */
+ JAYLINK_DEV_CAP_EMUCOM = 33,
+ /** Device supports ethernet connectivity. */
+ JAYLINK_DEV_CAP_ETHERNET = 38
+};
+
+/** Hardware information. */
+enum jaylink_hardware_info {
+ /**
+ * Status of the target power supply.
+ *
+ * This indicates whether the target power supply on pin 19 of the
+ * 20-pin JTAG / SWD connector is enabled or disabled.
+ *
+ * @see jaylink_set_target_power()
+ */
+ JAYLINK_HW_INFO_TARGET_POWER = (1 << 0),
+ /** Current consumption of the target in mA. */
+ JAYLINK_HW_INFO_ITARGET = (1 << 2),
+ /** Peak current consumption of the target in mA. */
+ JAYLINK_HW_INFO_ITARGET_PEAK = (1 << 3)
+};
+
+/** Device counters. */
+enum jaylink_counter {
+ /** Time the device is connected to a target in milliseconds. */
+ JAYLINK_COUNTER_TARGET_TIME = (1 << 0),
+ /**
+ * Number of times the device was connected or disconnected from a
+ * target.
+ */
+ JAYLINK_COUNTER_TARGET_CONNECTIONS = (1 << 1)
+};
+
+/** Device hardware types. */
+enum jaylink_hardware_type {
+ /** J-Link. */
+ JAYLINK_HW_TYPE_JLINK = 0,
+ /** Flasher. */
+ JAYLINK_HW_TYPE_FLASHER = 2,
+ /** J-Link Pro. */
+ JAYLINK_HW_TYPE_JLINK_PRO = 3
+};
+
+/** Target interfaces. */
+enum jaylink_target_interface {
+ /** Joint Test Action Group, IEEE 1149.1 (JTAG). */
+ JAYLINK_TIF_JTAG = 0,
+ /** Serial Wire Debug (SWD). */
+ JAYLINK_TIF_SWD = 1,
+ /** Background Debug Mode 3 (BDM3). */
+ JAYLINK_TIF_BDM3 = 2,
+ /** Renesas’ single-wire debug interface (FINE). */
+ JAYLINK_TIF_FINE = 3,
+ /** 2-wire JTAG for PIC32 compliant devices. */
+ JAYLINK_TIF_2W_JTAG_PIC32 = 4,
+};
+
+/**
+ * JTAG command versions.
+ *
+ * The JTAG command version only affects the device and the communication
+ * protocol. The behaviour of a JTAG operation is not affected at all.
+ */
+enum jaylink_jtag_version {
+ /**
+ * JTAG command version 2.
+ *
+ * This version is obsolete for major hardware version 5 and above. Use
+ * #JAYLINK_JTAG_VERSION_3 for these versions instead.
+ */
+ JAYLINK_JTAG_VERSION_2 = 1,
+ /** JTAG command version 3. */
+ JAYLINK_JTAG_VERSION_3 = 2
+};
+
+/** Serial Wire Output (SWO) capture modes. */
+enum jaylink_swo_mode {
+ /** Universal Asynchronous Receiver Transmitter (UART). */
+ JAYLINK_SWO_MODE_UART = 0
+};
+
+/** Target interface speed information. */
+struct jaylink_speed {
+ /** Base frequency in Hz. */
+ uint32_t freq;
+ /** Minimum frequency divider. */
+ uint16_t div;
+};
+
+/** Serial Wire Output (SWO) speed information. */
+struct jaylink_swo_speed {
+ /** Base frequency in Hz. */
+ uint32_t freq;
+ /** Minimum frequency divider. */
+ uint32_t min_div;
+ /** Maximum frequency divider. */
+ uint32_t max_div;
+ /** Minimum prescaler. */
+ uint32_t min_prescaler;
+ /** Maximum prescaler. */
+ uint32_t max_prescaler;
+};
+
+/** Device hardware version. */
+struct jaylink_hardware_version {
+ /** Hardware type. */
+ enum jaylink_hardware_type type;
+ /** Major version. */
+ uint8_t major;
+ /** Minor version. */
+ uint8_t minor;
+ /** Revision number. */
+ uint8_t revision;
+};
+
+/** Device hardware status. */
+struct jaylink_hardware_status {
+ /** Target reference voltage in mV. */
+ uint16_t target_voltage;
+ /** TCK pin state. */
+ bool tck;
+ /** TDI pin state. */
+ bool tdi;
+ /** TDO pin state. */
+ bool tdo;
+ /** TMS pin state. */
+ bool tms;
+ /** TRES pin state. */
+ bool tres;
+ /** TRST pin state. */
+ bool trst;
+};
+
+/** Device connection. */
+struct jaylink_connection {
+ /** Handle. */
+ uint16_t handle;
+ /**
+ * Process ID (PID).
+ *
+ * Identification of the client process. Usually this is the
+ * Process ID (PID) of the client process in an arbitrary format.
+ */
+ uint32_t pid;
+ /**
+ * Host ID (HID).
+ *
+ * IPv4 address string of the client in quad-dotted decimal format
+ * (e.g. 192.0.2.235). The address 0.0.0.0 should be used for the
+ * registration of an USB connection.
+ */
+ char hid[INET_ADDRSTRLEN];
+ /** IID. */
+ uint8_t iid;
+ /** CID. */
+ uint8_t cid;
+ /**
+ * Timestamp of the last registration in milliseconds.
+ *
+ * The timestamp is relative to the time the device was powered up.
+ */
+ uint32_t timestamp;
+};
+
+/** Target interface speed value for adaptive clocking. */
+#define JAYLINK_SPEED_ADAPTIVE_CLOCKING 0xffff
+
+/** Size of the device configuration data in bytes. */
+#define JAYLINK_DEV_CONFIG_SIZE 256
+
+/** Number of bytes required to store device capabilities. */
+#define JAYLINK_DEV_CAPS_SIZE 4
+
+/** Number of bytes required to store extended device capabilities. */
+#define JAYLINK_DEV_EXT_CAPS_SIZE 32
+
+/** Maximum number of connections that can be registered on a device. */
+#define JAYLINK_MAX_CONNECTIONS 16
+
+/** Media Access Control (MAC) address length in bytes. */
+#define JAYLINK_MAC_ADDRESS_LENGTH 6
+
+/**
+ * Maximum length of a device's nickname including trailing null-terminator in
+ * bytes.
+ */
+#define JAYLINK_NICKNAME_MAX_LENGTH 32
+
+/**
+ * Maximum length of a device's product name including trailing null-terminator
+ * in bytes.
+ */
+#define JAYLINK_PRODUCT_NAME_MAX_LENGTH 32
+
+/** Maximum length of a filename in bytes. */
+#define JAYLINK_FILE_NAME_MAX_LENGTH 255
+
+/** Maximum transfer size for a file in bytes. */
+#define JAYLINK_FILE_MAX_TRANSFER_SIZE 0x100000
+
+/**
+ * EMUCOM channel with the system time of the device in milliseconds.
+ *
+ * The channel is read-only and the time is encoded in 4 bytes. The byte order
+ * is little-endian.
+ */
+#define JAYLINK_EMUCOM_CHANNEL_TIME 0x0
+
+/**
+ * Offset of EMUCOM user channels.
+ *
+ * User channels are available to implement vendor and/or device specific
+ * functionalities. All channels below are reserved.
+ */
+#define JAYLINK_EMUCOM_CHANNEL_USER 0x10000
+
+/**
+ * @struct jaylink_context
+ *
+ * Opaque structure representing a libjaylink context.
+ */
+struct jaylink_context;
+
+/**
+ * @struct jaylink_device
+ *
+ * Opaque structure representing a device.
+ */
+struct jaylink_device;
+
+/**
+ * @struct jaylink_device_handle
+ *
+ * Opaque structure representing a handle of a device.
+ */
+struct jaylink_device_handle;
+
+/** Macro to mark public libjaylink API symbol. */
+#ifdef _WIN32
+#define JAYLINK_API
+#else
+#define JAYLINK_API __attribute__ ((visibility ("default")))
+#endif
+
+/**
+ * Log callback function type.
+ *
+ * @param[in] ctx libjaylink context.
+ * @param[in] level Log level.
+ * @param[in] format Message format in printf()-style.
+ * @param[in] args Message arguments.
+ * @param[in,out] user_data User data passed to the callback function.
+ *
+ * @return Number of characters printed on success, or a negative error code on
+ * failure.
+ */
+typedef int (*jaylink_log_callback)(const struct jaylink_context *ctx,
+ enum jaylink_log_level level, const char *format, va_list args,
+ void *user_data);
+
+/*--- core.c ----------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_init(struct jaylink_context **ctx);
+JAYLINK_API int jaylink_exit(struct jaylink_context *ctx);
+JAYLINK_API bool jaylink_library_has_cap(enum jaylink_capability cap);
+
+/*--- device.c --------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_get_devices(struct jaylink_context *ctx,
+ struct jaylink_device ***devs, size_t *count);
+JAYLINK_API void jaylink_free_devices(struct jaylink_device **devs,
+ bool unref);
+JAYLINK_API int jaylink_device_get_host_interface(
+ const struct jaylink_device *dev,
+ enum jaylink_host_interface *iface);
+JAYLINK_API int jaylink_device_get_serial_number(
+ const struct jaylink_device *dev, uint32_t *serial_number);
+JAYLINK_API int jaylink_device_get_usb_address(
+ const struct jaylink_device *dev,
+ enum jaylink_usb_address *address);
+JAYLINK_API int jaylink_device_get_ipv4_address(
+ const struct jaylink_device *dev, char *address);
+JAYLINK_API int jaylink_device_get_mac_address(
+ const struct jaylink_device *dev, uint8_t *address);
+JAYLINK_API int jaylink_device_get_hardware_version(
+ const struct jaylink_device *dev,
+ struct jaylink_hardware_version *version);
+JAYLINK_API int jaylink_device_get_product_name(
+ const struct jaylink_device *dev, char *name);
+JAYLINK_API int jaylink_device_get_nickname(const struct jaylink_device *dev,
+ char *nickname);
+JAYLINK_API struct jaylink_device *jaylink_ref_device(
+ struct jaylink_device *dev);
+JAYLINK_API void jaylink_unref_device(struct jaylink_device *dev);
+JAYLINK_API int jaylink_open(struct jaylink_device *dev,
+ struct jaylink_device_handle **devh);
+JAYLINK_API int jaylink_close(struct jaylink_device_handle *devh);
+JAYLINK_API struct jaylink_device *jaylink_get_device(
+ struct jaylink_device_handle *devh);
+JAYLINK_API int jaylink_get_firmware_version(
+ struct jaylink_device_handle *devh, char **version,
+ size_t *length);
+JAYLINK_API int jaylink_get_hardware_info(struct jaylink_device_handle *devh,
+ uint32_t mask, uint32_t *info);
+JAYLINK_API int jaylink_get_counters(struct jaylink_device_handle *devh,
+ uint32_t mask, uint32_t *values);
+JAYLINK_API int jaylink_get_hardware_version(
+ struct jaylink_device_handle *devh,
+ struct jaylink_hardware_version *version);
+JAYLINK_API int jaylink_get_hardware_status(struct jaylink_device_handle *devh,
+ struct jaylink_hardware_status *status);
+JAYLINK_API int jaylink_get_caps(struct jaylink_device_handle *devh,
+ uint8_t *caps);
+JAYLINK_API int jaylink_get_extended_caps(struct jaylink_device_handle *devh,
+ uint8_t *caps);
+JAYLINK_API int jaylink_get_free_memory(struct jaylink_device_handle *devh,
+ uint32_t *size);
+JAYLINK_API int jaylink_read_raw_config(struct jaylink_device_handle *devh,
+ uint8_t *config);
+JAYLINK_API int jaylink_write_raw_config(struct jaylink_device_handle *devh,
+ const uint8_t *config);
+JAYLINK_API int jaylink_register(struct jaylink_device_handle *devh,
+ struct jaylink_connection *connection,
+ struct jaylink_connection *connections, size_t *count);
+JAYLINK_API int jaylink_unregister(struct jaylink_device_handle *devh,
+ const struct jaylink_connection *connection,
+ struct jaylink_connection *connections, size_t *count);
+
+/*--- discovery.c -----------------------------------------------------------*/
+
+JAYLINK_API int jaylink_discovery_scan(struct jaylink_context *ctx,
+ uint32_t ifaces);
+
+/*--- emucom.c --------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_emucom_read(struct jaylink_device_handle *devh,
+ uint32_t channel, uint8_t *buffer, uint32_t *length);
+JAYLINK_API int jaylink_emucom_write(struct jaylink_device_handle *devh,
+ uint32_t channel, const uint8_t *buffer, uint32_t *length);
+
+/*--- error.c ---------------------------------------------------------------*/
+
+JAYLINK_API const char *jaylink_strerror(int error_code);
+JAYLINK_API const char *jaylink_strerror_name(int error_code);
+
+/*--- fileio.c --------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_file_read(struct jaylink_device_handle *devh,
+ const char *filename, uint8_t *buffer, uint32_t offset,
+ uint32_t *length);
+JAYLINK_API int jaylink_file_write(struct jaylink_device_handle *devh,
+ const char *filename, const uint8_t *buffer, uint32_t offset,
+ uint32_t *length);
+JAYLINK_API int jaylink_file_get_size(struct jaylink_device_handle *devh,
+ const char *filename, uint32_t *size);
+JAYLINK_API int jaylink_file_delete(struct jaylink_device_handle *devh,
+ const char *filename);
+
+/*--- jtag.c ----------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_jtag_io(struct jaylink_device_handle *devh,
+ const uint8_t *tms, const uint8_t *tdi, uint8_t *tdo,
+ uint16_t length, enum jaylink_jtag_version version);
+JAYLINK_API int jaylink_jtag_clear_trst(struct jaylink_device_handle *devh);
+JAYLINK_API int jaylink_jtag_set_trst(struct jaylink_device_handle *devh);
+
+/*--- log.c -----------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_log_set_level(struct jaylink_context *ctx,
+ enum jaylink_log_level level);
+JAYLINK_API int jaylink_log_get_level(const struct jaylink_context *ctx,
+ enum jaylink_log_level *level);
+JAYLINK_API int jaylink_log_set_callback(struct jaylink_context *ctx,
+ jaylink_log_callback callback, void *user_data);
+JAYLINK_API int jaylink_log_set_domain(struct jaylink_context *ctx,
+ const char *domain);
+JAYLINK_API const char *jaylink_log_get_domain(
+ const struct jaylink_context *ctx);
+
+/*--- strutil.c -------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_parse_serial_number(const char *str,
+ uint32_t *serial_number);
+
+/*--- swd.c -----------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_swd_io(struct jaylink_device_handle *devh,
+ const uint8_t *direction, const uint8_t *out, uint8_t *in,
+ uint16_t length);
+
+/*--- swo.c -----------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_swo_start(struct jaylink_device_handle *devh,
+ enum jaylink_swo_mode mode, uint32_t baudrate, uint32_t size);
+JAYLINK_API int jaylink_swo_stop(struct jaylink_device_handle *devh);
+JAYLINK_API int jaylink_swo_read(struct jaylink_device_handle *devh,
+ uint8_t *buffer, uint32_t *length);
+JAYLINK_API int jaylink_swo_get_speeds(struct jaylink_device_handle *devh,
+ enum jaylink_swo_mode mode, struct jaylink_swo_speed *speed);
+
+/*--- target.c --------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_set_speed(struct jaylink_device_handle *devh,
+ uint16_t speed);
+JAYLINK_API int jaylink_get_speeds(struct jaylink_device_handle *devh,
+ struct jaylink_speed *speed);
+JAYLINK_API int jaylink_select_interface(struct jaylink_device_handle *devh,
+ enum jaylink_target_interface iface,
+ enum jaylink_target_interface *prev_iface);
+JAYLINK_API int jaylink_get_available_interfaces(
+ struct jaylink_device_handle *devh, uint32_t *ifaces);
+JAYLINK_API int jaylink_get_selected_interface(
+ struct jaylink_device_handle *devh,
+ enum jaylink_target_interface *iface);
+JAYLINK_API int jaylink_clear_reset(struct jaylink_device_handle *devh);
+JAYLINK_API int jaylink_set_reset(struct jaylink_device_handle *devh);
+JAYLINK_API int jaylink_set_target_power(struct jaylink_device_handle *devh,
+ bool enable);
+
+/*--- util.c ----------------------------------------------------------------*/
+
+JAYLINK_API bool jaylink_has_cap(const uint8_t *caps, uint32_t cap);
+
+/*--- version.c -------------------------------------------------------------*/
+
+JAYLINK_API int jaylink_version_package_get_major(void);
+JAYLINK_API int jaylink_version_package_get_minor(void);
+JAYLINK_API int jaylink_version_package_get_micro(void);
+JAYLINK_API const char *jaylink_version_package_get_string(void);
+JAYLINK_API int jaylink_version_library_get_current(void);
+JAYLINK_API int jaylink_version_library_get_revision(void);
+JAYLINK_API int jaylink_version_library_get_age(void);
+JAYLINK_API const char *jaylink_version_library_get_string(void);
+
+#include "version.h"
+
+#endif /* LIBJAYLINK_LIBJAYLINK_H */
diff --git a/src/jtag/drivers/libjaylink/libjaylink/list.c b/src/jtag/drivers/libjaylink/libjaylink/list.c
new file mode 100644
index 0000000..7c54e50
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/list.c
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2016 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Singly-linked list functions.
+ */
+
+/** @private */
+JAYLINK_PRIV struct list *list_prepend(struct list *list, void *data)
+{
+ struct list *item;
+
+ item = malloc(sizeof(struct list));
+
+ if (!item)
+ return NULL;
+
+ item->data = data;
+ item->next = list;
+
+ return item;
+}
+
+/** @private */
+JAYLINK_PRIV struct list *list_remove(struct list *list, const void *data)
+{
+ struct list *item;
+ struct list *tmp;
+
+ if (!list)
+ return NULL;
+
+ item = list;
+
+ if (item->data == data) {
+ tmp = item->next;
+ free(item);
+ return tmp;
+ }
+
+ while (item->next) {
+ if (item->next->data == data) {
+ tmp = item->next;
+ item->next = item->next->next;
+ free(tmp);
+ break;
+ }
+
+ item = item->next;
+ }
+
+ return list;
+}
+
+/** @private */
+JAYLINK_PRIV struct list *list_find_custom(struct list *list,
+ list_compare_callback callback, const void *user_data)
+{
+ if (!callback)
+ return NULL;
+
+ while (list) {
+ if (callback(list->data, user_data))
+ return list;
+
+ list = list->next;
+ }
+
+ return NULL;
+}
+
+/** @private */
+JAYLINK_PRIV size_t list_length(struct list *list)
+{
+ size_t length;
+
+ for (length = 0; list; length++)
+ list = list->next;
+
+ return length;
+}
+
+/** @private */
+JAYLINK_PRIV void list_free(struct list *list)
+{
+ struct list *tmp;
+
+ while (list) {
+ tmp = list;
+ list = list->next;
+ free(tmp);
+ }
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/log.c b/src/jtag/drivers/libjaylink/libjaylink/log.c
new file mode 100644
index 0000000..07ef172
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/log.c
@@ -0,0 +1,266 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Logging functions.
+ */
+
+/**
+ * Set the libjaylink log level.
+ *
+ * @param[in,out] ctx libjaylink context.
+ * @param[in] level Log level to set.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_log_set_level(struct jaylink_context *ctx,
+ enum jaylink_log_level level)
+{
+ if (!ctx)
+ return JAYLINK_ERR_ARG;
+
+ if (level > JAYLINK_LOG_LEVEL_DEBUG_IO)
+ return JAYLINK_ERR_ARG;
+
+ ctx->log_level = level;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Get the libjaylink log level.
+ *
+ * @param[in] ctx libjaylink context.
+ * @param[out] level Log level on success, and undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_log_get_level(const struct jaylink_context *ctx,
+ enum jaylink_log_level *level)
+{
+ if (!ctx || !level)
+ return JAYLINK_ERR_ARG;
+
+ *level = ctx->log_level;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Set the libjaylink log callback function.
+ *
+ * @param[in,out] ctx libjaylink context.
+ * @param[in] callback Callback function to use, or NULL to use the default log
+ * function.
+ * @param[in] user_data User data to be passed to the callback function.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_log_set_callback(struct jaylink_context *ctx,
+ jaylink_log_callback callback, void *user_data)
+{
+ if (!ctx)
+ return JAYLINK_ERR_ARG;
+
+ if (callback) {
+ ctx->log_callback = callback;
+ ctx->log_callback_data = user_data;
+ } else {
+ ctx->log_callback = &log_vprintf;
+ ctx->log_callback_data = NULL;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Set the libjaylink log domain.
+ *
+ * The log domain is a string which is used as prefix for all log messages to
+ * differentiate them from messages of other libraries.
+ *
+ * The maximum length of the log domain is #JAYLINK_LOG_DOMAIN_MAX_LENGTH
+ * bytes, excluding the trailing null-terminator. A log domain which exceeds
+ * this length will be silently truncated.
+ *
+ * @param[in,out] ctx libjaylink context.
+ * @param[in] domain Log domain to use. To set the default log domain, use
+ * #JAYLINK_LOG_DOMAIN_DEFAULT.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_log_set_domain(struct jaylink_context *ctx,
+ const char *domain)
+{
+ int ret;
+
+ if (!ctx || !domain)
+ return JAYLINK_ERR_ARG;
+
+ ret = snprintf(ctx->log_domain, JAYLINK_LOG_DOMAIN_MAX_LENGTH + 1,
+ "%s", domain);
+
+ if (ret < 0)
+ return JAYLINK_ERR;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Get the libjaylink log domain.
+ *
+ * @param[in] ctx libjaylink context.
+ *
+ * @return A string which contains the current log domain on success, or NULL
+ * on failure. The string is null-terminated and must not be free'd by
+ * the caller.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API const char *jaylink_log_get_domain(
+ const struct jaylink_context *ctx)
+{
+ if (!ctx)
+ return NULL;
+
+ return ctx->log_domain;
+}
+
+/** @private */
+JAYLINK_PRIV int log_vprintf(const struct jaylink_context *ctx,
+ enum jaylink_log_level level, const char *format, va_list args,
+ void *user_data)
+{
+ (void)user_data;
+
+ /*
+ * Filter out messages with higher verbosity than the verbosity of the
+ * current log level.
+ */
+ if (level > ctx->log_level)
+ return 0;
+
+ if (ctx->log_domain[0] != '\0')
+ fprintf(stderr, "%s", ctx->log_domain);
+
+ vfprintf(stderr, format, args);
+ fprintf(stderr, "\n");
+
+ return 0;
+}
+
+/** @private */
+JAYLINK_PRIV void log_err(const struct jaylink_context *ctx,
+ const char *format, ...)
+{
+ va_list args;
+
+ if (!ctx)
+ return;
+
+ va_start(args, format);
+ ctx->log_callback(ctx, JAYLINK_LOG_LEVEL_ERROR, format, args,
+ ctx->log_callback_data);
+ va_end(args);
+}
+
+/** @private */
+JAYLINK_PRIV void log_warn(const struct jaylink_context *ctx,
+ const char *format, ...)
+{
+ va_list args;
+
+ if (!ctx)
+ return;
+
+ va_start(args, format);
+ ctx->log_callback(ctx, JAYLINK_LOG_LEVEL_WARNING, format, args,
+ ctx->log_callback_data);
+ va_end(args);
+}
+
+/** @private */
+JAYLINK_PRIV void log_info(const struct jaylink_context *ctx,
+ const char *format, ...)
+{
+ va_list args;
+
+ if (!ctx)
+ return;
+
+ va_start(args, format);
+ ctx->log_callback(ctx, JAYLINK_LOG_LEVEL_INFO, format, args,
+ ctx->log_callback_data);
+ va_end(args);
+}
+
+/** @private */
+JAYLINK_PRIV void log_dbg(const struct jaylink_context *ctx,
+ const char *format, ...)
+{
+ va_list args;
+
+ if (!ctx)
+ return;
+
+ va_start(args, format);
+ ctx->log_callback(ctx, JAYLINK_LOG_LEVEL_DEBUG, format, args,
+ ctx->log_callback_data);
+ va_end(args);
+}
+
+/** @private */
+JAYLINK_PRIV void log_dbgio(const struct jaylink_context *ctx,
+ const char *format, ...)
+{
+ va_list args;
+
+ if (!ctx)
+ return;
+
+ va_start(args, format);
+ ctx->log_callback(ctx, JAYLINK_LOG_LEVEL_DEBUG_IO, format, args,
+ ctx->log_callback_data);
+ va_end(args);
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/socket.c b/src/jtag/drivers/libjaylink/libjaylink/socket.c
new file mode 100644
index 0000000..f2a6588
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/socket.c
@@ -0,0 +1,257 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2016-2017 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#endif
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Socket abstraction layer.
+ */
+
+/**
+ * Close a socket.
+ *
+ * @param[in] sock Socket descriptor.
+ *
+ * @return Whether the socket was successfully closed.
+ */
+JAYLINK_PRIV bool socket_close(int sock)
+{
+ int ret;
+
+#ifdef _WIN32
+ ret = closesocket(sock);
+#else
+ ret = close(sock);
+#endif
+
+ if (!ret)
+ return true;
+
+ return false;
+}
+
+/**
+ * Bind an address to a socket.
+ *
+ * @param[in] sock Socket descriptor.
+ * @param[in] address Address to be bound to the socket.
+ * @param[in] length Length of the structure pointed to by @p address in bytes.
+ *
+ * @return Whether the address was successfully assigned to the socket.
+ */
+JAYLINK_PRIV bool socket_bind(int sock, const struct sockaddr *address,
+ size_t length)
+{
+ int ret;
+
+ ret = bind(sock, address, length);
+
+#ifdef _WIN32
+ if (ret == SOCKET_ERROR)
+ return false;
+#else
+ if (ret < 0)
+ return false;
+#endif
+
+ return true;
+}
+
+/**
+ * Send a message on a socket.
+ *
+ * @param[in] sock Socket descriptor.
+ * @param[in] buffer Buffer of the message to be sent.
+ * @param[in,out] length Length of the message in bytes. On success, the value
+ * gets updated with the actual number of bytes sent. The
+ * value is undefined on failure.
+ * @param[in] flags Flags to modify the function behaviour. Use bitwise OR to
+ * specify multiple flags.
+ *
+ * @return Whether the message was sent successfully.
+ */
+JAYLINK_PRIV bool socket_send(int sock, const void *buffer, size_t *length,
+ int flags)
+{
+ ssize_t ret;
+
+ ret = send(sock, buffer, *length, flags);
+#ifdef _WIN32
+ if (ret == SOCKET_ERROR)
+ return false;
+#else
+ if (ret < 0)
+ return false;
+#endif
+ *length = ret;
+
+ return true;
+}
+
+/**
+ * Receive a message from a socket.
+ *
+ * @param[in] sock Socket descriptor.
+ * @param[out] buffer Buffer to store the received message on success. Its
+ * content is undefined on failure.
+ * @param[in,out] length Maximum length of the message in bytes. On success,
+ * the value gets updated with the actual number of
+ * received bytes. The value is undefined on failure.
+ * @param[in] flags Flags to modify the function behaviour. Use bitwise OR to
+ * specify multiple flags.
+ *
+ * @return Whether a message was successfully received.
+ */
+JAYLINK_PRIV bool socket_recv(int sock, void *buffer, size_t *length,
+ int flags)
+{
+ ssize_t ret;
+
+ ret = recv(sock, buffer, *length, flags);
+
+#ifdef _WIN32
+ if (ret == SOCKET_ERROR)
+ return false;
+#else
+ if (ret < 0)
+ return false;
+#endif
+
+ *length = ret;
+
+ return true;
+}
+
+/**
+ * Send a message on a socket.
+ *
+ * @param[in] sock Socket descriptor.
+ * @param[in] buffer Buffer to send message from.
+ * @param[in,out] length Number of bytes to send. On success, the value gets
+ * updated with the actual number of bytes sent. The
+ * value is undefined on failure.
+ * @param[in] flags Flags to modify the function behaviour. Use bitwise OR to
+ * specify multiple flags.
+ * @param[in] address Destination address of the message.
+ * @param[in] address_length Length of the structure pointed to by @p address
+ * in bytes.
+ *
+ * @return Whether the message was successfully sent.
+ */
+JAYLINK_PRIV bool socket_sendto(int sock, const void *buffer, size_t *length,
+ int flags, const struct sockaddr *address,
+ size_t address_length)
+{
+ ssize_t ret;
+
+ ret = sendto(sock, buffer, *length, flags, address, address_length);
+
+#ifdef _WIN32
+ if (ret == SOCKET_ERROR)
+ return false;
+#else
+ if (ret < 0)
+ return false;
+#endif
+
+ *length = ret;
+
+ return true;
+}
+
+/**
+ * Receive a message from a socket.
+ *
+ * @param[in] sock Socket descriptor.
+ * @param[out] buffer Buffer to store the received message on success. Its
+ * content is undefined on failure.
+ * @param[in,out] length Maximum length of the message in bytes. On success,
+ * the value gets updated with the actual number of
+ * received bytes. The value is undefined on failure.
+ * @param[in] flags Flags to modify the function behaviour. Use bitwise OR to
+ * specify multiple flags.
+ * @param[out] address Structure to store the source address of the message on
+ * success. Its content is undefined on failure.
+ * Can be NULL.
+ * @param[in,out] address_length Length of the structure pointed to by
+ * @p address in bytes. On success, the value
+ * gets updated with the actual length of the
+ * structure. The value is undefined on failure.
+ * Should be NULL if @p address is NULL.
+ *
+ * @return Whether a message was successfully received.
+ */
+JAYLINK_PRIV bool socket_recvfrom(int sock, void *buffer, size_t *length,
+ int flags, struct sockaddr *address, size_t *address_length)
+{
+ ssize_t ret;
+#ifdef _WIN32
+ int tmp;
+
+ tmp = *address_length;
+ ret = recvfrom(sock, buffer, *length, flags, address, &tmp);
+
+ if (ret == SOCKET_ERROR)
+ return false;
+#else
+ socklen_t tmp;
+
+ tmp = *address_length;
+ ret = recvfrom(sock, buffer, *length, flags, address, &tmp);
+
+ if (ret < 0)
+ return false;
+#endif
+
+ *address_length = tmp;
+ *length = ret;
+
+ return true;
+}
+
+/**
+ * Set an option on a socket.
+ *
+ * @param[in] sock Socket descriptor.
+ * @param[in] level Level at which the option is defined.
+ * @param[in] option Option to set the value for.
+ * @param[in] value Buffer of the value to be set.
+ * @param[in] length Length of the value buffer in bytes.
+ *
+ * @return Whether the option was set successfully.
+ */
+JAYLINK_PRIV bool socket_set_option(int sock, int level, int option,
+ const void *value, size_t length)
+{
+ if (!setsockopt(sock, level, option, value, length))
+ return true;
+
+ return false;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/strutil.c b/src/jtag/drivers/libjaylink/libjaylink/strutil.c
new file mode 100644
index 0000000..283ed17
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/strutil.c
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2016 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "libjaylink.h"
+
+/**
+ * @file
+ *
+ * String utility functions.
+ */
+
+/**
+ * Convert a string representation of a serial number to an integer.
+ *
+ * The string representation of the serial number must be in decimal form.
+ *
+ * @param[in] str String representation to convert.
+ * @param[out] serial_number Serial number on success, and undefined on
+ * failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR Conversion error. Serial number is invalid or string
+ * representation contains invalid character(s).
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_parse_serial_number(const char *str,
+ uint32_t *serial_number)
+{
+ char *end_ptr;
+ unsigned long long tmp;
+
+ if (!str || !serial_number)
+ return JAYLINK_ERR_ARG;
+
+ errno = 0;
+ tmp = strtoull(str, &end_ptr, 10);
+
+ if (*end_ptr != '\0' || errno != 0 || tmp > UINT32_MAX)
+ return JAYLINK_ERR;
+
+ *serial_number = tmp;
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/swd.c b/src/jtag/drivers/libjaylink/libjaylink/swd.c
new file mode 100644
index 0000000..29265b7
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/swd.c
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Serial Wire Debug (SWD) functions.
+ */
+
+/** @cond PRIVATE */
+#define CMD_SWD_IO 0xcf
+
+/**
+ * Error code indicating that there is not enough free memory on the device to
+ * perform the SWD I/O operation.
+ */
+#define SWD_IO_ERR_NO_MEMORY 0x06
+/** @endcond */
+
+/**
+ * Perform a SWD I/O operation.
+ *
+ * @note This function must only be used if the #JAYLINK_TIF_SWD interface is
+ * available and selected.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] direction Buffer to read the transfer direction from.
+ * @param[in] out Buffer to read host-to-target data from.
+ * @param[out] in Buffer to store target-to-host data on success. Its content
+ * is undefined on failure. The buffer must be large enough to
+ * contain at least the specified number of bits to transfer.
+ * @param[in] length Total number of bits to transfer from host to target and
+ * vice versa.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV_NO_MEMORY Not enough memory on the device to perform
+ * the operation.
+ * @retval JAYLINK_ERR_DEV Unspecified device error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_select_interface()
+ * @see jaylink_set_speed()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_swd_io(struct jaylink_device_handle *devh,
+ const uint8_t *direction, const uint8_t *out, uint8_t *in,
+ uint16_t length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint16_t num_bytes;
+ uint8_t buf[4];
+ uint8_t status;
+
+ if (!devh || !direction || !out || !in || !length)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ num_bytes = (length + 7) / 8;
+
+ ret = transport_start_write_read(devh, 4 + 2 * num_bytes,
+ num_bytes + 1, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_SWD_IO;
+ buf[1] = 0x00;
+ buffer_set_u16(buf, length, 2);
+
+ ret = transport_write(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_write(devh, direction, num_bytes);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_write(devh, out, num_bytes);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, in, num_bytes);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, &status, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ if (status == SWD_IO_ERR_NO_MEMORY) {
+ return JAYLINK_ERR_DEV_NO_MEMORY;
+ } else if (status > 0) {
+ log_err(ctx, "SWD I/O operation failed: 0x%x.", status);
+ return JAYLINK_ERR_DEV;
+ }
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/swo.c b/src/jtag/drivers/libjaylink/libjaylink/swo.c
new file mode 100644
index 0000000..6037f64
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/swo.c
@@ -0,0 +1,453 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Serial Wire Output (SWO) functions.
+ */
+
+/** @cond PRIVATE */
+#define CMD_SWO 0xeb
+
+#define SWO_CMD_START 0x64
+#define SWO_CMD_STOP 0x65
+#define SWO_CMD_READ 0x66
+#define SWO_CMD_GET_SPEEDS 0x6e
+
+#define SWO_PARAM_MODE 0x01
+#define SWO_PARAM_BAUDRATE 0x02
+#define SWO_PARAM_READ_SIZE 0x03
+#define SWO_PARAM_BUFFER_SIZE 0x04
+
+#define SWO_ERR 0x80000000
+/** @endcond */
+
+/**
+ * Start SWO capture.
+ *
+ * @note This function must be used only if the device has the
+ * #JAYLINK_DEV_CAP_SWO capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] mode Mode to capture data with.
+ * @param[in] baudrate Baudrate to capture data in bit per second.
+ * @param[in] size Device internal buffer size in bytes to use for capturing.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV Unspecified device error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_swo_get_speeds()
+ * @see jaylink_get_free_memory()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_swo_start(struct jaylink_device_handle *devh,
+ enum jaylink_swo_mode mode, uint32_t baudrate, uint32_t size)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[32];
+ uint32_t status;
+
+ if (!devh || !baudrate || !size)
+ return JAYLINK_ERR_ARG;
+
+ if (mode != JAYLINK_SWO_MODE_UART)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 21, 4, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_SWO;
+ buf[1] = SWO_CMD_START;
+
+ buf[2] = 0x04;
+ buf[3] = SWO_PARAM_MODE;
+ buffer_set_u32(buf, mode, 4);
+
+ buf[8] = 0x04;
+ buf[9] = SWO_PARAM_BAUDRATE;
+ buffer_set_u32(buf, baudrate, 10);
+
+ buf[14] = 0x04;
+ buf[15] = SWO_PARAM_BUFFER_SIZE;
+ buffer_set_u32(buf, size, 16);
+
+ buf[20] = 0x00;
+
+ ret = transport_write(devh, buf, 21);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ status = buffer_get_u32(buf, 0);
+
+ if (status > 0) {
+ log_err(ctx, "Failed to start capture: 0x%x.", status);
+ return JAYLINK_ERR_DEV;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Stop SWO capture.
+ *
+ * @note This function must be used only if the device has the
+ * #JAYLINK_DEV_CAP_SWO capability.
+ *
+ * @param[in,out] devh Device handle.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV Unspecified device error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_swo_start()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_swo_stop(struct jaylink_device_handle *devh)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[4];
+ uint32_t status;
+
+ if (!devh)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 3, 4, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_SWO;
+ buf[1] = SWO_CMD_STOP;
+ buf[2] = 0x00;
+
+ ret = transport_write(devh, buf, 3);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ status = buffer_get_u32(buf, 0);
+
+ if (status > 0) {
+ log_err(ctx, "Failed to stop capture: 0x%x.", status);
+ return JAYLINK_ERR_DEV;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Read SWO trace data.
+ *
+ * @note This function must be used only if the device has the
+ * #JAYLINK_DEV_CAP_SWO capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] buffer Buffer to store trace data on success. Its content is
+ * undefined on failure.
+ * @param[in,out] length Maximum number of bytes to read. On success, the value
+ * gets updated with the actual number of bytes read. The
+ * value is undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_PROTO Protocol violation.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV Unspecified device error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_swo_start()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_swo_read(struct jaylink_device_handle *devh,
+ uint8_t *buffer, uint32_t *length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[32];
+ uint32_t status;
+ uint32_t tmp;
+
+ if (!devh || !buffer || !length)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 9, 8, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_SWO;
+ buf[1] = SWO_CMD_READ;
+
+ buf[2] = 0x04;
+ buf[3] = SWO_PARAM_READ_SIZE;
+ buffer_set_u32(buf, *length, 4);
+
+ buf[8] = 0x00;
+
+ ret = transport_write(devh, buf, 9);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 8);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ status = buffer_get_u32(buf, 0);
+ tmp = buffer_get_u32(buf, 4);
+
+ if (tmp > *length) {
+ log_err(ctx, "Received %u bytes but only %u bytes were "
+ "requested.", tmp, *length);
+ return JAYLINK_ERR_PROTO;
+ }
+
+ *length = tmp;
+
+ if (tmp > 0) {
+ ret = transport_start_read(devh, tmp);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buffer, tmp);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+ }
+
+ if (status > 0) {
+ log_err(ctx, "Failed to read data: 0x%x.", status);
+ return JAYLINK_ERR_DEV;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve SWO speeds.
+
+ * The speeds are calculated as follows:
+ *
+ * @par
+ * <tt>speeds = @a freq / n</tt> with <tt>n >= @a min_div</tt> and
+ * <tt>n <= @a max_div</tt>, where @p n is an integer
+ *
+ * Assuming, for example, a base frequency @a freq of 4500 kHz, a minimum
+ * divider @a min_div of 1 and a maximum divider @a max_div of 8 then the
+ * highest possible SWO speed is 4500 kHz / 1 = 4500 kHz. The next highest
+ * speed is 2250 kHz for a divider of 2, and so on. Accordingly, the lowest
+ * possible speed is 4500 kHz / 8 = 562.5 kHz.
+ *
+ * @note This function must be used only if the device has the
+ * #JAYLINK_DEV_CAP_SWO capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] mode Capture mode to retrieve speeds for.
+ * @param[out] speed Speed information on success, and undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_PROTO Protocol violation.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR_DEV Unspecified device error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_swo_get_speeds(struct jaylink_device_handle *devh,
+ enum jaylink_swo_mode mode, struct jaylink_swo_speed *speed)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[24];
+ uint32_t tmp;
+ uint32_t length;
+
+ if (!devh || !speed)
+ return JAYLINK_ERR_ARG;
+
+ if (mode != JAYLINK_SWO_MODE_UART)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 9, 4, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_SWO;
+ buf[1] = SWO_CMD_GET_SPEEDS;
+
+ buf[2] = 0x04;
+ buf[3] = SWO_PARAM_MODE;
+ buffer_set_u32(buf, mode, 4);
+
+ buf[8] = 0x00;
+
+ ret = transport_write(devh, buf, 9);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ tmp = buffer_get_u32(buf, 0);
+
+ if (tmp & SWO_ERR) {
+ log_err(ctx, "Failed to retrieve speed information: 0x%x.",
+ tmp);
+ return JAYLINK_ERR_DEV;
+ }
+
+ length = tmp;
+
+ if (length != 28) {
+ log_err(ctx, "Unexpected number of bytes received: %u.",
+ length);
+ return JAYLINK_ERR_PROTO;
+ }
+
+ length = length - 4;
+ ret = transport_start_read(devh, length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ speed->freq = buffer_get_u32(buf, 4);
+ speed->min_div = buffer_get_u32(buf, 8);
+
+ if (!speed->min_div) {
+ log_err(ctx, "Minimum frequency divider is zero.");
+ return JAYLINK_ERR_PROTO;
+ }
+
+ speed->max_div = buffer_get_u32(buf, 12);
+
+ if (speed->max_div < speed->min_div) {
+ log_err(ctx, "Maximum frequency divider is less than minimum "
+ "frequency divider.");
+ return JAYLINK_ERR_PROTO;
+ }
+
+ speed->min_prescaler = buffer_get_u32(buf, 16);
+ speed->max_prescaler = buffer_get_u32(buf, 20);
+
+ if (speed->max_prescaler < speed->min_prescaler) {
+ log_err(ctx, "Maximum prescaler is less than minimum "
+ "prescaler.");
+ return JAYLINK_ERR_PROTO;
+ }
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/target.c b/src/jtag/drivers/libjaylink/libjaylink/target.c
new file mode 100644
index 0000000..264335b
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/target.c
@@ -0,0 +1,533 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Target related functions.
+ */
+
+/** @cond PRIVATE */
+#define CMD_SET_SPEED 0x05
+#define CMD_SET_TARGET_POWER 0x08
+#define CMD_GET_SPEEDS 0xc0
+#define CMD_SELECT_TIF 0xc7
+#define CMD_CLEAR_RESET 0xdc
+#define CMD_SET_RESET 0xdd
+
+#define TIF_GET_SELECTED 0xfe
+#define TIF_GET_AVAILABLE 0xff
+/** @endcond */
+
+/**
+ * Set the target interface speed.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] speed Speed in kHz or #JAYLINK_SPEED_ADAPTIVE_CLOCKING for
+ * adaptive clocking. Speed of 0 kHz is not allowed and
+ * adaptive clocking must only be used if the device has the
+ * #JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING capability.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_get_speeds()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_set_speed(struct jaylink_device_handle *devh,
+ uint16_t speed)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[3];
+
+ if (!devh || !speed)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 3, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_SET_SPEED;
+ buffer_set_u16(buf, speed, 1);
+
+ ret = transport_write(devh, buf, 3);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve target interface speeds.
+ *
+ * The speeds are applicable for the currently selected target interface only
+ * and calculated as follows:
+ *
+ * @par
+ * <tt>speeds = @a freq / n</tt> with <tt>n >= @a div</tt>, where @p n is an
+ * integer
+ *
+ * Assuming, for example, a base frequency @a freq of 4 MHz and a minimum
+ * divider @a div of 4 then the highest possible target interface speed is
+ * 4 MHz / 4 = 1 MHz. The next highest speed is 800 kHz for a divider of 5, and
+ * so on.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_GET_SPEEDS capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] speed Speed information on success, and undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_PROTO Protocol violation.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_select_interface()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_get_speeds(struct jaylink_device_handle *devh,
+ struct jaylink_speed *speed)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[6];
+ uint16_t div;
+
+ if (!devh || !speed)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 1, 6, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_GET_SPEEDS;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 6);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ div = buffer_get_u16(buf, 4);
+
+ if (!div) {
+ log_err(ctx, "Minimum frequency divider is zero.");
+ return JAYLINK_ERR_PROTO;
+ }
+
+ speed->freq = buffer_get_u32(buf, 0);
+ speed->div = div;
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Select the target interface.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_SELECT_TIF capability.
+ *
+ * @warning This function may return a value for @p prev_iface which is not
+ * covered by #jaylink_target_interface.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] iface Target interface to select.
+ * @param[out] prev_iface Previously selected target interface on success, and
+ * undefined on failure. Can be NULL.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_get_available_interfaces()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_select_interface(struct jaylink_device_handle *devh,
+ enum jaylink_target_interface iface,
+ enum jaylink_target_interface *prev_iface)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[4];
+
+ if (!devh)
+ return JAYLINK_ERR_ARG;
+
+ switch (iface) {
+ case JAYLINK_TIF_JTAG:
+ case JAYLINK_TIF_SWD:
+ case JAYLINK_TIF_BDM3:
+ case JAYLINK_TIF_FINE:
+ case JAYLINK_TIF_2W_JTAG_PIC32:
+ break;
+ default:
+ return JAYLINK_ERR_ARG;
+ }
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 2, 4, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_SELECT_TIF;
+ buf[1] = iface;
+
+ ret = transport_write(devh, buf, 2);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ if (prev_iface)
+ *prev_iface = buffer_get_u32(buf, 0);
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve the available target interfaces.
+ *
+ * The target interfaces are stored in a 32-bit bit field where each individual
+ * bit represents a target interface. A set bit indicates an available target
+ * interface. See #jaylink_target_interface for a description of the target
+ * interfaces and their bit positions.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_SELECT_TIF capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] ifaces Target interfaces on success, and undefined on failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_select_interface()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_get_available_interfaces(
+ struct jaylink_device_handle *devh, uint32_t *ifaces)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[4];
+
+ if (!devh || !ifaces)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 2, 4, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_SELECT_TIF;
+ buf[1] = TIF_GET_AVAILABLE;
+
+ ret = transport_write(devh, buf, 2);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ *ifaces = buffer_get_u32(buf, 0);
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Retrieve the selected target interface.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_SELECT_TIF capability.
+ *
+ * @warning This function may return a value for @p iface which is not covered
+ * by #jaylink_target_interface.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] iface Selected target interface on success, and undefined on
+ * failure.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @see jaylink_select_interface()
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_get_selected_interface(
+ struct jaylink_device_handle *devh,
+ enum jaylink_target_interface *iface)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[4];
+
+ if (!devh || !iface)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write_read(devh, 2, 4, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_SELECT_TIF;
+ buf[1] = TIF_GET_SELECTED;
+
+ ret = transport_write(devh, buf, 2);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ ret = transport_read(devh, buf, 4);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_read() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ *iface = buffer_get_u32(buf, 0);
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Clear the target reset signal.
+ *
+ * @param[in,out] devh Device handle.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_clear_reset(struct jaylink_device_handle *devh)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[1];
+
+ if (!devh)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 1, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_CLEAR_RESET;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Set the target reset signal.
+ *
+ * @param[in,out] devh Device handle.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_set_reset(struct jaylink_device_handle *devh)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[1];
+
+ if (!devh)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 1, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_SET_RESET;
+
+ ret = transport_write(devh, buf, 1);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
+
+/**
+ * Set the target power supply.
+ *
+ * If enabled, the target is supplied with 5 V from pin 19 of the 20-pin
+ * JTAG / SWD connector.
+ *
+ * @note This function must only be used if the device has the
+ * #JAYLINK_DEV_CAP_SET_TARGET_POWER capability.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] enable Determines whether to enable or disable the target power
+ * supply.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_set_target_power(struct jaylink_device_handle *devh,
+ bool enable)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[2];
+
+ if (!devh)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+ ret = transport_start_write(devh, 2, true);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_start_wrte() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ buf[0] = CMD_SET_TARGET_POWER;
+ buf[1] = enable;
+
+ ret = transport_write(devh, buf, 2);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "transport_write() failed: %s.",
+ jaylink_strerror(ret));
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/transport.c b/src/jtag/drivers/libjaylink/libjaylink/transport.c
new file mode 100644
index 0000000..0c276b3
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/transport.c
@@ -0,0 +1,309 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Transport abstraction layer.
+ */
+
+/**
+ * Open a device.
+ *
+ * This function must be called before any other function of the transport
+ * abstraction layer for the given device handle is called.
+ *
+ * @param[in,out] devh Device handle.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ */
+JAYLINK_PRIV int transport_open(struct jaylink_device_handle *devh)
+{
+ int ret;
+
+ switch (devh->dev->iface) {
+#ifdef HAVE_LIBUSB
+ case JAYLINK_HIF_USB:
+ ret = transport_usb_open(devh);
+ break;
+#endif
+ case JAYLINK_HIF_TCP:
+ ret = transport_tcp_open(devh);
+ break;
+ default:
+ log_err(devh->dev->ctx, "BUG: Invalid host interface: %u.",
+ devh->dev->iface);
+ return JAYLINK_ERR;
+ }
+
+ return ret;
+}
+
+/**
+ * Close a device.
+ *
+ * After this function has been called no other function of the transport
+ * abstraction layer for the given device handle must be called.
+ *
+ * @param[in,out] devh Device handle.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR Other error conditions.
+ */
+JAYLINK_PRIV int transport_close(struct jaylink_device_handle *devh)
+{
+ int ret;
+
+ switch (devh->dev->iface) {
+#ifdef HAVE_LIBUSB
+ case JAYLINK_HIF_USB:
+ ret = transport_usb_close(devh);
+ break;
+#endif
+ case JAYLINK_HIF_TCP:
+ ret = transport_tcp_close(devh);
+ break;
+ default:
+ log_err(devh->dev->ctx, "BUG: Invalid host interface: %u.",
+ devh->dev->iface);
+ return JAYLINK_ERR;
+ }
+
+ return ret;
+}
+
+/**
+ * Start a write operation for a device.
+ *
+ * The data of a write operation must be written with at least one call of
+ * transport_write(). It is required that all data of a write operation is
+ * written before an other write and/or read operation is started.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] length Number of bytes of the write operation.
+ * @param[in] has_command Determines whether the data of the write operation
+ * contains the protocol command.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ */
+JAYLINK_PRIV int transport_start_write(struct jaylink_device_handle *devh,
+ size_t length, bool has_command)
+{
+ int ret;
+
+ switch (devh->dev->iface) {
+#ifdef HAVE_LIBUSB
+ case JAYLINK_HIF_USB:
+ ret = transport_usb_start_write(devh, length, has_command);
+ break;
+#endif
+ case JAYLINK_HIF_TCP:
+ ret = transport_tcp_start_write(devh, length, has_command);
+ break;
+ default:
+ log_err(devh->dev->ctx, "BUG: Invalid host interface: %u.",
+ devh->dev->iface);
+ return JAYLINK_ERR;
+ }
+
+ return ret;
+}
+
+/**
+ * Start a read operation for a device.
+ *
+ * The data of a read operation must be read with at least one call of
+ * transport_read(). It is required that all data of a read operation is read
+ * before an other write and/or read operation is started.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] length Number of bytes of the read operation.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ */
+JAYLINK_PRIV int transport_start_read(struct jaylink_device_handle *devh,
+ size_t length)
+{
+ int ret;
+
+ switch (devh->dev->iface) {
+#ifdef HAVE_LIBUSB
+ case JAYLINK_HIF_USB:
+ ret = transport_usb_start_read(devh, length);
+ break;
+#endif
+ case JAYLINK_HIF_TCP:
+ ret = transport_tcp_start_read(devh, length);
+ break;
+ default:
+ log_err(devh->dev->ctx, "BUG: Invalid host interface: %u.",
+ devh->dev->iface);
+ return JAYLINK_ERR;
+ }
+
+ return ret;
+}
+
+/**
+ * Start a write and read operation for a device.
+ *
+ * This function starts a write and read operation as the consecutive call of
+ * transport_start_write() and transport_start_read() but has a different
+ * meaning from the protocol perspective and can therefore not be replaced by
+ * these functions and vice versa.
+ *
+ * @note The write operation must be completed first before the read operation
+ * must be processed.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] write_length Number of bytes of the write operation.
+ * @param[in] read_length Number of bytes of the read operation.
+ * @param[in] has_command Determines whether the data of the write operation
+ * contains the protocol command.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ */
+JAYLINK_PRIV int transport_start_write_read(struct jaylink_device_handle *devh,
+ size_t write_length, size_t read_length, bool has_command)
+{
+ int ret;
+
+ switch (devh->dev->iface) {
+#ifdef HAVE_LIBUSB
+ case JAYLINK_HIF_USB:
+ ret = transport_usb_start_write_read(devh, write_length,
+ read_length, has_command);
+ break;
+#endif
+ case JAYLINK_HIF_TCP:
+ ret = transport_tcp_start_write_read(devh, write_length,
+ read_length, has_command);
+ break;
+ default:
+ log_err(devh->dev->ctx, "BUG: Invalid host interface: %u.",
+ devh->dev->iface);
+ return JAYLINK_ERR;
+ }
+
+ return ret;
+}
+
+/**
+ * Write data to a device.
+ *
+ * Before this function is used transport_start_write() or
+ * transport_start_write_read() must be called to start a write operation. The
+ * total number of written bytes must not exceed the number of bytes of the
+ * write operation.
+ *
+ * @note A write operation will be performed and the data will be sent to the
+ * device when the number of written bytes reaches the number of bytes of
+ * the write operation. Before that the data will be written into a
+ * buffer.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[in] buffer Buffer to write data from.
+ * @param[in] length Number of bytes to write.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ */
+JAYLINK_PRIV int transport_write(struct jaylink_device_handle *devh,
+ const uint8_t *buffer, size_t length)
+{
+ int ret;
+
+ switch (devh->dev->iface) {
+#ifdef HAVE_LIBUSB
+ case JAYLINK_HIF_USB:
+ ret = transport_usb_write(devh, buffer, length);
+ break;
+#endif
+ case JAYLINK_HIF_TCP:
+ ret = transport_tcp_write(devh, buffer, length);
+ break;
+ default:
+ log_err(devh->dev->ctx, "BUG: Invalid host interface: %u.",
+ devh->dev->iface);
+ return JAYLINK_ERR;
+ }
+
+ return ret;
+}
+
+/**
+ * Read data from a device.
+ *
+ * Before this function is used transport_start_read() or
+ * transport_start_write_read() must be called to start a read operation. The
+ * total number of read bytes must not exceed the number of bytes of the read
+ * operation.
+ *
+ * @param[in,out] devh Device handle.
+ * @param[out] buffer Buffer to read data into on success. Its content is
+ * undefined on failure.
+ * @param[in] length Number of bytes to read.
+ *
+ * @retval JAYLINK_OK Success.
+ * @retval JAYLINK_ERR_ARG Invalid arguments.
+ * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
+ * @retval JAYLINK_ERR_IO Input/output error.
+ * @retval JAYLINK_ERR Other error conditions.
+ */
+JAYLINK_PRIV int transport_read(struct jaylink_device_handle *devh,
+ uint8_t *buffer, size_t length)
+{
+ int ret;
+
+ switch (devh->dev->iface) {
+#ifdef HAVE_LIBUSB
+ case JAYLINK_HIF_USB:
+ ret = transport_usb_read(devh, buffer, length);
+ break;
+#endif
+ case JAYLINK_HIF_TCP:
+ ret = transport_tcp_read(devh, buffer, length);
+ break;
+ default:
+ log_err(devh->dev->ctx, "BUG: Invalid host interface: %u.",
+ devh->dev->iface);
+ return JAYLINK_ERR;
+ }
+
+ return ret;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/transport_tcp.c b/src/jtag/drivers/libjaylink/libjaylink/transport_tcp.c
new file mode 100644
index 0000000..7e10179
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/transport_tcp.c
@@ -0,0 +1,601 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2015-2017 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#endif
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Transport abstraction layer (TCP/IP).
+ */
+
+/** @cond PRIVATE */
+#define CMD_SERVER 0x00
+#define CMD_CLIENT 0x07
+
+/**
+ * Response status code indicating that the maximum number of simultaneous
+ * connections on the device has been reached.
+ */
+#define RESP_MAX_CONNECTIONS 0xfe
+
+/** Buffer size in bytes. */
+#define BUFFER_SIZE 2048
+
+/** Timeout of a receive operation in milliseconds. */
+#define RECV_TIMEOUT 5000
+/** Timeout of a send operation in milliseconds. */
+#define SEND_TIMEOUT 5000
+
+/** String of the port number for the J-Link TCP/IP protocol. */
+#define PORT_STRING "19020"
+
+/** Size of the server's hello message in bytes. */
+#define SERVER_HELLO_SIZE 4
+/**
+ * Maximum length of the server name including trailing null-terminator in
+ * bytes.
+ */
+#define SERVER_NAME_MAX_LENGTH 256
+/** @endcond */
+
+static int initialize_handle(struct jaylink_device_handle *devh)
+{
+ struct jaylink_context *ctx;
+
+ ctx = devh->dev->ctx;
+
+ devh->buffer_size = BUFFER_SIZE;
+ devh->buffer = malloc(devh->buffer_size);
+
+ if (!devh->buffer) {
+ log_err(ctx, "Transport buffer malloc failed.");
+ return JAYLINK_ERR_MALLOC;
+ }
+
+ devh->read_length = 0;
+ devh->bytes_available = 0;
+ devh->read_pos = 0;
+
+ devh->write_length = 0;
+ devh->write_pos = 0;
+
+ return JAYLINK_OK;
+}
+
+static void cleanup_handle(struct jaylink_device_handle *devh)
+{
+ free(devh->buffer);
+}
+
+static int _recv(struct jaylink_device_handle *devh, uint8_t *buffer,
+ size_t length)
+{
+ struct jaylink_context *ctx;
+ size_t tmp;
+
+ ctx = devh->dev->ctx;
+
+ while (length > 0) {
+ tmp = length;
+
+ if (!socket_recv(devh->sock, buffer, &tmp, 0)) {
+ log_err(ctx, "Failed to receive data from device.");
+ return JAYLINK_ERR_IO;
+ } else if (!tmp) {
+ log_err(ctx, "Failed to receive data from device: "
+ "remote connection closed.");
+ return JAYLINK_ERR_IO;
+ }
+
+ buffer += tmp;
+ length -= tmp;
+
+ log_dbgio(ctx, "Received %zu bytes from device.", tmp);
+ }
+
+ return JAYLINK_OK;
+}
+
+static int handle_server_hello(struct jaylink_device_handle *devh)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ uint8_t buf[SERVER_HELLO_SIZE];
+ char name[SERVER_NAME_MAX_LENGTH];
+ uint16_t proto_version;
+ size_t length;
+
+ ctx = devh->dev->ctx;
+
+ ret = _recv(devh, buf, sizeof(buf));
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "Failed to receive hello message.");
+ return ret;
+ }
+
+ if (buf[0] == RESP_MAX_CONNECTIONS) {
+ log_err(ctx, "Maximum number of connections reached.");
+ return JAYLINK_ERR;
+ }
+
+ if (buf[0] != CMD_SERVER) {
+ log_err(ctx, "Invalid hello message received.");
+ return JAYLINK_ERR_PROTO;
+ }
+
+ proto_version = buffer_get_u16(buf, 1);
+
+ log_dbg(ctx, "Protocol version: 0x%04x.", proto_version);
+
+ length = buf[3];
+ ret = _recv(devh, (uint8_t *)name, length);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "Failed to receive server name.");
+ return ret;
+ }
+
+ name[length] = '\0';
+
+ log_dbg(ctx, "Server name: %s.", name);
+
+ return JAYLINK_OK;
+}
+
+static int set_socket_timeouts(struct jaylink_device_handle *devh)
+{
+ struct jaylink_context *ctx;
+
+ ctx = devh->dev->ctx;
+#ifdef _WIN32
+ DWORD timeout;
+
+ timeout = RECV_TIMEOUT;
+
+ if (!socket_set_option(devh->sock, SOL_SOCKET, SO_RCVTIMEO, &timeout,
+ sizeof(timeout))) {
+ log_err(ctx, "Failed to set socket receive timeout.");
+ return JAYLINK_ERR;
+ }
+
+ timeout = SEND_TIMEOUT;
+
+ if (!socket_set_option(devh->sock, SOL_SOCKET, SO_SNDTIMEO, &timeout,
+ sizeof(timeout))) {
+ log_err(ctx, "Failed to set socket send timeout.");
+ return JAYLINK_ERR;
+ }
+#else
+ struct timeval timeout;
+
+ timeout.tv_sec = RECV_TIMEOUT / 1000;
+ timeout.tv_usec = (RECV_TIMEOUT % 1000) * 1000;
+
+ if (!socket_set_option(devh->sock, SOL_SOCKET, SO_RCVTIMEO, &timeout,
+ sizeof(struct timeval))) {
+ log_err(ctx, "Failed to set socket receive timeout.");
+ return JAYLINK_ERR;
+ }
+
+ timeout.tv_sec = SEND_TIMEOUT / 1000;
+ timeout.tv_usec = (SEND_TIMEOUT % 1000) * 1000;
+
+ if (!socket_set_option(devh->sock, SOL_SOCKET, SO_SNDTIMEO, &timeout,
+ sizeof(struct timeval))) {
+ log_err(ctx, "Failed to set socket send timeout.");
+ return JAYLINK_ERR;
+ }
+#endif
+ return JAYLINK_OK;
+}
+
+JAYLINK_PRIV int transport_tcp_open(struct jaylink_device_handle *devh)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ struct jaylink_device *dev;
+ struct addrinfo hints;
+ struct addrinfo *info;
+ struct addrinfo *rp;
+ int sock;
+
+ dev = devh->dev;
+ ctx = dev->ctx;
+
+ log_dbg(ctx, "Trying to open device (IPv4 address = %s).",
+ dev->ipv4_address);
+
+ ret = initialize_handle(devh);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "Initialize device handle failed.");
+ return ret;
+ }
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ ret = getaddrinfo(dev->ipv4_address, PORT_STRING, &hints, &info);
+
+ if (ret != 0) {
+ log_err(ctx, "Address lookup failed.");
+ cleanup_handle(devh);
+ return JAYLINK_ERR;
+ }
+
+ sock = -1;
+
+ for (rp = info; rp != NULL; rp = rp->ai_next) {
+ sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+
+ if (sock < 0)
+ continue;
+
+ if (!connect(sock, info->ai_addr, info->ai_addrlen))
+ break;
+
+ socket_close(sock);
+ sock = -1;
+ }
+
+ freeaddrinfo(info);
+
+ if (sock < 0) {
+ log_err(ctx, "Failed to open device.");
+ cleanup_handle(devh);
+ return JAYLINK_ERR;
+ }
+
+ log_dbg(ctx, "Device opened successfully.");
+
+ devh->sock = sock;
+ ret = set_socket_timeouts(devh);
+
+ if (ret != JAYLINK_OK) {
+ socket_close(sock);
+ cleanup_handle(devh);
+ return ret;
+ }
+
+ ret = handle_server_hello(devh);
+
+ if (ret != JAYLINK_OK) {
+ socket_close(sock);
+ cleanup_handle(devh);
+ return ret;
+ }
+
+ return JAYLINK_OK;
+}
+
+JAYLINK_PRIV int transport_tcp_close(struct jaylink_device_handle *devh)
+{
+ struct jaylink_context *ctx;
+
+ ctx = devh->dev->ctx;
+
+ log_dbg(ctx, "Closing device (IPv4 address = %s).",
+ devh->dev->ipv4_address);
+
+ cleanup_handle(devh);
+
+ log_dbg(ctx, "Device closed successfully.");
+
+ return JAYLINK_OK;
+}
+
+JAYLINK_PRIV int transport_tcp_start_write(struct jaylink_device_handle *devh,
+ size_t length, bool has_command)
+{
+ struct jaylink_context *ctx;
+
+ if (!length)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+
+ log_dbgio(ctx, "Starting write operation (length = %zu bytes).",
+ length);
+
+ if (devh->write_pos > 0)
+ log_warn(ctx, "Last write operation left %zu bytes in the "
+ "buffer.", devh->write_pos);
+
+ if (devh->write_length > 0)
+ log_warn(ctx, "Last write operation was not performed.");
+
+ devh->write_length = length;
+ devh->write_pos = 0;
+
+ if (has_command) {
+ devh->buffer[0] = CMD_CLIENT;
+ devh->write_pos++;
+ }
+
+ return JAYLINK_OK;
+}
+
+JAYLINK_PRIV int transport_tcp_start_read(struct jaylink_device_handle *devh,
+ size_t length)
+{
+ struct jaylink_context *ctx;
+
+ if (!length)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+
+ log_dbgio(ctx, "Starting read operation (length = %zu bytes).",
+ length);
+
+ if (devh->bytes_available > 0)
+ log_dbg(ctx, "Last read operation left %zu bytes in the "
+ "buffer.", devh->bytes_available);
+
+ if (devh->read_length > 0)
+ log_warn(ctx, "Last read operation left %zu bytes.",
+ devh->read_length);
+
+ devh->read_length = length;
+
+ return JAYLINK_OK;
+}
+
+JAYLINK_PRIV int transport_tcp_start_write_read(
+ struct jaylink_device_handle *devh, size_t write_length,
+ size_t read_length, bool has_command)
+{
+ struct jaylink_context *ctx;
+
+ if (!read_length || !write_length)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+
+ log_dbgio(ctx, "Starting write / read operation (length = "
+ "%zu / %zu bytes).", write_length, read_length);
+
+ if (devh->write_pos > 0)
+ log_warn(ctx, "Last write operation left %zu bytes in the "
+ "buffer.", devh->write_pos);
+
+ if (devh->write_length > 0)
+ log_warn(ctx, "Last write operation was not performed.");
+
+ if (devh->bytes_available > 0)
+ log_warn(ctx, "Last read operation left %zu bytes in the "
+ "buffer.", devh->bytes_available);
+
+ if (devh->read_length > 0)
+ log_warn(ctx, "Last read operation left %zu bytes.",
+ devh->read_length);
+
+ devh->write_length = write_length;
+ devh->write_pos = 0;
+
+ if (has_command) {
+ devh->buffer[0] = CMD_CLIENT;
+ devh->write_pos++;
+ }
+
+ devh->read_length = read_length;
+ devh->bytes_available = 0;
+ devh->read_pos = 0;
+
+ return JAYLINK_OK;
+}
+
+static int _send(struct jaylink_device_handle *devh, const uint8_t *buffer,
+ size_t length)
+{
+ struct jaylink_context *ctx;
+ size_t tmp;
+
+ ctx = devh->dev->ctx;
+
+ while (length > 0) {
+ tmp = length;
+
+ if (!socket_send(devh->sock, buffer, &tmp, 0)) {
+ log_err(ctx, "Failed to send data to device.");
+ return JAYLINK_ERR_IO;
+ }
+
+ buffer += tmp;
+ length -= tmp;
+
+ log_dbgio(ctx, "Sent %zu bytes to device.", tmp);
+ }
+
+ return JAYLINK_OK;
+}
+
+static bool adjust_buffer(struct jaylink_device_handle *devh, size_t size)
+{
+ struct jaylink_context *ctx;
+ uint8_t *buffer;
+ size_t num;
+
+ ctx = devh->dev->ctx;
+
+ /* Adjust buffer size to a multiple of BUFFER_SIZE bytes. */
+ num = size / BUFFER_SIZE;
+
+ if (size % BUFFER_SIZE > 0)
+ num++;
+
+ size = num * BUFFER_SIZE;
+ buffer = realloc(devh->buffer, size);
+
+ if (!buffer) {
+ log_err(ctx, "Failed to adjust buffer size to %zu bytes.",
+ size);
+ return false;
+ }
+
+ devh->buffer = buffer;
+ devh->buffer_size = size;
+
+ log_dbg(ctx, "Adjusted buffer size to %zu bytes.", size);
+
+ return true;
+}
+
+JAYLINK_PRIV int transport_tcp_write(struct jaylink_device_handle *devh,
+ const uint8_t *buffer, size_t length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ size_t tmp;
+
+ ctx = devh->dev->ctx;
+
+ if (length > devh->write_length) {
+ log_err(ctx, "Requested to write %zu bytes but only %zu bytes "
+ "are expected for the write operation.", length,
+ devh->write_length);
+ return JAYLINK_ERR_ARG;
+ }
+
+ /*
+ * Store data in the buffer if the expected number of bytes for the
+ * write operation is not reached.
+ */
+ if (length < devh->write_length) {
+ if (devh->write_pos + length > devh->buffer_size) {
+ if (!adjust_buffer(devh, devh->write_pos + length))
+ return JAYLINK_ERR_MALLOC;
+ }
+
+ memcpy(devh->buffer + devh->write_pos, buffer, length);
+
+ devh->write_length -= length;
+ devh->write_pos += length;
+
+ log_dbgio(ctx, "Wrote %zu bytes into buffer.", length);
+ return JAYLINK_OK;
+ }
+
+ /*
+ * Expected number of bytes for this write operation is reached and
+ * therefore the write operation will be performed.
+ */
+ devh->write_length = 0;
+
+ /* Send data directly to the device if the buffer is empty. */
+ if (!devh->write_pos)
+ return _send(devh, buffer, length);
+
+ tmp = MIN(length, devh->buffer_size - devh->write_pos);
+
+ /*
+ * Fill up the internal buffer in order to reduce the number of
+ * messages sent to the device for performance reasons.
+ */
+ memcpy(devh->buffer + devh->write_pos, buffer, tmp);
+
+ length -= tmp;
+ buffer += tmp;
+
+ log_dbgio(ctx, "Buffer filled up with %zu bytes.", tmp);
+
+ ret = _send(devh, devh->buffer, devh->write_pos + tmp);
+
+ devh->write_pos = 0;
+
+ if (ret != JAYLINK_OK)
+ return ret;
+
+ if (!length)
+ return JAYLINK_OK;
+
+ return _send(devh, buffer, length);
+}
+
+JAYLINK_PRIV int transport_tcp_read(struct jaylink_device_handle *devh,
+ uint8_t *buffer, size_t length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+
+ ctx = devh->dev->ctx;
+
+ if (length > devh->read_length) {
+ log_err(ctx, "Requested to read %zu bytes but only %zu bytes "
+ "are expected for the read operation.", length,
+ devh->read_length);
+ return JAYLINK_ERR_ARG;
+ }
+
+ if (length <= devh->bytes_available) {
+ memcpy(buffer, devh->buffer + devh->read_pos, length);
+
+ devh->read_length -= length;
+ devh->bytes_available -= length;
+ devh->read_pos += length;
+
+ log_dbgio(ctx, "Read %zu bytes from buffer.", length);
+ return JAYLINK_OK;
+ }
+
+ if (devh->bytes_available) {
+ memcpy(buffer, devh->buffer + devh->read_pos,
+ devh->bytes_available);
+
+ buffer += devh->bytes_available;
+ length -= devh->bytes_available;
+ devh->read_length -= devh->bytes_available;
+
+ log_dbgio(ctx, "Read %zu bytes from buffer to flush it.",
+ devh->bytes_available);
+
+ devh->bytes_available = 0;
+ devh->read_pos = 0;
+ }
+
+ ret = _recv(devh, buffer, length);
+
+ if (ret != JAYLINK_OK)
+ return ret;
+
+ devh->read_length -= length;
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/transport_usb.c b/src/jtag/drivers/libjaylink/libjaylink/transport_usb.c
new file mode 100644
index 0000000..dfe9eac
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/transport_usb.c
@@ -0,0 +1,620 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2016 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "libjaylink.h"
+#include "libjaylink-internal.h"
+
+/**
+ * @file
+ *
+ * Transport abstraction layer (USB).
+ */
+
+/** Timeout of an USB transfer in milliseconds. */
+#define USB_TIMEOUT 1000
+
+/**
+ * Number of consecutive timeouts before an USB transfer will be treated as
+ * timed out.
+ */
+#define NUM_TIMEOUTS 2
+
+/** Chunk size in bytes in which data is transferred. */
+#define CHUNK_SIZE 2048
+
+static int initialize_handle(struct jaylink_device_handle *devh)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ struct libusb_config_descriptor *config;
+ const struct libusb_interface *interface;
+ const struct libusb_interface_descriptor *desc;
+ const struct libusb_endpoint_descriptor *epdesc;
+ bool found_interface;
+ bool found_endpoint_in;
+ bool found_endpoint_out;
+ uint8_t i;
+
+ ctx = devh->dev->ctx;
+ devh->interface_number = 0;
+
+ /*
+ * Retrieve active configuration descriptor to determine the endpoints
+ * for the interface number of the device.
+ */
+ ret = libusb_get_active_config_descriptor(devh->dev->usb_dev, &config);
+
+ if (ret != LIBUSB_SUCCESS) {
+ log_err(ctx, "Failed to get configuration descriptor: %s.",
+ libusb_error_name(ret));
+ return JAYLINK_ERR;
+ }
+
+ found_interface = false;
+
+ for (i = 0; i < config->bNumInterfaces; i++) {
+ interface = &config->interface[i];
+ desc = &interface->altsetting[0];
+
+ if (desc->bInterfaceClass != LIBUSB_CLASS_VENDOR_SPEC)
+ continue;
+
+ if (desc->bInterfaceSubClass != LIBUSB_CLASS_VENDOR_SPEC)
+ continue;
+
+ if (desc->bNumEndpoints < 2)
+ continue;
+
+ found_interface = true;
+ devh->interface_number = i;
+ break;
+ }
+
+ if (!found_interface) {
+ log_err(ctx, "No suitable interface found.");
+ libusb_free_config_descriptor(config);
+ return JAYLINK_ERR;
+ }
+
+ found_endpoint_in = false;
+ found_endpoint_out = false;
+
+ for (i = 0; i < desc->bNumEndpoints; i++) {
+ epdesc = &desc->endpoint[i];
+
+ if (epdesc->bEndpointAddress & LIBUSB_ENDPOINT_IN) {
+ devh->endpoint_in = epdesc->bEndpointAddress;
+ found_endpoint_in = true;
+ } else {
+ devh->endpoint_out = epdesc->bEndpointAddress;
+ found_endpoint_out = true;
+ }
+ }
+
+ libusb_free_config_descriptor(config);
+
+ if (!found_endpoint_in) {
+ log_err(ctx, "Interface IN endpoint not found.");
+ return JAYLINK_ERR;
+ }
+
+ if (!found_endpoint_out) {
+ log_err(ctx, "Interface OUT endpoint not found.");
+ return JAYLINK_ERR;
+ }
+
+ log_dbg(ctx, "Using endpoint %02x (IN) and %02x (OUT).",
+ devh->endpoint_in, devh->endpoint_out);
+
+ /* Buffer size must be a multiple of CHUNK_SIZE bytes. */
+ devh->buffer_size = CHUNK_SIZE;
+ devh->buffer = malloc(devh->buffer_size);
+
+ if (!devh->buffer) {
+ log_err(ctx, "Transport buffer malloc failed.");
+ return JAYLINK_ERR_MALLOC;
+ }
+
+ devh->read_length = 0;
+ devh->bytes_available = 0;
+ devh->read_pos = 0;
+
+ devh->write_length = 0;
+ devh->write_pos = 0;
+
+ return JAYLINK_OK;
+}
+
+static void cleanup_handle(struct jaylink_device_handle *devh)
+{
+ free(devh->buffer);
+}
+
+JAYLINK_PRIV int transport_usb_open(struct jaylink_device_handle *devh)
+{
+ int ret;
+ struct jaylink_device *dev;
+ struct jaylink_context *ctx;
+ struct libusb_device_handle *usb_devh;
+
+ dev = devh->dev;
+ ctx = dev->ctx;
+
+ log_dbg(ctx, "Trying to open device (bus:address = %03u:%03u).",
+ libusb_get_bus_number(dev->usb_dev),
+ libusb_get_device_address(dev->usb_dev));
+
+ ret = initialize_handle(devh);
+
+ if (ret != JAYLINK_OK) {
+ log_err(ctx, "Initialize device handle failed.");
+ return ret;
+ }
+
+ ret = libusb_open(dev->usb_dev, &usb_devh);
+
+ if (ret != LIBUSB_SUCCESS) {
+ log_err(ctx, "Failed to open device: %s.",
+ libusb_error_name(ret));
+ cleanup_handle(devh);
+ return JAYLINK_ERR;
+ }
+
+ ret = libusb_claim_interface(usb_devh, devh->interface_number);
+
+ if (ret != LIBUSB_SUCCESS) {
+ log_err(ctx, "Failed to claim interface: %s.",
+ libusb_error_name(ret));
+ cleanup_handle(devh);
+ libusb_close(usb_devh);
+ return JAYLINK_ERR;
+ }
+
+ log_dbg(ctx, "Device opened successfully.");
+
+ devh->usb_devh = usb_devh;
+
+ return JAYLINK_OK;
+}
+
+JAYLINK_PRIV int transport_usb_close(struct jaylink_device_handle *devh)
+{
+ int ret;
+ struct jaylink_device *dev;
+ struct jaylink_context *ctx;
+
+ dev = devh->dev;
+ ctx = dev->ctx;
+
+ log_dbg(ctx, "Closing device (bus:address = %03u:%03u).",
+ libusb_get_bus_number(dev->usb_dev),
+ libusb_get_device_address(dev->usb_dev));
+
+ ret = libusb_release_interface(devh->usb_devh, devh->interface_number);
+
+ libusb_close(devh->usb_devh);
+ cleanup_handle(devh);
+
+ if (ret != LIBUSB_SUCCESS) {
+ log_err(ctx, "Failed to release interface: %s.",
+ libusb_error_name(ret));
+ return JAYLINK_ERR;
+ }
+
+ log_dbg(ctx, "Device closed successfully.");
+
+ return JAYLINK_OK;
+}
+
+JAYLINK_PRIV int transport_usb_start_write(struct jaylink_device_handle *devh,
+ size_t length, bool has_command)
+{
+ struct jaylink_context *ctx;
+
+ (void)has_command;
+
+ if (!length)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+
+ log_dbgio(ctx, "Starting write operation (length = %zu bytes).", length);
+
+ if (devh->write_pos > 0)
+ log_warn(ctx, "Last write operation left %zu bytes in the "
+ "buffer.", devh->write_pos);
+
+ if (devh->write_length > 0)
+ log_warn(ctx, "Last write operation was not performed.");
+
+ devh->write_length = length;
+ devh->write_pos = 0;
+
+ return JAYLINK_OK;
+}
+
+JAYLINK_PRIV int transport_usb_start_read(struct jaylink_device_handle *devh,
+ size_t length)
+{
+ struct jaylink_context *ctx;
+
+ if (!length)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+
+ log_dbgio(ctx, "Starting read operation (length = %zu bytes).",
+ length);
+
+ if (devh->bytes_available > 0)
+ log_dbg(ctx, "Last read operation left %zu bytes in the "
+ "buffer.", devh->bytes_available);
+
+ if (devh->read_length > 0)
+ log_warn(ctx, "Last read operation left %zu bytes.",
+ devh->read_length);
+
+ devh->read_length = length;
+
+ return JAYLINK_OK;
+}
+
+JAYLINK_PRIV int transport_usb_start_write_read(
+ struct jaylink_device_handle *devh, size_t write_length,
+ size_t read_length, bool has_command)
+{
+ struct jaylink_context *ctx;
+
+ (void)has_command;
+
+ if (!read_length || !write_length)
+ return JAYLINK_ERR_ARG;
+
+ ctx = devh->dev->ctx;
+
+ log_dbgio(ctx, "Starting write / read operation (length = "
+ "%zu / %zu bytes).", write_length, read_length);
+
+ if (devh->write_pos > 0)
+ log_warn(ctx, "Last write operation left %zu bytes in the "
+ "buffer.", devh->write_pos);
+
+ if (devh->write_length > 0)
+ log_warn(ctx, "Last write operation was not performed.");
+
+ if (devh->bytes_available > 0)
+ log_warn(ctx, "Last read operation left %zu bytes in the "
+ "buffer.", devh->bytes_available);
+
+ if (devh->read_length > 0)
+ log_warn(ctx, "Last read operation left %zu bytes.",
+ devh->read_length);
+
+ devh->write_length = write_length;
+ devh->write_pos = 0;
+
+ devh->read_length = read_length;
+ devh->bytes_available = 0;
+ devh->read_pos = 0;
+
+ return JAYLINK_OK;
+}
+
+static int usb_recv(struct jaylink_device_handle *devh, uint8_t *buffer,
+ size_t *length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ unsigned int tries;
+ int transferred;
+
+ ctx = devh->dev->ctx;
+
+ tries = NUM_TIMEOUTS;
+ transferred = 0;
+
+ while (tries > 0 && !transferred) {
+ /* Always request CHUNK_SIZE bytes from the device. */
+ ret = libusb_bulk_transfer(devh->usb_devh, devh->endpoint_in,
+ (unsigned char *)buffer, CHUNK_SIZE, &transferred,
+ USB_TIMEOUT);
+
+ if (ret == LIBUSB_ERROR_TIMEOUT) {
+ log_warn(ctx, "Failed to receive data from "
+ "device: %s.", libusb_error_name(ret));
+ tries--;
+ continue;
+ } else if (ret != LIBUSB_SUCCESS) {
+ log_err(ctx, "Failed to receive data from "
+ "device: %s.", libusb_error_name(ret));
+ return JAYLINK_ERR;
+ }
+
+ log_dbgio(ctx, "Received %i bytes from device.", transferred);
+ }
+
+ /* Ignore a possible timeout if at least one byte was received. */
+ if (transferred > 0) {
+ *length = transferred;
+ return JAYLINK_OK;
+ }
+
+ log_err(ctx, "Receiving data from device timed out.");
+
+ return JAYLINK_ERR_TIMEOUT;
+}
+
+static bool adjust_buffer(struct jaylink_device_handle *devh, size_t size)
+{
+ struct jaylink_context *ctx;
+ size_t num_chunks;
+ uint8_t *buffer;
+
+ ctx = devh->dev->ctx;
+
+ /* Adjust buffer size to a multiple of CHUNK_SIZE bytes. */
+ num_chunks = size / CHUNK_SIZE;
+
+ if (size % CHUNK_SIZE > 0)
+ num_chunks++;
+
+ size = num_chunks * CHUNK_SIZE;
+ buffer = realloc(devh->buffer, size);
+
+ if (!buffer) {
+ log_err(ctx, "Failed to adjust buffer size to %zu bytes.",
+ size);
+ return false;
+ }
+
+ devh->buffer = buffer;
+ devh->buffer_size = size;
+
+ log_dbg(ctx, "Adjusted buffer size to %zu bytes.", size);
+
+ return true;
+}
+
+static int usb_send(struct jaylink_device_handle *devh, const uint8_t *buffer,
+ size_t length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ unsigned int tries;
+ int transferred;
+
+ ctx = devh->dev->ctx;
+ tries = NUM_TIMEOUTS;
+
+ while (tries > 0 && length > 0) {
+ /* Send data in chunks of CHUNK_SIZE bytes to the device. */
+ ret = libusb_bulk_transfer(devh->usb_devh, devh->endpoint_out,
+ (unsigned char *)buffer, MIN(CHUNK_SIZE, length),
+ &transferred, USB_TIMEOUT);
+
+ if (ret == LIBUSB_SUCCESS) {
+ tries = NUM_TIMEOUTS;
+ } else if (ret == LIBUSB_ERROR_TIMEOUT) {
+ log_warn(ctx, "Failed to send data to device: %s.",
+ libusb_error_name(ret));
+ tries--;
+ } else {
+ log_err(ctx, "Failed to send data to device: %s.",
+ libusb_error_name(ret));
+ return JAYLINK_ERR;
+ }
+
+ buffer += transferred;
+ length -= transferred;
+
+ log_dbgio(ctx, "Sent %i bytes to device.", transferred);
+ }
+
+ if (!length)
+ return JAYLINK_OK;
+
+ log_err(ctx, "Sending data to device timed out.");
+
+ return JAYLINK_ERR_TIMEOUT;
+}
+
+JAYLINK_PRIV int transport_usb_write(struct jaylink_device_handle *devh,
+ const uint8_t *buffer, size_t length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ size_t num_chunks;
+ size_t fill_bytes;
+ size_t tmp;
+
+ ctx = devh->dev->ctx;
+
+ if (length > devh->write_length) {
+ log_err(ctx, "Requested to write %zu bytes but only %zu bytes "
+ "are expected for the write operation.", length,
+ devh->write_length);
+ return JAYLINK_ERR_ARG;
+ }
+
+ /*
+ * Store data in the buffer if the expected number of bytes for the
+ * write operation is not reached.
+ */
+ if (length < devh->write_length) {
+ if (devh->write_pos + length > devh->buffer_size) {
+ if (!adjust_buffer(devh, devh->write_pos + length))
+ return JAYLINK_ERR_MALLOC;
+ }
+
+ memcpy(devh->buffer + devh->write_pos, buffer, length);
+
+ devh->write_length -= length;
+ devh->write_pos += length;
+
+ log_dbgio(ctx, "Wrote %zu bytes into buffer.", length);
+ return JAYLINK_OK;
+ }
+
+ /*
+ * Expected number of bytes for this write operation is reached and
+ * therefore the write operation will be performed.
+ */
+ devh->write_length = 0;
+
+ /* Send data directly to the device if the buffer is empty. */
+ if (!devh->write_pos)
+ return usb_send(devh, buffer, length);
+
+ /*
+ * Calculate the number of bytes to fill up the buffer to reach a
+ * multiple of CHUNK_SIZE bytes. This ensures that the data from the
+ * buffer will be sent to the device in chunks of CHUNK_SIZE bytes.
+ * Note that this is why the buffer size must be a multiple of
+ * CHUNK_SIZE bytes.
+ */
+ num_chunks = devh->write_pos / CHUNK_SIZE;
+
+ if (devh->write_pos % CHUNK_SIZE)
+ num_chunks++;
+
+ fill_bytes = (num_chunks * CHUNK_SIZE) - devh->write_pos;
+ tmp = MIN(length, fill_bytes);
+
+ if (tmp > 0) {
+ memcpy(devh->buffer + devh->write_pos, buffer, tmp);
+
+ length -= tmp;
+ buffer += tmp;
+
+ log_dbgio(ctx, "Buffer filled up with %zu bytes.", tmp);
+ }
+
+ /* Send buffered data to the device. */
+ ret = usb_send(devh, devh->buffer, devh->write_pos + tmp);
+ devh->write_pos = 0;
+
+ if (ret != JAYLINK_OK)
+ return ret;
+
+ if (!length)
+ return JAYLINK_OK;
+
+ /* Send remaining data to the device. */
+ return usb_send(devh, buffer, length);
+}
+
+JAYLINK_PRIV int transport_usb_read(struct jaylink_device_handle *devh,
+ uint8_t *buffer, size_t length)
+{
+ int ret;
+ struct jaylink_context *ctx;
+ size_t bytes_received;
+ size_t tmp;
+
+ ctx = devh->dev->ctx;
+
+ if (length > devh->read_length) {
+ log_err(ctx, "Requested to read %zu bytes but only %zu bytes "
+ "are expected for the read operation.", length,
+ devh->read_length);
+ return JAYLINK_ERR_ARG;
+ }
+
+ if (length <= devh->bytes_available) {
+ memcpy(buffer, devh->buffer + devh->read_pos, length);
+
+ devh->read_length -= length;
+ devh->bytes_available -= length;
+ devh->read_pos += length;
+
+ log_dbgio(ctx, "Read %zu bytes from buffer.", length);
+ return JAYLINK_OK;
+ }
+
+ if (devh->bytes_available) {
+ memcpy(buffer, devh->buffer + devh->read_pos,
+ devh->bytes_available);
+
+ buffer += devh->bytes_available;
+ length -= devh->bytes_available;
+ devh->read_length -= devh->bytes_available;
+
+ log_dbgio(ctx, "Read %zu bytes from buffer to flush it.",
+ devh->bytes_available);
+
+ devh->bytes_available = 0;
+ devh->read_pos = 0;
+ }
+
+ while (length > 0) {
+ /*
+ * If less than CHUNK_SIZE bytes are requested from the device,
+ * store the received data into the internal buffer instead of
+ * directly into the user provided buffer. This is necessary to
+ * prevent a possible buffer overflow because the number of
+ * requested bytes from the device is always CHUNK_SIZE and
+ * therefore up to CHUNK_SIZE bytes may be received.
+ * Note that this is why the internal buffer size must be at
+ * least CHUNK_SIZE bytes.
+ */
+ if (length < CHUNK_SIZE) {
+ ret = usb_recv(devh, devh->buffer, &bytes_received);
+
+ if (ret != JAYLINK_OK)
+ return ret;
+
+ tmp = MIN(bytes_received, length);
+ memcpy(buffer, devh->buffer, tmp);
+
+ /*
+ * Setup the buffer for the remaining data if more data
+ * was received from the device than was requested.
+ */
+ if (bytes_received > length) {
+ devh->bytes_available = bytes_received - tmp;
+ devh->read_pos = tmp;
+ }
+
+ buffer += tmp;
+ length -= tmp;
+ devh->read_length -= tmp;
+
+ log_dbgio(ctx, "Read %zu bytes from buffer.", tmp);
+ } else {
+ ret = usb_recv(devh, buffer, &bytes_received);
+
+ if (ret != JAYLINK_OK)
+ return ret;
+
+ buffer += bytes_received;
+ length -= bytes_received;
+ devh->read_length -= bytes_received;
+
+ log_dbgio(ctx, "Read %zu bytes from device.",
+ bytes_received);
+ }
+ }
+
+ return JAYLINK_OK;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/util.c b/src/jtag/drivers/libjaylink/libjaylink/util.c
new file mode 100644
index 0000000..4862d4e
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/util.c
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2014-2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include <stdbool.h>
+
+#include "libjaylink.h"
+
+/**
+ * @file
+ *
+ * Utility functions.
+ */
+
+/**
+ * Check for a capability.
+ *
+ * The capabilities are expected to be stored in a bit array consisting of one
+ * or more bytes where each individual bit represents a capability. The first
+ * bit of this array is the least significant bit of the first byte and the
+ * following bits are sequentially numbered in order of increasing bit
+ * significance and byte index. A set bit indicates a supported capability.
+ *
+ * @param[in] caps Buffer with capabilities.
+ * @param[in] cap Bit position of the capability to check for.
+ *
+ * @retval true Capability is supported.
+ * @retval false Capability is not supported or invalid argument.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API bool jaylink_has_cap(const uint8_t *caps, uint32_t cap)
+{
+ if (!caps)
+ return false;
+
+ if (caps[cap / 8] & (1 << (cap % 8)))
+ return true;
+
+ return false;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/version.c b/src/jtag/drivers/libjaylink/libjaylink/version.c
new file mode 100644
index 0000000..88bc023
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/version.c
@@ -0,0 +1,128 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#include "libjaylink.h"
+
+/**
+ * @file
+ *
+ * Package and library version functions.
+ */
+
+/**
+ * Get the major version number of the libjaylink package.
+ *
+ * @return The major version number of the libjaylink package.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_version_package_get_major(void)
+{
+ return JAYLINK_VERSION_PACKAGE_MAJOR;
+}
+
+/**
+ * Get the minor version number of the libjaylink package.
+ *
+ * @return The minor version number of the libjaylink package.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_version_package_get_minor(void)
+{
+ return JAYLINK_VERSION_PACKAGE_MINOR;
+}
+
+/**
+ * Get the micro version number of the libjaylink package.
+ *
+ * @return The micro version number of the libjaylink package.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_version_package_get_micro(void)
+{
+ return JAYLINK_VERSION_PACKAGE_MICRO;
+}
+
+/**
+ * Get the version number string of the libjaylink package.
+ *
+ * @return A string which contains the version number of the libjaylink
+ * package. The string is null-terminated and must not be free'd by the
+ * caller.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API const char *jaylink_version_package_get_string(void)
+{
+ return JAYLINK_VERSION_PACKAGE_STRING;
+}
+
+/**
+ * Get the <i>current</i> version number of the libjaylink libtool interface.
+ *
+ * @return The <i>current</i> version number of the libjaylink libtool
+ * interface.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_version_library_get_current(void)
+{
+ return JAYLINK_VERSION_LIBRARY_CURRENT;
+}
+
+/**
+ * Get the <i>revision</i> version number of the libjaylink libtool interface.
+ *
+ * @return The <i>revision</i> version number of the libjaylink libtool
+ * interface.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_version_library_get_revision(void)
+{
+ return JAYLINK_VERSION_LIBRARY_REVISION;
+}
+
+/**
+ * Get the <i>age</i> version number of the libjaylink libtool interface.
+ *
+ * @return The <i>age</i> version number of the libjaylink libtool interface.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API int jaylink_version_library_get_age(void)
+{
+ return JAYLINK_VERSION_LIBRARY_AGE;
+}
+
+/**
+ * Get the version number string of the libjaylink libtool interface.
+ *
+ * @return A string which contains the version number of the libjaylink libtool
+ * interface. The string is null-terminated and must not be free'd by
+ * the caller.
+ *
+ * @since 0.1.0
+ */
+JAYLINK_API const char *jaylink_version_library_get_string(void)
+{
+ return JAYLINK_VERSION_LIBRARY_STRING;
+}
diff --git a/src/jtag/drivers/libjaylink/libjaylink/version.h.in b/src/jtag/drivers/libjaylink/libjaylink/version.h.in
new file mode 100644
index 0000000..d6a7796
--- /dev/null
+++ b/src/jtag/drivers/libjaylink/libjaylink/version.h.in
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the libjaylink project.
+ *
+ * Copyright (C) 2015 Marc Schink <jaylink-dev@marcschink.de>
+ *
+ * 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/>.
+ */
+
+#ifndef LIBJAYLINK_VERSION_H
+#define LIBJAYLINK_VERSION_H
+
+/**
+ * @file
+ *
+ * Package and library version macros.
+ */
+
+/** Major version number of the libjaylink package. */
+#define JAYLINK_VERSION_PACKAGE_MAJOR @JAYLINK_VERSION_PACKAGE_MAJOR@
+
+/** Minor version number of the libjaylink package. */
+#define JAYLINK_VERSION_PACKAGE_MINOR @JAYLINK_VERSION_PACKAGE_MINOR@
+
+/** Micro version number of the libjaylink package. */
+#define JAYLINK_VERSION_PACKAGE_MICRO @JAYLINK_VERSION_PACKAGE_MICRO@
+
+/** Version number string of the libjaylink package. */
+#define JAYLINK_VERSION_PACKAGE_STRING "@JAYLINK_VERSION_PACKAGE@"
+
+/** <i>Current</i> version number of the libjaylink libtool interface. */
+#define JAYLINK_VERSION_LIBRARY_CURRENT @JAYLINK_VERSION_LIBRARY_CURRENT@
+
+/** <i>Revision</i> version number of the libjaylink libtool interface. */
+#define JAYLINK_VERSION_LIBRARY_REVISION @JAYLINK_VERSION_LIBRARY_REVISION@
+
+/** <i>Age</i> version number of the libjaylink libtool interface. */
+#define JAYLINK_VERSION_LIBRARY_AGE @JAYLINK_VERSION_LIBRARY_AGE@
+
+/** Version number string of the libjaylink libtool interface. */
+#define JAYLINK_VERSION_LIBRARY_STRING "@JAYLINK_VERSION_LIBRARY@"
+
+#endif /* LIBJAYLINK_VERSION_H */