diff --git a/Makefile b/Makefile
index 15ce20aa..3f7a53cb 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,7 @@ ifeq ($(PROBE_HOST), pc-stlinkv2)
PC_HOSTED = true
NO_LIBOPENCM3 = true
endif
-ifeq ($(PROBE_HOST), pc-hosted)
+ifeq ($(PROBE_HOST), hosted)
PC_HOSTED = true
NO_LIBOPENCM3 = true
endif
diff --git a/UsingSWO b/UsingSWO
index 36517ead..a9d8ee16 100644
--- a/UsingSWO
+++ b/UsingSWO
@@ -109,12 +109,13 @@ Note that swolisten can be used with either BMP firmware, or with a
conventional TTL serial dongle. See at the bottom of this file for
information on how to use a dongle.
-The command line to build the swolisten tool is;
+The command line to build the swolisten tool may look like:
-gcc -I /usr/local/include/libusb-1.0 -L /usr/local/lib -lusb-1.0 swolisten.c -o swolisten
+E.g. for Ubuntu
+gcc -I /usr/local/include/libusb-1.0 -L /usr/local/lib swolisten.c -o swolisten -lusb-1.0
-For Opensuse:
-gcc -I /usr/include/libusb-1.0 -lusb-1.0 swolisten.c swolisten -std=gnu99 -g -Og
+E.g. For Opensuse:
+gcc -I /usr/include/libusb-1.0 swolisten.c swolisten -std=gnu99 -g -Og -lusb-1.0
...you will obviously need to change the paths to your libusb files.
diff --git a/scripts/stm32_mem.py b/scripts/stm32_mem.py
index ae994029..c6feed9d 100755
--- a/scripts/stm32_mem.py
+++ b/scripts/stm32_mem.py
@@ -18,6 +18,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
+from __future__ import print_function
from time import sleep
import struct
import os
@@ -27,9 +28,9 @@ import argparse
import usb
import dfu
-CMD_GETCOMMANDS = 0x00
-CMD_SETADDRESSPOINTER = 0x21
-CMD_ERASE = 0x41
+CMD_GETCOMMANDS = 0x00
+CMD_SETADDRESSPOINTER = 0x21
+CMD_ERASE = 0x41
def stm32_erase(dev, addr):
erase_cmd = struct.pack(" 0x1f800):
+ if (os.path.getsize(args.progfile) > 0x1f800):
print("File too large")
exit(0)
@@ -212,7 +213,7 @@ if __name__ == "__main__":
start = 0x8002000
addr = start
while bin:
- print ("Programming memory at 0x%08X\r" % addr),
+ print ("Programming memory at 0x%08X" % addr, end="\r")
stdout.flush()
try:
# STM DFU bootloader erases always.
@@ -243,7 +244,7 @@ if __name__ == "__main__":
except:
# Abort silent if bootloader does not support upload
break
- print ("Verifying memory at 0x%08X\r" % addr),
+ print ("Verifying memory at 0x%08X" % addr, end="\r")
stdout.flush()
if len > 1024 :
size = 1024
diff --git a/src/gdb_main.c b/src/gdb_main.c
index 9157f2b8..fcf79e69 100644
--- a/src/gdb_main.c
+++ b/src/gdb_main.c
@@ -490,19 +490,23 @@ handle_v_packet(char *packet, int plen)
target_reset(cur_target);
flash_mode = 1;
}
- if(target_flash_erase(cur_target, addr, len) == 0)
+ if(target_flash_erase(cur_target, addr, len) == 0) {
gdb_putpacketz("OK");
- else
+ } else {
+ flash_mode = 0;
gdb_putpacketz("EFF");
+ }
} else if (sscanf(packet, "vFlashWrite:%08lx:%n", &addr, &bin) == 1) {
/* Write Flash Memory */
len = plen - bin;
DEBUG_GDB("Flash Write %08lX %08lX\n", addr, len);
- if(cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0)
+ if(cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0) {
gdb_putpacketz("OK");
- else
+ } else {
+ flash_mode = 0;
gdb_putpacketz("EFF");
+ }
} else if (!strcmp(packet, "vFlashDone")) {
/* Commit flash operations. */
diff --git a/src/platforms/Readme.md b/src/platforms/Readme.md
new file mode 100644
index 00000000..b3480bb4
--- /dev/null
+++ b/src/platforms/Readme.md
@@ -0,0 +1,23 @@
+# Platforms and platform support files
+
+This directory contains the implementation of platforms and support file
+used by (multiple) platforms.
+
+## Implementation directories
+
+native : Firmware for original Black Magic Probe
+stlink : Firmware for STLINK-V2 and V21
+swlink : Firmware for STLINK-V1 and Bluepill
+hydrabus : Firmware https://hydrabus.com/
+f4discovery : Firmware for STM32F407DISCO
+launchpad-icdi :
+tm4c:
+hosted: PC-hosted BMP running as PC application talking to firmware BMPs,
+ STLINK-V2/21/3, FTDI MPSSE probes, CMSIS-DAP and JLINK
+
+
+## Support directories
+
+common: libopencm3 based support for firmware BMPs
+stm32: STM32 specific libopencm3 based support for firmware BMPs
+pc: Support for PC-hosted BMPs.
diff --git a/src/platforms/common/cdcacm.c b/src/platforms/common/cdcacm.c
index 5ebbae02..73f594aa 100644
--- a/src/platforms/common/cdcacm.c
+++ b/src/platforms/common/cdcacm.c
@@ -61,7 +61,7 @@ static const struct usb_device_descriptor dev = {
#ifdef SAMD21E17
.bMaxPacketSize0 = 64,
#else
- .bMaxPacketSize0 = 8,
+ .bMaxPacketSize0 = 32,
#endif
.idVendor = 0x1D50,
.idProduct = 0x6018,
diff --git a/src/platforms/common/swdptap.c b/src/platforms/common/swdptap.c
index 29278ccc..d6e82d21 100644
--- a/src/platforms/common/swdptap.c
+++ b/src/platforms/common/swdptap.c
@@ -52,6 +52,8 @@ static void swdptap_turnaround(int dir)
SWDIO_MODE_FLOAT();
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
+ gpio_set(SWCLK_PORT, SWCLK_PIN);
+ gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
if(dir == SWDIO_STATUS_DRIVE)
SWDIO_MODE_DRIVE();
@@ -68,6 +70,9 @@ static uint32_t swdptap_seq_in(int ticks)
int res;
res = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
+ gpio_set(SWCLK_PORT, SWCLK_PIN);
+ gpio_set(SWCLK_PORT, SWCLK_PIN);
+ gpio_set(SWCLK_PORT, SWCLK_PIN);
if (res)
ret |= index;
index <<= 1;
@@ -90,20 +95,22 @@ static bool swdptap_seq_in_parity(uint32_t *ret, int ticks)
swdptap_turnaround(SWDIO_STATUS_FLOAT);
while (len--) {
- gpio_clear(SWCLK_PORT, SWCLK_PIN);
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
- if (bit) {
+ gpio_set(SWCLK_PORT, SWCLK_PIN);
+ gpio_set(SWCLK_PORT, SWCLK_PIN);
+ if (bit)
res |= index;
- }
index <<= 1;
+ gpio_clear(SWCLK_PORT, SWCLK_PIN);
}
- gpio_clear(SWCLK_PORT, SWCLK_PIN);
int parity = __builtin_popcount(res);
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
if (bit)
parity++;
+ else
+ gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
#ifdef DEBUG_SWD_BITS
for (int i = 0; i < len; i++)
@@ -115,42 +122,39 @@ static bool swdptap_seq_in_parity(uint32_t *ret, int ticks)
static void swdptap_seq_out(uint32_t MS, int ticks)
{
- int data = MS & 1;
#ifdef DEBUG_SWD_BITS
for (int i = 0; i < ticks; i++)
DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
#endif
swdptap_turnaround(SWDIO_STATUS_DRIVE);
+ gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
while (ticks--) {
- gpio_set_val(SWDIO_PORT, SWDIO_PIN, data);
- gpio_clear(SWCLK_PORT, SWCLK_PIN);
- MS >>= 1;
- data = MS & 1;
gpio_set(SWCLK_PORT, SWCLK_PIN);
+ MS >>= 1;
+ gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
+ gpio_clear(SWCLK_PORT, SWCLK_PIN);
+ gpio_clear(SWCLK_PORT, SWCLK_PIN);
}
- gpio_clear(SWCLK_PORT, SWCLK_PIN);
}
static void swdptap_seq_out_parity(uint32_t MS, int ticks)
{
int parity = __builtin_popcount(MS);
- int data = MS & 1;
#ifdef DEBUG_SWD_BITS
for (int i = 0; i < ticks; i++)
DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
#endif
swdptap_turnaround(SWDIO_STATUS_DRIVE);
- gpio_set_val(SWDIO_PORT, SWDIO_PIN, data);
+ gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
MS >>= 1;
while (ticks--) {
- data = MS & 1;
gpio_set(SWCLK_PORT, SWCLK_PIN);
- gpio_set_val(SWDIO_PORT, SWDIO_PIN, data);
+ gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
MS >>= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN);
}
gpio_set_val(SWDIO_PORT, SWDIO_PIN, parity & 1);
- gpio_clear(SWCLK_PORT, SWCLK_PIN);
+ gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
diff --git a/src/platforms/f4discovery/Readme b/src/platforms/f4discovery/Readme
deleted file mode 100644
index bbcfc4fb..00000000
--- a/src/platforms/f4discovery/Readme
+++ /dev/null
@@ -1,28 +0,0 @@
-System vs BMP Bootloader
-========================
-For the BMP bootloader, flashing was not reliable. So we use the system
-bootloder unconditional.
-
-Connections:
-====================
-
-PA0: User button to force system bootloader entry with reset
-PA2/PA3 eventual connected to the STLINK/ STM32F103C8
-
-PC2: TDI
-PC4: TMS/SWDIO
-PC5: TCK/SWCLK
-PC6: TDO/TRACESWO
-
-PC1: TRST
-PC8: SRST
-
-PD15/Blue Led: Indicator that system bootloader is entered via BMP
-
-Bootstrapping the F4Discovery on-board ST-Link
-==============================================
-http://embdev.net/articles/STM_Discovery_as_Black_Magic_Probe has some hints
-how to modify the F4Discovery on-board ST-Link. If you try to do so and hit
-a problem that stands some test like that you load the right firmware to the
-right device via the right BMP probe, explain, report and ask on the
-blackmagic mailing list http://sourceforge.net/mail/?group_id=407419.
diff --git a/src/platforms/f4discovery/Readme.md b/src/platforms/f4discovery/Readme.md
new file mode 100644
index 00000000..a3dae25f
--- /dev/null
+++ b/src/platforms/f4discovery/Readme.md
@@ -0,0 +1,13 @@
+# Firmware BMP for STM32F407 DISCO boards
+
+Kept for historical reasons to load BMP bootloader to the STM32F103 of the onboard STLINK or external STLINKs. As stlink-tool now allows to load BMP firmware via the original STLINK bootloader is no longer really needed.
+
+## Connections:
+
+PC2: TDI
+PC4: TMS/SWDIO
+PC5: TCK/SWCLK
+PC6: TDO/TRACESWO
+
+PC1: TRST
+PC8: SRST
diff --git a/src/platforms/hosted/Makefile.inc b/src/platforms/hosted/Makefile.inc
index dd1dfc44..d1700d01 100644
--- a/src/platforms/hosted/Makefile.inc
+++ b/src/platforms/hosted/Makefile.inc
@@ -1,5 +1,6 @@
SYS = $(shell $(CC) -dumpmachine)
CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG
+CFLAGS += -DUSE_USB_VERSION_BIT
CFLAGS +=-I ./target -I./platforms/pc
ifneq (, $(findstring linux, $(SYS)))
@@ -15,22 +16,28 @@ SRC += serial_win.c
LDFLAGS += -lws2_32
LDFLAGS += -lsetupapi
#https://github.com/dmlc/xgboost/issues/1945 indicates macosx as indicator
-else ifneq (filter, macosx darwin, $(SYS)))
-LDFLAGS += -lsetupapi
-LDFLAGS += hidapi/mac/.libs/libhidapi.a -framework IOKit
-LDFLAGS += -framework CoreFoundation hidapi/mac/.libs/libhidapi.a
+else ifneq (filter, macosx darwin, $(SYS))
+SRC += serial_unix.c
+LDFLAGS += -lhidapi
+LDFLAGS += -framework CoreFoundation
CFLAGS += -Ihidapi/hidapi
endif
LDFLAGS += -lusb-1.0
CFLAGS += $(shell pkg-config --cflags libftdi1)
LDFLAGS += $(shell pkg-config --libs libftdi1)
+CFLAGS += -Wno-missing-field-initializers
-ifeq ($(shell pkg-config --exists hidapi-libusb && echo 0), 0)
-CFLAGS += $(shell pkg-config --cflags hidapi-libusb)
-LDFLAGS += $(shell pkg-config --libs hidapi-libusb)
-CFLAGS += -DCMSIS_DAP
-SRC += cmsis_dap.c dap.c
+ifneq (, $(findstring mingw, $(SYS)))
+ SRC += cmsis_dap.c dap.c hid.c
+ CFLAGS += -DCMSIS_DAP
+else
+ ifeq ($(shell pkg-config --exists hidapi-libusb && echo 0), 0)
+ CFLAGS += $(shell pkg-config --cflags hidapi-libusb)
+ LDFLAGS += $(shell pkg-config --libs hidapi-libusb)
+ CFLAGS += -DCMSIS_DAP
+ SRC += cmsis_dap.c dap.c
+ endif
endif
VPATH += platforms/pc
diff --git a/src/platforms/hosted/Readme.md b/src/platforms/hosted/Readme.md
index bfbfaf6d..a3f31c43 100644
--- a/src/platforms/hosted/Readme.md
+++ b/src/platforms/hosted/Readme.md
@@ -13,19 +13,51 @@ connect to the BMP with the CDCACM GDB serial server. GDB functionality
is the same, monitor option may vary.
More arguments allow to
-### print information on the connected target "blackmagiv -t"
-### directly flash a binary file at 0x0800000 "blackmagic "
+### Print information on the connected target
+```
+blackmagic -t
+```
+### Directly flash a binary file at lowest flash address
+```
+blackmagic
+```
or with the -S argument at some other address
-### read flash to binary file "blackmagic -r .bin
-### verify flash against binary file "blackmagic -V .bin
-
-Use "blackmagic -h" to see all options.
+```
+blackmagic -S 0x08002000
+```
+### Read flash to binary file
+```
+blackmagic -r .bin
+```
+### Verify flash against binary file
+```
+blackmagic -V .bin
+```
+### Show more options
+```
+blackmagic -h"
+```
## Used libraries:
### libusb
### libftdi, for FTDI support
### hidapi-libusb, for CMSIS-DAP support
+## Compiling on windows
+
+You can crosscompile blackmagic for windows with mingw or on windows
+with cygwin. For compilation, headers for libftdi1 and libusb-1.0 are
+needed. For running, libftdi1.dll and libusb-1.0.dll are needed and
+the executable must be able to find them. Mingw on cygwin does not provide
+a libftdi package yet.
+
+To prepare libusb access to the ftdi device, run zadig https://zadig.akeo.ie/.
+Choose WinUSB(libusb-1.0) for the BMP Ftdi device.
+
+Running cygwin/blackmagic in a cygwin console, the program does not react
+on ^C. In another console, run "ps ax" to find the WINPID of the process
+and then "taskkill /F ?PID (WINPID)".
+
## Supported debuggers
REMOTE_BMP is a "normal" BMP usb connected
@@ -39,16 +71,76 @@ REMOTE_BMP is a "normal" BMP usb connected
| FTDI MPSSE | ++ | Requires a device descrition
| JLINK | - | Usefull to add BMP support for MCUs with built-in JLINK
+## Device matching
+As other USB dongles already connected to the host PC may use FTDI chips,
+cable descriptions must be provided to match with the dongle.
+To match the dongle, at least USB VID/PID that must match.
+If a description is given, the USB device must provide that string. If a
+serial number string is given on the command line, that number must match
+with serial number in the USB descriptor of the device.
+
+## FTDI connection possibilities:
+
+| Direct Connection |
+| ----------------------|
+| MPSSE_SK --> JTAG_TCK |
+| MPSSE_DO --> JTAG_TDI |
+| MPSSE_DI <-- JTAG_TDO |
+| MPSSE_CS <-> JTAG_TMS |
+
+\+ JTAG and bitbanging SWD is possible
+\- No level translation, no buffering, no isolation
+Example: [Flossjtag](https://randomprojects.org/wiki/Floss-JTAG).
+
+| Resistor SWD |
+|------------------------|
+| MPSSE_SK ---> JTAG_TCK |
+| MPSSE_DO -R-> JTAG_TMS |
+| MPSSE_DI <--- JTAG_TMS |
+
+BMP would allow direct MPSSE_DO ->JTAG_TMS connections as BMP tristates DO
+when reading. Resistor defeats contentions anyways. R is typical choosen
+in the range of 470R
+
+\+ MPSSE SWD possible
+\- No Jtag, no level translation, no buffering, no isolation
+
+|Direct buffered Connection|
+|--------------------------|
+| MPSSE_SK -B-> JTAG_TCK |
+| MPSSE_DO -B-> JTAG_TDI |
+| MPSSE_DI <-B- JTAG_TDO |
+| MPSSE_CS -B-> JTAG_TMS |
+
+\+ Only Jtag, buffered, possible level translation and isolation
+\- No SWD
+Example: [Turtelizer]http://www.ethernut.de/en/hardware/turtelizer/index.html)
+[schematics](http://www.ethernut.de/pdf/turtelizer20c-schematic.pdf)
+
+The 'r' command line arguments allows to specify an external SWD
+resistor connection added to some existing cable. Jtag is not possible
+together with the 'r' argument.
+
+### Many variants possible
+As the FTDI has more pins, these pins may be used to control
+enables of buffers and multiplexer selection in many variants.
+
+### FTDI SWD speed
+SWD read needs two USB round trip, one for the acknowledge and one
+round-trip after the data phase, while JTAG only needs one round-trip.
+For that, SWD read speed is about half the JTAG read speed.
+
+### Reset, Target voltage readback etc
+The additional pins may also control Reset functionality, provide
+information if target voltage is applied. etc.
+
+### Cable descriptions
+Please help to verify the cable description and give feedback on the
+cables already listed and propose other cable. A link to the schematics
+is welcome.
+
## Feedback
### Issues and Pull request on https://github.com/blacksphere/blackmagic/
### Discussions on Discord.
You can find the Discord link here: https://1bitsquared.com/pages/chat
### Blackmagic mailing list http://sourceforge.net/mail/?group_id=407419
-
-## Known deficiencies
-### For REMOTE_BMP
-#### On windows, the device node must be given on the command line
-Finding the device from USB VID/PID/Serial in not yet implemented
-### FTDI MPSSE
-#### No auto detection
-Cable description must be given on the command line
diff --git a/src/platforms/hosted/bmp_remote.c b/src/platforms/hosted/bmp_remote.c
index 22d7a494..9b679473 100644
--- a/src/platforms/hosted/bmp_remote.c
+++ b/src/platforms/hosted/bmp_remote.c
@@ -51,18 +51,7 @@ int remote_init(bool verbose)
}
if (verbose)
DEBUG_WARN("Remote is %s\n", &construct[1]);
- char *p = strstr(&construct[1], "(Firmware v");
- if (!p)
- return -1;
- int major = 0, minor = 0, step = 0;
- int res = sscanf(p, "(Firmware v%d.%d.%d", &major, &minor, &step);
- if (res !=3)
- return -1;
- uint32_t version = major * 10000 + minor * 100 + step;
- /* check that firmare is > 1.6.1 */
- if (version < 10602)
- return -1;
- return 0;
+ return 0;
}
bool remote_target_get_power(void)
@@ -346,7 +335,12 @@ static void remote_ap_mem_write_sized(
void remote_adiv5_dp_defaults(ADIv5_DP_t *dp)
{
- if (remote_init(false)) {
+ uint8_t construct[REMOTE_MAX_MSG_SIZE];
+ int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, "%s",
+ REMOTE_HL_CHECK_STR);
+ platform_buffer_write(construct, s);
+ s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
+ if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN(
"Please update BMP firmware for substantial speed increase!\n");
return;
diff --git a/src/platforms/hosted/cmsis_dap.c b/src/platforms/hosted/cmsis_dap.c
index d9fe402a..c955761a 100644
--- a/src/platforms/hosted/cmsis_dap.c
+++ b/src/platforms/hosted/cmsis_dap.c
@@ -51,6 +51,7 @@ static int report_size = 512 + 1; // TODO: read actual report size
/* LPC845 Breakout Board Rev. 0 report invalid response with > 65 bytes */
int dap_init(bmp_info_t *info)
{
+ printf("dap_init\n");
if (hid_init())
return -1;
int size = strlen(info->serial);
@@ -111,7 +112,7 @@ static uint32_t dap_dp_error(ADIv5_DP_t *dp)
return err;
}
-static uint32_t dap_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
+static uint32_t dap_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
uint16_t addr, uint32_t value)
{
bool APnDP = addr & ADIV5_APnDP;
@@ -128,7 +129,16 @@ static uint32_t dap_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
static uint32_t dap_dp_read_reg(ADIv5_DP_t *dp, uint16_t addr)
{
- return dap_read_reg(dp, addr);
+ uint32_t res;
+ if (addr & ADIV5_APnDP) {
+ dap_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
+ res = dap_dp_low_access(dp, ADIV5_LOW_READ,
+ ADIV5_DP_RDBUFF, 0);
+ } else {
+ res = dap_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
+ }
+ DEBUG_PROBE("dp_read %04x %08" PRIx32 "\n", addr, res);
+ return res;
}
void dap_exit_function(void)
diff --git a/src/platforms/hosted/dap.c b/src/platforms/hosted/dap.c
index 5db31c9a..fefaf353 100644
--- a/src/platforms/hosted/dap.c
+++ b/src/platforms/hosted/dap.c
@@ -374,11 +374,11 @@ void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data)
} while (buf[1] == DAP_TRANSFER_WAIT);
if (buf[1] > DAP_TRANSFER_WAIT) {
- DEBUG_PROBE("dap_write_reg %02x data %08x:fault\n", reg, data);
+ DEBUG_WARN("dap_write_reg %02x data %08x:fault\n", reg, data);
dp->fault = 1;
}
if (buf[1] == DAP_TRANSFER_ERROR) {
- DEBUG_PROBE("dap_write_reg %02x data %08x: protocoll error\n",
+ DEBUG_WARN("dap_write_reg %02x data %08x: protocoll error\n",
reg, data);
dap_line_reset();
}
@@ -399,8 +399,8 @@ unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src,
buf[4] = SWD_AP_DRW | DAP_TRANSFER_RnW;
dbg_dap_cmd(buf, 1023, 5 + 1);
unsigned int transferred = buf[0] + (buf[1] << 8);
- if (buf[2] > DAP_TRANSFER_FAULT) {
- DEBUG_PROBE("line_reset\n");
+ if (buf[2] >= DAP_TRANSFER_FAULT) {
+ DEBUG_WARN("dap_read_block @ %08 "PRIx32 " fault -> line reset\n", src);
dap_line_reset();
}
if (sz != transferred) {
diff --git a/src/platforms/hosted/ftdi_bmp.c b/src/platforms/hosted/ftdi_bmp.c
index 46f969fe..f4f4fe47 100644
--- a/src/platforms/hosted/ftdi_bmp.c
+++ b/src/platforms/hosted/ftdi_bmp.c
@@ -2,6 +2,7 @@
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
+ * Copyright (C) 2018 Uwe Bonnes(bon@elektron.ikp.physik.tu-darmstadt.de)
* Written by Gareth McMullin
*
* This program is free software: you can redistribute it and/or modify
@@ -36,42 +37,110 @@ static uint8_t outbuf[BUF_SIZE];
static uint16_t bufptr = 0;
cable_desc_t *active_cable;
+data_desc_t active_state;
cable_desc_t cable_desc[] = {
{
- /* Direct connection from FTDI to Jtag/Swd.*/
+ /* Direct connection from FTDI to Jtag/Swd.
+ Pin 6 direct connected to RST.*/
+ .vendor = 0x0403,
+ .product = 0x6014,
+ .interface = INTERFACE_A,
+ // No explicit reset
+ .bb_swdio_in_port_cmd = GET_BITS_LOW,
+ .bb_swdio_in_pin = MPSSE_CS,
+ .description = "UM232H",
+ .name = "um232h"
+ },
+ {
+ /* Direct connection from FTDI to Jtag/Swd.
+ Pin 6 direct connected to RST.*/
.vendor = 0x0403,
.product = 0x6010,
.interface = INTERFACE_A,
- .dbus_data = 0x08,
- .dbus_ddr = 0x1B,
- .bitbang_tms_in_port_cmd = GET_BITS_LOW,
- .bitbang_tms_in_pin = MPSSE_TMS,
+ .init.data_low = PIN6, /* PULL nRST high*/
+ .bb_swdio_in_port_cmd = GET_BITS_LOW,
+ .bb_swdio_in_pin = MPSSE_CS,
+ .assert_srst.data_low = ~PIN6,
+ .assert_srst.ddr_low = PIN6,
+ .deassert_srst.data_low = PIN6,
+ .deassert_srst.ddr_low = ~PIN6,
.description = "FLOSS-JTAG",
.name = "flossjtag"
},
+ {
+ /* MPSSE_SK (DB0) ----------- SWDCK/JTCK
+ * MPSSE-DO (DB1) -- 470 R -- SWDIO/JTMS
+ * MPSSE-DI (DB2) ----------- SWDIO/JTMS
+ * DO is tristated with SWD read, so
+ * resistor is not necessary, but protects
+ * from contentions in case of errors.
+ * JTAG not possible
+ * PIN6 (DB6) ----------- NRST */
+ .vendor = 0x0403,
+ .product = 0x6010,/*FT2232H*/
+ .interface = INTERFACE_B,
+ .init.data_low = PIN4, /* Pull up pin 4 */
+ .init.ddr_low = PIN4, /* Pull up pin 4 */
+ .mpsse_swd_read.set_data_low = MPSSE_DO,
+ .mpsse_swd_write.set_data_low = MPSSE_DO,
+ .assert_srst.data_low = ~PIN6,
+ .assert_srst.ddr_low = PIN6,
+ .deassert_srst.data_low = PIN6,
+ .deassert_srst.ddr_low = ~PIN6,
+ .target_voltage_cmd = GET_BITS_LOW,
+ .target_voltage_pin = PIN4, /* Always read as target voltage present.*/
+ .description = "USBMATE",
+ .name = "usbmate"
+ },
+ {
+ /* MPSSE_SK (DB0) ----------- SWDCK/JTCK
+ * MPSSE-DO (DB1) -- 470 R -- SWDIO/JTMS
+ * MPSSE-DI (DB2) ----------- SWDIO/JTMS
+ * DO is tristated with SWD read, so
+ * resistor is not necessary, but protects
+ * from contentions in case of errors.
+ * JTAG not possible.*/
+ .vendor = 0x0403,
+ .product = 0x6014,/*FT232H*/
+ .interface = INTERFACE_A,
+ .mpsse_swd_read.set_data_low = MPSSE_DO,
+ .mpsse_swd_write.set_data_low = MPSSE_DO,
+ .name = "ft232h_resistor_swd"
+ },
{
/* Buffered connection from FTDI to Jtag/Swd.
* TCK and TMS not independant switchable!
- * SWD not possible. */
+ * SWD not possible.
+ * PIN4 low enables buffers
+ * PIN5 Low indicates VRef applied
+ * PIN6 reads back SRST
+ * CBUS PIN1 Sets SRST
+ * CBUS PIN2 low drives SRST
+ */
.vendor = 0x0403,
.product = 0x6010,
.interface = INTERFACE_A,
- .dbus_data = 0x08,
- .dbus_ddr = 0x1B,
+ .init.ddr_low = PIN4,
+ .init.data_high = PIN4 | PIN3 | PIN2,
+ .init.ddr_high = PIN4 | PIN3 | PIN2 | PIN1 | PIN0,
+ .assert_srst.data_high = ~PIN2,
+ .deassert_srst.data_high = PIN2,
+ .srst_get_port_cmd = GET_BITS_LOW,
+ .srst_get_pin = PIN6,
.description = "FTDIJTAG",
.name = "ftdijtag"
},
{
/* UART/SWO on Interface A
* JTAG and control on INTERFACE_B
- * Bit 5 high selects SWD-READ (TMS routed to TDO)
- * Bit 6 high selects JTAG vs SWD (TMS routed to TDI/TDO)
+ * Bit 5 high selects SWD-WRITE (TMS routed to MPSSE_DI)
+ * Bit 6 high selects JTAG vs SWD (TMS routed to MPSSE_CS)
* BCBUS 1 (Output) N_SRST
- * BCBUS 2 (Input) V_ISO available
+ * BCBUS 2 (Input/ Internal Pull Up) V_ISO available
*
* For bitbanged SWD, set Bit 5 low and select SWD read with
- * Bit 6 low. Read Connector TMS as FTDI TDO.
+ * Bit 6 low. Read Connector TMS as MPSSE_DI.
*
* TDO is routed to Interface 0 RXD as SWO or with Uart
* Connector pin 10 pulled to ground will connect Interface 0 RXD
@@ -80,33 +149,51 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403,
.product = 0x6010,
.interface = INTERFACE_B,
- .dbus_data = 0x6A,
- .dbus_ddr = 0x6B,
- .cbus_data = 0x02,
- .cbus_ddr = 0x02,
- .bitbang_tms_in_port_cmd = GET_BITS_LOW,
- .bitbang_tms_in_pin = MPSSE_TDO, /* keep bit 5 low*/
- .bitbang_swd_dbus_read_data = 0x02,
- .name = "ftdiswd"
+ .init.data_low = PIN6 | PIN5,
+ .init.ddr_low = PIN6 | PIN5,
+ .init.data_high = PIN1 | PIN2,
+ .assert_srst.data_high = ~PIN1,
+ .assert_srst.ddr_high = PIN1,
+ .deassert_srst.data_high = PIN1,
+ .deassert_srst.ddr_high = ~PIN1,
+ .mpsse_swd_read.clr_data_low = PIN5 | PIN6,
+ .mpsse_swd_write.set_data_low = PIN5,
+ .mpsse_swd_write.clr_data_low = PIN6,
+ .jtag.set_data_low = PIN6,
+ .target_voltage_cmd = GET_BITS_HIGH,
+ .target_voltage_pin = ~PIN2,
+ .name = "ftdiswd",
+ .description = "FTDISWD"
},
{
.vendor = 0x15b1,
.product = 0x0003,
.interface = INTERFACE_A,
- .dbus_data = 0x08,
- .dbus_ddr = 0x1B,
+ .init.ddr_low = PIN5,
.name = "olimex"
},
{
/* Buffered connection from FTDI to Jtag/Swd.
* TCK and TMS not independant switchable!
- * => SWD not possible. */
+ * => SWD not possible.
+ * DBUS PIN4 / JTAGOE low enables buffers
+ * DBUS PIN5 / TRST high drives nTRST low OC
+ * DBUS PIN6 / RST high drives nSRST low OC
+ * CBUS PIN0 reads back SRST
+ */
.vendor = 0x0403,
.product = 0xbdc8,
.interface = INTERFACE_A,
- .dbus_data = 0x08,
- .dbus_ddr = 0x1B,
- .name = "turtelizer"
+ /* Drive low to activate JTAGOE and deassert TRST/RST.*/
+ .init.data_low = 0,
+ .init.ddr_low = PIN6 | PIN5 | PIN4,
+ .init.ddr_high = PIN2, /* ONE LED */
+ .assert_srst.data_low = PIN6,
+ .deassert_srst.data_low = ~PIN6,
+ .srst_get_port_cmd = GET_BITS_HIGH,
+ .srst_get_pin = PIN0,
+ .name = "turtelizer",
+ .description = "Turtelizer JTAG/RS232 Adapter"
},
{
/* https://reference.digilentinc.com/jtag_hs1/jtag_hs1
@@ -117,8 +204,6 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403,
.product = 0xbdc8,
.interface = INTERFACE_A,
- .dbus_data = 0x08,
- .dbus_ddr = 0x1B,
.name = "jtaghs1"
},
{
@@ -126,10 +211,10 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403,
.product = 0xbdc8,
.interface = INTERFACE_A,
- .dbus_data = 0xA8,
- .dbus_ddr = 0xAB,
- .bitbang_tms_in_port_cmd = GET_BITS_LOW,
- .bitbang_tms_in_pin = MPSSE_TMS,
+ .init.data_low = MPSSE_CS | MPSSE_DO | MPSSE_DI,
+ .init.ddr_low = MPSSE_CS | MPSSE_DO | MPSSE_SK,
+ .bb_swdio_in_port_cmd = GET_BITS_LOW,
+ .bb_swdio_in_pin = MPSSE_CS,
.name = "ftdi"
},
{
@@ -137,10 +222,10 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403,
.product = 0x6014,
.interface = INTERFACE_A,
- .dbus_data = 0x88,
- .dbus_ddr = 0x8B,
- .cbus_data = 0x20,
- .cbus_ddr = 0x3f,
+ .init.data_low = PIN7,
+ .init.ddr_low = PIN7,
+ .init.data_high = PIN5,
+ .init.ddr_high = PIN5 | PIN4 | PIN3 | PIN2 | PIN1 | PIN0,
.name = "digilent"
},
{
@@ -148,10 +233,10 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403,
.product = 0x6014,
.interface = INTERFACE_A,
- .dbus_data = 0x08,
- .dbus_ddr = 0x0B,
- .bitbang_tms_in_port_cmd = GET_BITS_LOW,
- .bitbang_tms_in_pin = MPSSE_TMS,
+ .init.data_low = MPSSE_CS | MPSSE_DO | MPSSE_DI,
+ .init.ddr_low = MPSSE_CS | MPSSE_DO | MPSSE_SK,
+ .bb_swdio_in_port_cmd = GET_BITS_LOW,
+ .bb_swdio_in_pin = MPSSE_CS,
.name = "ft232h"
},
{
@@ -159,45 +244,63 @@ cable_desc_t cable_desc[] = {
.vendor = 0x0403,
.product = 0x6011,
.interface = INTERFACE_A,
- .dbus_data = 0x08,
- .dbus_ddr = 0x0B,
- .bitbang_tms_in_port_cmd = GET_BITS_LOW,
- .bitbang_tms_in_pin = MPSSE_TMS,
+ .bb_swdio_in_port_cmd = GET_BITS_LOW,
+ .bb_swdio_in_pin = MPSSE_CS,
.name = "ft4232h"
},
{
/* http://www.olimex.com/dev/pdf/ARM-USB-OCD.pdf.
- * BDUS 4 global enables JTAG Buffer.
+ * DBUS 4 global enables JTAG Buffer.
* => TCK and TMS not independant switchable!
* => SWD not possible. */
.vendor = 0x15ba,
.product = 0x002b,
.interface = INTERFACE_A,
- .dbus_data = 0x08,
- .dbus_ddr = 0x1B,
- .cbus_data = 0x00,
- .cbus_ddr = 0x08,
+ .init.ddr_low = PIN4,
+ .init.data_high = PIN3 | PIN1 | PIN0,
+ .init.ddr_high = PIN4 | PIN3 | PIN1 | PIN0,
.name = "arm-usb-ocd-h"
},
+ {
+ }
};
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
{
int err;
- unsigned index = 0;
- for(index = 0; index < sizeof(cable_desc)/sizeof(cable_desc[0]);
- index++)
- if (strcmp(cable_desc[index].name, cl_opts->opt_cable) == 0)
+ cable_desc_t *cable = &cable_desc[0];
+ for(; cable->name; cable++) {
+ if (strcmp(cable->name, cl_opts->opt_cable) == 0)
break;
+ }
- if (index == sizeof(cable_desc)/sizeof(cable_desc[0])) {
- DEBUG_WARN( "No cable matching %s found\n", cl_opts->opt_cable);
+ if (!cable->name ) {
+ DEBUG_WARN( "No cable matching found for %s\n", cl_opts->opt_cable);
return -1;
}
- active_cable = &cable_desc[index];
-
- DEBUG_WARN("Black Magic Probe for FTDI/MPSSE\n");
+ active_cable = cable;
+ memcpy(&active_state, &active_cable->init, sizeof(data_desc_t));
+ /* If swd_(read|write) is not given for the selected cable and
+ the 'r' command line argument is give, assume resistor SWD
+ connection.*/
+ if (cl_opts->external_resistor_swd &&
+ (active_cable->mpsse_swd_read.set_data_low == 0) &&
+ (active_cable->mpsse_swd_read.clr_data_low == 0) &&
+ (active_cable->mpsse_swd_read.set_data_high == 0) &&
+ (active_cable->mpsse_swd_read.clr_data_high == 0) &&
+ (active_cable->mpsse_swd_write.set_data_low == 0) &&
+ (active_cable->mpsse_swd_write.clr_data_low == 0) &&
+ (active_cable->mpsse_swd_write.set_data_high == 0) &&
+ (active_cable->mpsse_swd_write.clr_data_high == 0)) {
+ DEBUG_INFO("Using external resistor SWD\n");
+ active_cable->mpsse_swd_read.set_data_low = MPSSE_DO;
+ active_cable->mpsse_swd_write.set_data_low = MPSSE_DO;
+ } else if (!libftdi_swd_possible(NULL, NULL) &&
+ !cl_opts->opt_usejtag) {
+ DEBUG_WARN("SWD with cable not possible, trying JTAG\n");
+ cl_opts->opt_usejtag = true;
+ }
if(ftdic) {
ftdi_usb_close(ftdic);
ftdi_free(ftdic);
@@ -237,7 +340,58 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
err, ftdi_get_error_string(ftdic));
goto error_2;
}
- return 0;
+ assert(ftdic != NULL);
+ err = ftdi_usb_purge_buffers(ftdic);
+ if (err != 0) {
+ fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
+ err, ftdi_get_error_string(ftdic));
+ goto error_2;
+ }
+ /* Reset MPSSE controller. */
+ err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
+ if (err != 0) {
+ fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
+ err, ftdi_get_error_string(ftdic));
+ goto error_2;
+ }
+ /* Enable MPSSE controller. Pin directions are set later.*/
+ err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
+ if (err != 0) {
+ fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
+ err, ftdi_get_error_string(ftdic));
+ goto error_2;
+ }
+ uint8_t ftdi_init[16];
+ /* Test for pending garbage.*/
+ int garbage = ftdi_read_data(ftdic, ftdi_init, sizeof(ftdi_init));
+ if (garbage > 0) {
+ DEBUG_WARN("FTDI init garbage at start:");
+ for (int i = 0; i < garbage; i++)
+ DEBUG_WARN(" %02x", ftdi_init[i]);
+ DEBUG_WARN("\n");
+ }
+ int index = 0;
+ ftdi_init[index++]= LOOPBACK_END; /* FT2232D gets upset otherwise*/
+ ftdi_init[index++]= TCK_DIVISOR;
+ /* Use CLK/2 for about 50 % SWDCLK duty cycle on FT2232c.*/
+ ftdi_init[index++]= 1;
+ ftdi_init[index++]= 0;
+ ftdi_init[index++]= SET_BITS_LOW;
+ ftdi_init[index++]= active_state.data_low;
+ ftdi_init[index++]= active_state.ddr_low;
+ ftdi_init[index++]= SET_BITS_HIGH;
+ ftdi_init[index++]= active_state.data_high;
+ ftdi_init[index++]= active_state.ddr_high;
+ libftdi_buffer_write(ftdi_init, index);
+ libftdi_buffer_flush();
+ garbage = ftdi_read_data(ftdic, ftdi_init, sizeof(ftdi_init));
+ if (garbage > 0) {
+ DEBUG_WARN("FTDI init garbage at end:");
+ for (int i = 0; i < garbage; i++)
+ DEBUG_WARN(" %02x", ftdi_init[i]);
+ DEBUG_WARN("\n");
+ } return 0;
+
error_2:
ftdi_usb_close(ftdic);
error_1:
@@ -245,24 +399,106 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
return -1;
}
-void libftdi_srst_set_val(bool assert)
+static void libftdi_set_data(data_desc_t* data)
{
- (void)assert;
- libftdi_buffer_flush();
+ uint8_t cmd[6];
+ int index = 0;
+ if ((data->data_low) || (data->ddr_low)) {
+ if (data->data_low > 0)
+ active_state.data_low |= (data->data_low & 0xff);
+ else
+ active_state.data_low &= (data->data_low & 0xff);
+ if (data->ddr_low > 0)
+ active_state.ddr_low |= (data->ddr_low & 0xff);
+ else
+ active_state.ddr_low &= (data->ddr_low & 0xff);
+ cmd[index++] = SET_BITS_LOW;
+ cmd[index++] = active_state.data_low;
+ cmd[index++] = active_state.ddr_low;
+ }
+ if ((data->data_high) || (data->ddr_high)) {
+ if (data->data_high > 0)
+ active_state.data_high |= (data->data_high & 0xff);
+ else
+ active_state.data_high &= (data->data_high & 0xff);
+ if (data->ddr_high > 0)
+ active_state.ddr_high |= (data->ddr_high & 0xff);
+ else
+ active_state.ddr_high &= (data->ddr_high & 0xff);
+ cmd[index++] = SET_BITS_HIGH;
+ cmd[index++] = active_state.data_high;
+ cmd[index++] = active_state.ddr_high;
+ }
+ if (index) {
+ libftdi_buffer_write(cmd, index);
+ libftdi_buffer_flush();
+ }
}
-bool libftdi_srst_get_val(void) { return false; }
+void libftdi_srst_set_val(bool assert)
+{
+ if (assert)
+ libftdi_set_data(&active_cable->assert_srst);
+ else
+ libftdi_set_data(&active_cable->deassert_srst);
+}
+
+bool libftdi_srst_get_val(void)
+{
+ uint8_t cmd[1] = {0};
+ uint8_t pin = 0;
+ if (active_cable->srst_get_port_cmd && active_cable->srst_get_pin) {
+ cmd[0]= active_cable->srst_get_port_cmd;
+ pin = active_cable->srst_get_pin;
+ } else if (active_cable->assert_srst.data_low &&
+ active_cable->assert_srst.ddr_low) {
+ cmd[0]= GET_BITS_LOW;
+ pin = active_cable->assert_srst.data_low;
+ } else if (active_cable->assert_srst.data_high &&
+ active_cable->assert_srst.ddr_high) {
+ cmd[0]= GET_BITS_HIGH;
+ pin = active_cable->assert_srst.data_high;
+ }else {
+ return false;
+ }
+ libftdi_buffer_write(cmd, 1);
+ uint8_t data[1];
+ libftdi_buffer_read(data, 1);
+ bool res = false;
+ if (((pin < 0x7f) || (pin == PIN7)))
+ res = data[0] & pin;
+ else
+ res = !(data[0] & ~pin);
+ return res;
+}
void libftdi_buffer_flush(void)
{
+ if (!bufptr)
+ return;
+ DEBUG_WIRE("Flush %d\n", bufptr);
+#if defined(USE_USB_VERSION_BIT)
+static struct ftdi_transfer_control *tc_write = NULL;
+ if (tc_write)
+ ftdi_transfer_data_done(tc_write);
+ tc_write = ftdi_write_data_submit(ftdic, outbuf, bufptr);
+#else
assert(ftdi_write_data(ftdic, outbuf, bufptr) == bufptr);
DEBUG_WIRE("FT2232 libftdi_buffer flush: %d bytes\n", bufptr);
+#endif
bufptr = 0;
}
int libftdi_buffer_write(const uint8_t *data, int size)
{
if((bufptr + size) / BUF_SIZE > 0) libftdi_buffer_flush();
+ DEBUG_WIRE("Write %d bytes:", size);
+ for (int i = 0; i < size; i++) {
+ DEBUG_WIRE(" %02x", data[i]);
+ if (i && ((i & 0xf) == 0xf))
+ DEBUG_WIRE("\n\t");
+ }
+ DEBUG_WIRE("\n");
memcpy(outbuf + bufptr, data, size);
bufptr += size;
return size;
@@ -270,14 +506,111 @@ int libftdi_buffer_write(const uint8_t *data, int size)
int libftdi_buffer_read(uint8_t *data, int size)
{
- int index = 0;
+#if defined(USE_USB_VERSION_BIT)
+ struct ftdi_transfer_control *tc;
outbuf[bufptr++] = SEND_IMMEDIATE;
libftdi_buffer_flush();
+ tc = ftdi_read_data_submit(ftdic, data, size);
+ ftdi_transfer_data_done(tc);
+#else
+ int index = 0;
+ const uint8_t cmd[1] = {SEND_IMMEDIATE};
+ libftdi_buffer_write(cmd, 1);
+ libftdi_buffer_flush();
while((index += ftdi_read_data(ftdic, data + index, size-index)) != size);
+#endif
+ DEBUG_WIRE("Read %d bytes:", size);
+ for (int i = 0; i < size; i++) {
+ DEBUG_WIRE(" %02x", data[i]);
+ if (i && ((i & 0xf) == 0xf))
+ DEBUG_WIRE("\n\t");
+ }
+ DEBUG_WIRE("\n");
return size;
}
+void libftdi_jtagtap_tdi_tdo_seq(
+ uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
+{
+ int rsize, rticks;
+
+ if(!ticks) return;
+ if (!DI && !DO) return;
+
+// printf("ticks: %d\n", ticks);
+ if(final_tms) ticks--;
+ rticks = ticks & 7;
+ ticks >>= 3;
+ uint8_t data[8];
+ uint8_t cmd = ((DO)? MPSSE_DO_READ : 0) |
+ ((DI)? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) | MPSSE_LSB;
+ rsize = ticks;
+ if(ticks) {
+ data[0] = cmd;
+ data[1] = ticks - 1;
+ data[2] = 0;
+ libftdi_buffer_write(data, 3);
+ if (DI)
+ libftdi_buffer_write(DI, ticks);
+ }
+ int index = 0;
+ if(rticks) {
+ rsize++;
+ data[index++] = cmd | MPSSE_BITMODE;
+ data[index++] = rticks - 1;
+ if (DI)
+ data[index++] = DI[ticks];
+ }
+ if(final_tms) {
+ rsize++;
+ data[index++] = MPSSE_WRITE_TMS | ((DO)? MPSSE_DO_READ : 0) |
+ MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG;
+ data[index++] = 0;
+ if (DI)
+ data[index++] = (DI[ticks]) >> rticks?0x81 : 0x01;
+ }
+ if (index)
+ libftdi_buffer_write(data, index);
+ if (DO) {
+ int index = 0;
+ uint8_t *tmp = alloca(rsize);
+ libftdi_buffer_read(tmp, rsize);
+ if(final_tms) rsize--;
+
+ while(rsize--) {
+ /*if(rsize) printf("%02X ", tmp[index]);*/
+ *DO++ = tmp[index++];
+ }
+ if (rticks == 0)
+ *DO++ = 0;
+ if(final_tms) {
+ rticks++;
+ *(--DO) >>= 1;
+ *DO |= tmp[index] & 0x80;
+ } else DO--;
+ if(rticks) {
+ *DO >>= (8-rticks);
+ }
+ /*printf("%02X\n", *DO);*/
+ }
+}
+
const char *libftdi_target_voltage(void)
{
- return "not supported";
+ uint8_t pin = active_cable->target_voltage_pin;
+ if (active_cable->target_voltage_cmd && pin) {
+ libftdi_buffer_write(&active_cable->target_voltage_cmd, 1);
+ uint8_t data[1];
+ libftdi_buffer_read(data, 1);
+ bool res = false;
+ if (((pin < 0x7f) || (pin == PIN7)))
+ res = data[0] & pin;
+ else
+ res = !(data[0] & ~pin);
+ if (res)
+ return "Present";
+ else
+ return "Absent";
+ }
+ return NULL;
}
diff --git a/src/platforms/hosted/ftdi_bmp.h b/src/platforms/hosted/ftdi_bmp.h
index c44607b4..fc2a8def 100644
--- a/src/platforms/hosted/ftdi_bmp.h
+++ b/src/platforms/hosted/ftdi_bmp.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin
+ * Copyright (C) 2018 Uwe Bonnes (non@elektron.ikp.physik.tu-darmstadt.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
@@ -25,25 +26,82 @@
#include "swdptap.h"
#include "jtagtap.h"
+typedef struct data_desc_s {
+ int16_t data_low;
+ int16_t ddr_low;
+ int16_t data_high;
+ int16_t ddr_high;
+}data_desc_t;
+
+typedef struct pin_settings_s {
+ uint8_t set_data_low;
+ uint8_t clr_data_low;
+ uint8_t set_data_high;
+ uint8_t clr_data_high;
+}pin_settings_t;
+
typedef struct cable_desc_s {
int vendor;
int product;
int interface;
- uint8_t dbus_data;
- uint8_t dbus_ddr;
- uint8_t cbus_data;
- uint8_t cbus_ddr;
- uint8_t bitbang_tms_in_port_cmd;
- uint8_t bitbang_tms_in_pin;
- uint8_t bitbang_swd_dbus_read_data;
- /* bitbang_swd_dbus_read_data is same as dbus_data,
- * as long as CBUS is not involved.*/
+ /* Initial (C|D)(Bus|Ddr) values for additional pins.
+ * MPSSE_CS|DI|DO|SK are initialized accordig to mode.*/
+ data_desc_t init;
+ /* MPSSE command to read TMS/SWDIO in bitbanging SWD.
+ * In many cases this is the TMS port, so then use "GET_PIN_LOW".*/
+ uint8_t bb_swdio_in_port_cmd;
+ /* bus bit to read TMS/SWDIO in bitbanging SWD.
+ * In many cases this is the TMS port, so then use "MPSSE_CS".*/
+ uint8_t bb_swdio_in_pin;
+ /* Bus data to allow bitbanging switched SWD read.
+ * TMS is routed to bb_swdio_in_port/pin.*/
+ pin_settings_t bb_swd_read;
+ /* Bus data to allow bitbanging switched SWD write.
+ * TMS is routed to MPSSE_CS.*/
+ pin_settings_t bb_swd_write;
+ /* dbus_data, dbus_ddr, cbus_data, cbus_ddr value to assert SRST.
+ * E.g. with CBUS Pin 1 low,
+ * give data_high = ~PIN1, ddr_high = PIN1 */
+ data_desc_t assert_srst;
+ /* Bus_data, dbus_ddr, cbus_data, cbus_ddr value to release SRST.
+ * E.g. with CBUS Pin 1 floating with internal pull up,
+ * give data_high = PIN1, ddr_high = ~PIN1 */
+ data_desc_t deassert_srst;
+ /* Command to read back SRST. If 0, port from assert_srst is used*/
+ uint8_t srst_get_port_cmd;
+ /* PIN to read back as SRST. if 0 port from assert_srst is ised.
+ * Use PINX if active high, use Complement (~PINX) if active low*/
+ uint8_t srst_get_pin;
+ /* Bbus data for pure MPSSE SWD read.
+ * Use together with swd_write if by some bits on DBUS,
+ * SWDIO can be routed to TDI and TDO.
+ * If both mpsse_swd_read|write and
+ * bitbang_swd_dbus_read_data/bitbang_tms_in_port_cmd/bitbang_tms_in_pin
+ * are provided, pure MPSSE SWD is choosen.
+ * If neither a complete set of swd_read|write or
+ * bitbang_swd_dbus_read_data/bitbang_tms_in_port_cmd/bitbang_tms_in_pin
+ * are provided, SWD can not be done.
+ * swd_read.set_data_low == swd_write.set_data_low == MPSSE_DO
+ * indicated resistor SWD and inhibits Jtag.*/
+ pin_settings_t mpsse_swd_read;
+ /* dbus data for pure MPSSE SWD write.*/
+ pin_settings_t mpsse_swd_write;
+ /* dbus data for jtag.*/
+ pin_settings_t jtag;
+ /* Command to read port to check target voltage.*/
+ uint8_t target_voltage_cmd;
+ /* Pin to check target voltage.*/
+ uint8_t target_voltage_pin;
+ /* USB readable description of the device.*/
char *description;
+ /* Command line argument to -c option to select this device.*/
char * name;
}cable_desc_t;
+extern cable_desc_t cable_desc[];
extern cable_desc_t *active_cable;
extern struct ftdi_context *ftdic;
+extern data_desc_t active_state;
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info);
@@ -53,9 +111,20 @@ void libftdi_buffer_flush(void);
int libftdi_buffer_write(const uint8_t *data, int size);
int libftdi_buffer_read(uint8_t *data, int size);
const char *libftdi_target_voltage(void);
+void libftdi_jtagtap_tdi_tdo_seq(
+ uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks);
+bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd);
-#define MPSSE_TDI 2
-#define MPSSE_TDO 4
-#define MPSSE_TMS 8
-
+#define MPSSE_SK 1
+#define PIN0 1
+#define MPSSE_DO 2
+#define PIN1 2
+#define MPSSE_DI 4
+#define PIN2 4
+#define MPSSE_CS 8
+#define PIN3 8
+#define PIN4 0x10
+#define PIN5 0x20
+#define PIN6 0x40
+#define PIN7 0x80
#endif
diff --git a/src/platforms/hosted/libftdi_jtagtap.c b/src/platforms/hosted/libftdi_jtagtap.c
index 30c8578b..7642129d 100644
--- a/src/platforms/hosted/libftdi_jtagtap.c
+++ b/src/platforms/hosted/libftdi_jtagtap.c
@@ -20,8 +20,6 @@
/* Low level JTAG implementation using FT2232 with libftdi.
*
- * Issues:
- * Should share interface with swdptap.c or at least clean up...
*/
#include
@@ -38,50 +36,59 @@ extern struct ftdi_context *ftdic;
static void jtagtap_reset(void);
static void jtagtap_tms_seq(uint32_t MS, int ticks);
-static void jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms,
- const uint8_t *DI, int ticks);
static void jtagtap_tdi_seq(
const uint8_t final_tms, const uint8_t *DI, int ticks);
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI);
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc)
{
- assert(ftdic != NULL);
- int err = ftdi_usb_purge_buffers(ftdic);
- if (err != 0) {
- DEBUG_WARN("ftdi_usb_purge_buffer: %d: %s\n",
- err, ftdi_get_error_string(ftdic));
- abort();
+ if ((active_cable->mpsse_swd_read.set_data_low == MPSSE_DO) &&
+ (active_cable->mpsse_swd_write.set_data_low == MPSSE_DO)) {
+ printf("Jtag not possible with resistor SWD!\n");
+ return -1;
}
- /* Reset MPSSE controller. */
- err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
- if (err != 0) {
- DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
- err, ftdi_get_error_string(ftdic));
- return -1;
- }
- /* Enable MPSSE controller. Pin directions are set later.*/
- err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
- if (err != 0) {
- DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
- err, ftdi_get_error_string(ftdic));
- return -1;
- }
- uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x00, 0x00, SET_BITS_LOW, 0,0,
- SET_BITS_HIGH, 0,0};
- ftdi_init[4]= active_cable->dbus_data;
- ftdi_init[5]= active_cable->dbus_ddr;
- ftdi_init[7]= active_cable->cbus_data;
- ftdi_init[8]= active_cable->cbus_ddr;
- libftdi_buffer_write(ftdi_init, 9);
- libftdi_buffer_flush();
-
jtag_proc->jtagtap_reset = jtagtap_reset;
jtag_proc->jtagtap_next =jtagtap_next;
jtag_proc->jtagtap_tms_seq = jtagtap_tms_seq;
- jtag_proc->jtagtap_tdi_tdo_seq = jtagtap_tdi_tdo_seq;
+ jtag_proc->jtagtap_tdi_tdo_seq = libftdi_jtagtap_tdi_tdo_seq;
jtag_proc->jtagtap_tdi_seq = jtagtap_tdi_seq;
+ active_state.data_low |= active_cable->jtag.set_data_low |
+ MPSSE_CS | MPSSE_DI | MPSSE_DO;
+ active_state.data_low &= ~(active_cable->jtag.clr_data_low | MPSSE_SK);
+ active_state.ddr_low |= MPSSE_CS | MPSSE_DO | MPSSE_SK;
+ active_state.ddr_low &= ~(MPSSE_DI);
+ active_state.data_high |= active_cable->jtag.set_data_high;
+ active_state.data_high &= ~(active_cable->jtag.clr_data_high);
+ uint8_t gab[16];
+ int garbage = ftdi_read_data(ftdic, gab, sizeof(gab));
+ if (garbage > 0) {
+ DEBUG_WARN("FTDI JTAG init got garbage:");
+ for (int i = 0; i < garbage; i++)
+ DEBUG_WARN(" %02x", gab[i]);
+ DEBUG_WARN("\n");
+ }
+ uint8_t cmd_write[16] = {
+ SET_BITS_LOW, active_state.data_low,
+ active_state.ddr_low,
+ SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
+ libftdi_buffer_write(cmd_write, 6);
+ libftdi_buffer_flush();
+ /* Write out start condition and pull garbage from read buffer.
+ * FT2232D otherwise misbehaves on runs follwoing the first run.*/
+ garbage = ftdi_read_data(ftdic, cmd_write, sizeof(cmd_write));
+ if (garbage > 0) {
+ DEBUG_WARN("FTDI JTAG end init got garbage:");
+ for (int i = 0; i < garbage; i++)
+ DEBUG_WARN(" %02x", cmd_write[i]);
+ DEBUG_WARN("\n");
+ }
+ /* Go to JTAG mode for SWJ-DP */
+ for (int i = 0; i <= 50; i++)
+ jtag_proc->jtagtap_next(1, 0); /* Reset SW-DP */
+ jtag_proc->jtagtap_tms_seq(0xE73C, 16); /* SWD to JTAG sequence */
+ jtag_proc->jtagtap_tms_seq(0x1F, 6);
+
return 0;
}
@@ -93,7 +100,7 @@ static void jtagtap_reset(void)
static void jtagtap_tms_seq(uint32_t MS, int ticks)
{
uint8_t tmp[3] = {
- MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE| MPSSE_READ_NEG, 0, 0};
+ MPSSE_WRITE_TMS | MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG, 0, 0};
while(ticks >= 0) {
tmp[1] = ticks<7?ticks-1:6;
tmp[2] = 0x80 | (MS & 0x7F);
@@ -103,77 +110,10 @@ static void jtagtap_tms_seq(uint32_t MS, int ticks)
}
}
-static void jtagtap_tdi_tdo_seq(
- uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
-{
- int rsize, rticks;
-
- if(!ticks) return;
- if (!DI && !DO) return;
-
-// DEBUG_PROBE("ticks: %d\n", ticks);
- if(final_tms) ticks--;
- rticks = ticks & 7;
- ticks >>= 3;
- uint8_t data[3];
- uint8_t cmd = ((DO)? MPSSE_DO_READ : 0) |
- ((DI)? (MPSSE_DO_WRITE | MPSSE_WRITE_NEG) : 0) | MPSSE_LSB;
- rsize = ticks;
- if(ticks) {
- data[0] = cmd;
- data[1] = ticks - 1;
- data[2] = 0;
- libftdi_buffer_write(data, 3);
- if (DI)
- libftdi_buffer_write(DI, ticks);
- }
- if(rticks) {
- int index = 0;
- rsize++;
- data[index++] = cmd | MPSSE_BITMODE;
- data[index++] = rticks - 1;
- if (DI)
- data[index++] = DI[ticks];
- libftdi_buffer_write(data, index);
- }
- if(final_tms) {
- int index = 0;
- rsize++;
- data[index++] = MPSSE_WRITE_TMS | ((DO)? MPSSE_DO_READ : 0) |
- MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG;
- data[index++] = 0;
- if (DI)
- data[index++] = (DI[ticks]) >> rticks?0x81 : 0x01;
- libftdi_buffer_write(data, index);
- }
- if (DO) {
- int index = 0;
- uint8_t *tmp = alloca(ticks);
- libftdi_buffer_read(tmp, rsize);
- if(final_tms) rsize--;
-
- while(rsize--) {
- if(rsize) DEBUG_WIRE("%02X ", tmp[index]);
- *DO++ = tmp[index++];
- }
- if (rticks == 0)
- *DO++ = 0;
- if(final_tms) {
- rticks++;
- *(--DO) >>= 1;
- *DO |= tmp[index] & 0x80;
- } else DO--;
- if(rticks) {
- *DO >>= (8-rticks);
- }
- DEBUG_WIRE("%02X\n", *DO);
- }
-}
-
static void jtagtap_tdi_seq(
const uint8_t final_tms, const uint8_t *DI, int ticks)
{
- return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks);
+ return libftdi_jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks);
}
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
@@ -187,7 +127,5 @@ static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
ret &= 0x80;
-// DEBUG("jtagtap_next(TMS = %d, TDI = %d) = %02X\n", dTMS, dTDI, ret);
-
return ret;
}
diff --git a/src/platforms/hosted/libftdi_swdptap.c b/src/platforms/hosted/libftdi_swdptap.c
index 91e54284..575b7138 100644
--- a/src/platforms/hosted/libftdi_swdptap.c
+++ b/src/platforms/hosted/libftdi_swdptap.c
@@ -28,52 +28,183 @@
#include "general.h"
#include "ftdi_bmp.h"
-static uint8_t olddir = 0;
+enum swdio_status{
+ SWDIO_STATUS_DRIVE = 0,
+ SWDIO_STATUS_FLOAT,
+};
-#define MPSSE_MASK (MPSSE_TDI | MPSSE_TDO | MPSSE_TMS)
-#define MPSSE_TD_MASK (MPSSE_TDI | MPSSE_TDO)
+static enum swdio_status olddir;
+static bool do_mpsse;
+static bool direct_bb_swd;
+
+#define MPSSE_MASK (MPSSE_DO | MPSSE_DI | MPSSE_CS)
+#define MPSSE_TD_MASK (MPSSE_DO | MPSSE_DI)
#define MPSSE_TMS_SHIFT (MPSSE_WRITE_TMS | MPSSE_LSB |\
MPSSE_BITMODE | MPSSE_WRITE_NEG)
+#define MPSSE_TDO_SHIFT (MPSSE_DO_WRITE | MPSSE_LSB |\
+ MPSSE_BITMODE | MPSSE_WRITE_NEG)
+static void swdptap_turnaround(enum swdio_status dir)
+{
+ if (dir == olddir)
+ return;
+ olddir = dir;
+ DEBUG_PROBE("Turnaround %s\n", (dir == SWDIO_STATUS_FLOAT) ? "float": "drive");
+ if (do_mpsse) {
+ if (dir == SWDIO_STATUS_FLOAT) /* SWDIO goes to input */ {
+ active_state.data_low |= active_cable->mpsse_swd_read.set_data_low | MPSSE_DO;
+ active_state.data_low &= ~active_cable->mpsse_swd_read.clr_data_low;
+ active_state.ddr_low &= ~MPSSE_DO;
+ active_state.data_high |= active_cable->mpsse_swd_read.set_data_high;
+ active_state.data_high &= ~active_cable->mpsse_swd_read.clr_data_high;
+ uint8_t cmd_read[6] = {
+ SET_BITS_LOW, active_state.data_low,
+ active_state.ddr_low,
+ SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
+ libftdi_buffer_write(cmd_read, 6);
+ }
+ uint8_t cmd[] = {MPSSE_TDO_SHIFT, 0, 0}; /* One clock cycle */
+ libftdi_buffer_write(cmd, sizeof(cmd));
+ if (dir == SWDIO_STATUS_DRIVE) /* SWDIO goes to output */ {
+ active_state.data_low |= active_cable->mpsse_swd_write.set_data_low | MPSSE_DO;
+ active_state.data_low &= ~active_cable->mpsse_swd_write.clr_data_low;
+ active_state.ddr_low |= MPSSE_DO;
+ active_state.data_high |= active_cable->mpsse_swd_write.set_data_high;
+ active_state.data_high &= ~active_cable->mpsse_swd_write.clr_data_high;
+ uint8_t cmd_write[6] = {
+ SET_BITS_LOW, active_state.data_low,
+ active_state.ddr_low,
+ SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
+ libftdi_buffer_write(cmd_write, 6);
+ }
+ } else {
+ uint8_t cmd[9];
+ int index = 0;
+
+ if(dir == SWDIO_STATUS_FLOAT) { /* SWDIO goes to input */
+ if (direct_bb_swd) {
+ active_state.data_low |= MPSSE_CS;
+ active_state.ddr_low &= ~MPSSE_CS;
+ } else {
+ active_state.data_low |= active_cable->bb_swd_read.set_data_low;
+ active_state.data_low &= ~active_cable->bb_swd_read.clr_data_low;
+ active_state.data_high |= active_cable->bb_swd_read.set_data_high;
+ active_state.data_high &= ~active_cable->bb_swd_read.clr_data_high;
+ }
+ cmd[index++] = SET_BITS_LOW;
+ cmd[index++] = active_state.data_low;
+ cmd[index++] = active_state.ddr_low;
+ cmd[index++] = SET_BITS_HIGH;
+ cmd[index++] = active_state.data_high;
+ cmd[index++] = active_state.ddr_high;
+ }
+ /* One clock cycle */
+ cmd[index++] = MPSSE_TMS_SHIFT;
+ cmd[index++] = 0;
+ cmd[index++] = 0;
+ if (dir == SWDIO_STATUS_DRIVE) {
+ if (direct_bb_swd) {
+ active_state.data_low |= MPSSE_CS;
+ active_state.ddr_low |= MPSSE_CS;
+ } else {
+ active_state.data_low |= active_cable->bb_swd_write.set_data_low;
+ active_state.data_low &= ~active_cable->bb_swd_write.clr_data_low;
+ active_state.data_high |= active_cable->bb_swd_write.set_data_high;
+ active_state.data_high &= ~active_cable->bb_swd_write.clr_data_high;
+ }
+ cmd[index++] = SET_BITS_LOW;
+ cmd[index++] = active_state.data_low;
+ cmd[index++] = active_state.ddr_low;
+ cmd[index++] = SET_BITS_HIGH;
+ cmd[index++] = active_state.data_high;
+ cmd[index++] = active_state.ddr_high;
+ }
+ libftdi_buffer_write(cmd, index);
+ }
+}
static bool swdptap_seq_in_parity(uint32_t *res, int ticks);
static uint32_t swdptap_seq_in(int ticks);
static void swdptap_seq_out(uint32_t MS, int ticks);
static void swdptap_seq_out_parity(uint32_t MS, int ticks);
+bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd)
+{
+ bool swd_read =
+ active_cable->mpsse_swd_read.set_data_low ||
+ active_cable->mpsse_swd_read.clr_data_low ||
+ active_cable->mpsse_swd_read.set_data_high ||
+ active_cable->mpsse_swd_read.clr_data_high;
+ bool swd_write =
+ active_cable->mpsse_swd_write.set_data_low ||
+ active_cable->mpsse_swd_write.clr_data_low ||
+ active_cable->mpsse_swd_write.set_data_high ||
+ active_cable->mpsse_swd_write.clr_data_high;
+ bool mpsse = swd_read && swd_write;
+ if (do_mpsse)
+ *do_mpsse = mpsse;
+ if (!mpsse) {
+ bool bb_swd_read =
+ active_cable->bb_swd_read.set_data_low ||
+ active_cable->bb_swd_read.clr_data_low ||
+ active_cable->bb_swd_read.set_data_high ||
+ active_cable->bb_swd_read.clr_data_high;
+ bool bb_swd_write =
+ active_cable->bb_swd_write.set_data_low ||
+ active_cable->bb_swd_write.clr_data_low ||
+ active_cable->bb_swd_write.set_data_high ||
+ active_cable->bb_swd_write.clr_data_high;
+ bool bb_direct_possible =
+ active_cable->bb_swdio_in_port_cmd == GET_BITS_LOW &&
+ active_cable->bb_swdio_in_pin == MPSSE_CS;
+ if (!bb_swd_read && !bb_swd_write) {
+ if (!bb_direct_possible)
+ return false;
+ }
+ if (direct_bb_swd)
+ *direct_bb_swd = true;
+ }
+ return true;
+}
+
int libftdi_swdptap_init(swd_proc_t *swd_proc)
{
- if (!active_cable->bitbang_tms_in_pin) {
+ if (!libftdi_swd_possible(&do_mpsse, &direct_bb_swd)) {
DEBUG_WARN("SWD not possible or missing item in cable description.\n");
return -1;
}
- int err = ftdi_usb_purge_buffers(ftdic);
- if (err != 0) {
- DEBUG_WARN("ftdi_usb_purge_buffer: %d: %s\n",
- err, ftdi_get_error_string(ftdic));
- return -1;
+ active_state.data_low |= MPSSE_CS | MPSSE_DI | MPSSE_DO;
+ active_state.data_low &= MPSSE_SK;
+ active_state.ddr_low |= MPSSE_SK;
+ active_state.ddr_low &= ~(MPSSE_CS | MPSSE_DI | MPSSE_DO);
+ if (do_mpsse) {
+ DEBUG_INFO("Using genuine MPSSE for SWD.\n");
+ active_state.data_low |= active_cable->mpsse_swd_read.set_data_low;
+ active_state.data_low &= ~(active_cable->mpsse_swd_read.clr_data_low);
+ active_state.data_high |= active_cable->mpsse_swd_read.set_data_high;
+ active_state.data_high &= ~(active_cable->mpsse_swd_read.clr_data_high);
+ } else if (direct_bb_swd) {
+ DEBUG_INFO("Using direct bitbang with SWDIO %cBUS%d.\n",
+ (active_cable->bb_swdio_in_port_cmd == GET_BITS_LOW) ? 'C' : 'D',
+ __builtin_ctz(active_cable->bb_swdio_in_pin));
+ } else {
+ DEBUG_INFO("Using switched bitbang for SWD.\n");
+ active_state.data_low |= active_cable->bb_swd_read.set_data_low;
+ active_state.data_low &= ~(active_cable->bb_swd_read.clr_data_low);
+ active_state.data_high |= active_cable->bb_swd_read.set_data_high;
+ active_state.data_high &= ~(active_cable->bb_swd_read.clr_data_high);
+ active_state.ddr_low |= MPSSE_CS;
+ if (active_cable->bb_swdio_in_port_cmd == GET_BITS_LOW)
+ active_state.ddr_low &= ~active_cable->bb_swdio_in_pin;
+ else if (active_cable->bb_swdio_in_port_cmd == GET_BITS_HIGH)
+ active_state.ddr_high &= ~active_cable->bb_swdio_in_pin;
}
- /* Reset MPSSE controller. */
- err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
- if (err != 0) {
- DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
- err, ftdi_get_error_string(ftdic));
- return -1;
- }
- /* Enable MPSSE controller. Pin directions are set later.*/
- err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
- if (err != 0) {
- DEBUG_WARN("ftdi_set_bitmode: %d: %s\n",
- err, ftdi_get_error_string(ftdic));
- return -1;
- }
- uint8_t ftdi_init[9] = {TCK_DIVISOR, 0x01, 0x00, SET_BITS_LOW, 0,0,
- SET_BITS_HIGH, 0,0};
- ftdi_init[4]= active_cable->dbus_data | MPSSE_MASK;
- ftdi_init[5]= active_cable->dbus_ddr & ~MPSSE_TD_MASK;
- ftdi_init[7]= active_cable->cbus_data;
- ftdi_init[8]= active_cable->cbus_ddr;
- libftdi_buffer_write(ftdi_init, 9);
+ uint8_t cmd_write[6] = {
+ SET_BITS_LOW, active_state.data_low,
+ active_state.ddr_low,
+ SET_BITS_HIGH, active_state.data_high, active_state.ddr_high};
+ libftdi_buffer_write(cmd_write, 6);
libftdi_buffer_flush();
+ olddir = SWDIO_STATUS_FLOAT;
swd_proc->swdptap_seq_in = swdptap_seq_in;
swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
@@ -83,136 +214,185 @@ int libftdi_swdptap_init(swd_proc_t *swd_proc)
return 0;
}
-static void swdptap_turnaround(uint8_t dir)
+bool swdptap_bit_in(void)
{
- if (dir == olddir)
- return;
- olddir = dir;
- uint8_t cmd[6];
+ swdptap_turnaround(SWDIO_STATUS_FLOAT);
+ uint8_t cmd[4];
int index = 0;
+ bool result = false;
- if(dir) { /* SWDIO goes to input */
- cmd[index++] = SET_BITS_LOW;
- if (active_cable->bitbang_swd_dbus_read_data)
- cmd[index] = active_cable->bitbang_swd_dbus_read_data;
- else
- cmd[index] = active_cable->dbus_data;
- index++;
- cmd[index++] = active_cable->dbus_ddr & ~MPSSE_MASK;
+ if (do_mpsse) {
+ uint8_t cmd[2] = {MPSSE_DO_READ | MPSSE_LSB | MPSSE_BITMODE, 0};
+ libftdi_buffer_write(cmd, sizeof(cmd));
+ uint8_t data[1];
+ libftdi_buffer_read(data, sizeof(data));
+ result = (data[0] & 0x80);
+ } else {
+ cmd[index++] = active_cable->bb_swdio_in_port_cmd;
+ cmd[index++] = MPSSE_TMS_SHIFT;
+ cmd[index++] = 0;
+ cmd[index++] = 0;
+ libftdi_buffer_write(cmd, index);
+ uint8_t data[1];
+ libftdi_buffer_read(data, sizeof(data));
+ result = (data[0] &= active_cable->bb_swdio_in_pin);
}
- /* One clock cycle */
- cmd[index++] = MPSSE_TMS_SHIFT;
- cmd[index++] = 0;
- cmd[index++] = 0;
- if (!dir) {
- cmd[index++] = SET_BITS_LOW;
- cmd[index++] = active_cable->dbus_data | MPSSE_MASK;
- cmd[index++] = active_cable->dbus_ddr & ~MPSSE_TD_MASK;
- }
- libftdi_buffer_write(cmd, index);
+ return result;
}
-static bool swdptap_seq_in_parity(uint32_t *res, int ticks)
+void swdptap_bit_out(bool val)
{
- int index = ticks + 1;
- uint8_t cmd[4];
- unsigned int parity = 0;
-
- cmd[0] = active_cable->bitbang_tms_in_port_cmd;
- cmd[1] = MPSSE_TMS_SHIFT;
- cmd[2] = 0;
- cmd[3] = 0;
- swdptap_turnaround(1);
- while (index--) {
- libftdi_buffer_write(cmd, 4);
+ swdptap_turnaround(SWDIO_STATUS_DRIVE);
+ if (do_mpsse) {
+ uint8_t cmd[3] = {MPSSE_TDO_SHIFT, 0, (val)? 1:0};
+ libftdi_buffer_write(cmd, sizeof(cmd));
+ } else {
+ uint8_t cmd[3];
+ cmd[0] = MPSSE_TMS_SHIFT;
+ cmd[1] = 0;
+ cmd[2] = (val)? 1 : 0;
+ libftdi_buffer_write(cmd, sizeof(cmd));
}
- uint8_t data[33];
- unsigned int ret = 0;
- libftdi_buffer_read(data, ticks + 1);
- if (data[ticks] & active_cable->bitbang_tms_in_pin)
- parity ^= 1;
- while (ticks--) {
- if (data[ticks] & active_cable->bitbang_tms_in_pin) {
+}
+
+bool swdptap_seq_in_parity(uint32_t *res, int ticks)
+{
+ assert(ticks == 32);
+ swdptap_turnaround(SWDIO_STATUS_FLOAT);
+ unsigned int parity = 0;
+ unsigned int result = 0;
+ if (do_mpsse) {
+ uint8_t DO[5];
+ libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks + 1);
+ result = DO[0] + (DO[1] << 8) + (DO[2] << 16) + (DO[3] << 24);
+ parity = __builtin_parity(result & ((1LL << ticks) - 1)) & 1;
+ parity ^= DO[4] & 1;
+ } else {
+ int index = ticks + 1;
+ uint8_t cmd[4];
+
+ cmd[0] = active_cable->bb_swdio_in_port_cmd;
+ cmd[1] = MPSSE_TMS_SHIFT;
+ cmd[2] = 0;
+ cmd[3] = 0;
+ while (index--) {
+ libftdi_buffer_write(cmd, sizeof(cmd));
+ }
+ uint8_t data[33];
+ libftdi_buffer_read(data, ticks + 1);
+ if (data[ticks] & active_cable->bb_swdio_in_pin)
parity ^= 1;
- ret |= (1 << ticks);
+ index = ticks;
+ while (index--) {
+ if (data[index] & active_cable->bb_swdio_in_pin) {
+ parity ^= 1;
+ result |= (1 << index);
+ }
}
}
- *res = ret;
+ *res = result;
return parity;
}
static uint32_t swdptap_seq_in(int ticks)
{
- int index = ticks;
- uint8_t cmd[4];
+ if (!ticks)
+ return 0;
+ uint32_t result = 0;
+ swdptap_turnaround(SWDIO_STATUS_FLOAT);
+ if (do_mpsse) {
+ uint8_t DO[4];
+ libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks);
+ for (int i = 0; i < (ticks >> 3) + (ticks & 7)? 1: 0; i++) {
+ result |= DO[i] << (8 * i);
+ }
+ } else {
+ int index = ticks;
+ uint8_t cmd[4];
- cmd[0] = active_cable->bitbang_tms_in_port_cmd;
- cmd[1] = MPSSE_TMS_SHIFT;
- cmd[2] = 0;
- cmd[3] = 0;
+ cmd[0] = active_cable->bb_swdio_in_port_cmd;
+ cmd[1] = MPSSE_TMS_SHIFT;
+ cmd[2] = 0;
+ cmd[3] = 0;
- swdptap_turnaround(1);
- while (index--) {
- libftdi_buffer_write(cmd, 4);
+ while (index--) {
+ libftdi_buffer_write(cmd, sizeof(cmd));
+ }
+ uint8_t data[32];
+ libftdi_buffer_read(data, ticks);
+ index = ticks;
+ while (index--) {
+ if (data[index] & active_cable->bb_swdio_in_pin)
+ result |= (1 << index);
+ }
}
- uint8_t data[32];
- uint32_t ret = 0;
- libftdi_buffer_read(data, ticks);
- while (ticks--) {
- if (data[ticks] & active_cable->bitbang_tms_in_pin)
- ret |= (1 << ticks);
- }
- return ret;
+ return result;
}
static void swdptap_seq_out(uint32_t MS, int ticks)
{
- uint8_t cmd[15];
- unsigned int index = 0;
- swdptap_turnaround(0);
- while (ticks) {
- cmd[index++] = MPSSE_TMS_SHIFT;
- if (ticks >= 7) {
- cmd[index++] = 6;
- cmd[index++] = MS & 0x7f;
- MS >>= 7;
- ticks -= 7;
- } else {
- cmd[index++] = ticks - 1;
- cmd[index++] = MS & 0x7f;
- ticks = 0;
+ if (!ticks)
+ return;
+ swdptap_turnaround(SWDIO_STATUS_DRIVE);
+ if (do_mpsse) {
+ uint8_t DI[4];
+ DI[0] = (MS >> 0) & 0xff;
+ DI[1] = (MS >> 8) & 0xff;
+ DI[2] = (MS >> 16) & 0xff;
+ DI[3] = (MS >> 24) & 0xff;
+ libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, ticks);
+ } else {
+ uint8_t cmd[16];
+ unsigned int index = 0;
+ while (ticks) {
+ cmd[index++] = MPSSE_TMS_SHIFT;
+ if (ticks >= 7) {
+ cmd[index++] = 6;
+ cmd[index++] = MS & 0x7f;
+ MS >>= 7;
+ ticks -= 7;
+ } else {
+ cmd[index++] = ticks - 1;
+ cmd[index++] = MS & 0x7f;
+ ticks = 0;
+ }
}
+ libftdi_buffer_write(cmd, index);
}
- libftdi_buffer_write(cmd, index);
}
static void swdptap_seq_out_parity(uint32_t MS, int ticks)
{
- uint8_t parity = 0;
- int steps = ticks;
- uint8_t cmd[18];
+ int parity = __builtin_parity(MS & ((1LL << ticks) - 1)) & 1;
unsigned int index = 0;
- uint32_t data = MS;
- swdptap_turnaround(0);
- while (steps) {
- cmd[index++] = MPSSE_TMS_SHIFT;
- if (steps >= 7) {
- cmd[index++] = 6;
- cmd[index++] = data & 0x7f;
- data >>= 7;
- steps -= 7;
- } else {
- cmd[index++] = steps - 1;
- cmd[index++] = data & 0x7f;
- steps = 0;
+ swdptap_turnaround(SWDIO_STATUS_DRIVE);
+ if (do_mpsse) {
+ uint8_t DI[8];
+ DI[0] = (MS >> 0) & 0xff;
+ DI[1] = (MS >> 8) & 0xff;
+ DI[2] = (MS >> 16) & 0xff;
+ DI[3] = (MS >> 24) & 0xff;
+ DI[4] = parity;
+ libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, ticks + 1);
+ } else {
+ uint8_t cmd[32];
+ int steps = ticks;
+ while (steps) {
+ cmd[index++] = MPSSE_TMS_SHIFT;
+ if (steps >= 7) {
+ cmd[index++] = 6;
+ cmd[index++] = MS & 0x7f;
+ MS >>= 7;
+ steps -= 7;
+ } else {
+ cmd[index++] = steps - 1;
+ cmd[index++] = MS & 0x7f;
+ steps = 0;
+ }
}
+ cmd[index++] = MPSSE_TMS_SHIFT;
+ cmd[index++] = 0;
+ cmd[index++] = parity;
+ libftdi_buffer_write(cmd, index);
}
- while (ticks--) {
- parity ^= MS;
- MS >>= 1;
- }
- cmd[index++] = MPSSE_TMS_SHIFT;
- cmd[index++] = 0;
- cmd[index++] = parity;
- libftdi_buffer_write(cmd, index);
}
diff --git a/src/platforms/hosted/platform.c b/src/platforms/hosted/platform.c
index 631fa49c..1bb738a6 100644
--- a/src/platforms/hosted/platform.c
+++ b/src/platforms/hosted/platform.c
@@ -37,9 +37,6 @@
#include "jlink.h"
#include "cmsis_dap.h"
-#define VENDOR_ID_BMP 0x1d50
-#define PRODUCT_ID_BMP 0x6018
-
#define VENDOR_ID_STLINK 0x0483
#define PRODUCT_ID_STLINK_MASK 0xffe0
#define PRODUCT_ID_STLINK_GROUP 0x3740
@@ -101,6 +98,8 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
char product[128];
bmp_type_t type = BMP_TYPE_NONE;
bool access_problems = false;
+ char *active_cable = NULL;
+ bool ftdi_unknown = false;
rescan:
found_debuggers = 0;
for (int i = 0; devs[i]; i++) {
@@ -165,6 +164,8 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
if ((desc.idVendor == VENDOR_ID_BMP) &&
(desc.idProduct == PRODUCT_ID_BMP)) {
type = BMP_TYPE_BMP;
+ } else if ((strstr(manufacturer, "CMSIS")) || (strstr(product, "CMSIS"))) {
+ type = BMP_TYPE_CMSIS_DAP;
} else if (desc.idVendor == VENDOR_ID_STLINK) {
if ((desc.idProduct == PRODUCT_ID_STLINKV2) ||
(desc.idProduct == PRODUCT_ID_STLINKV21) ||
@@ -177,16 +178,45 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
DEBUG_WARN( "INFO: STLINKV1 not supported\n");
continue;
}
- } else if ((strstr(manufacturer, "CMSIS")) || (strstr(product, "CMSIS"))) {
- type = BMP_TYPE_CMSIS_DAP;
} else if (desc.idVendor == VENDOR_ID_SEGGER) {
type = BMP_TYPE_JLINK;
- } else{
- continue;
+ } else {
+ cable_desc_t *cable = &cable_desc[0];
+ for (; cable->name; cable++) {
+ bool found = false;
+ if ((cable->vendor != desc.idVendor) || (cable->product != desc.idProduct))
+ continue; /* VID/PID do not match*/
+ if (cl_opts->opt_cable) {
+ if (strcmp(cable->name, cl_opts->opt_cable))
+ continue; /* cable names do not match*/
+ else
+ found = true;
+ }
+ if (cable->description) {
+ if (strcmp(cable->description, product))
+ continue; /* discriptions do not match*/
+ else
+ found = true;
+ } else { /* VID/PID fits, but no cl_opts->opt_cable and no description*/
+ if ((cable->vendor == 0x0403) && /* FTDI*/
+ ((cable->product == 0x6010) || /* FT2232C/D/H*/
+ (cable->product == 0x6011) || /* FT4232H Quad HS USB-UART/FIFO IC */
+ (cable->product == 0x6014))) { /* FT232H Single HS USB-UART/FIFO IC */
+ ftdi_unknown = true;
+ continue; /* Cable name is needed */
+ }
+ }
+ if (found) {
+ active_cable = cable->name;
+ type = BMP_TYPE_LIBFTDI;
+ break;
+ }
+ }
+ if (!cable->name)
+ continue;
}
- found_debuggers ++;
if (report) {
- DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers,
+ DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers + 1,
serial,
manufacturer,product);
}
@@ -197,11 +227,19 @@ static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
strncpy(info->product, product, sizeof(info->product));
strncpy(info->manufacturer, manufacturer, sizeof(info->manufacturer));
if (cl_opts->opt_position &&
- (cl_opts->opt_position == found_debuggers)) {
+ (cl_opts->opt_position == (found_debuggers + 1))) {
found_debuggers = 1;
break;
+ } else {
+ found_debuggers++;
}
}
+ if ((found_debuggers == 0) && ftdi_unknown)
+ DEBUG_WARN("Generic FTDI MPSSE VID/PID found. Please specify exact type with \"-c \" !\n");
+ if ((found_debuggers == 1) && !cl_opts->opt_cable && (type == BMP_TYPE_LIBFTDI))
+ cl_opts->opt_cable = active_cable;
+ if (!found_debuggers && cl_opts->opt_list_only)
+ DEBUG_WARN("No usable debugger found\n");
if ((found_debuggers > 1) ||
((found_debuggers == 1) && (cl_opts->opt_list_only))) {
if (!report) {
@@ -242,12 +280,16 @@ void platform_init(int argc, char **argv)
if (cl_opts.opt_device) {
info.bmp_type = BMP_TYPE_BMP;
} else if (cl_opts.opt_cable) {
- /* check for libftdi devices*/
- res = ftdi_bmp_init(&cl_opts, &info);
- if (res)
- exit(-1);
- else
- info.bmp_type = BMP_TYPE_LIBFTDI;
+ if ((!strcmp(cl_opts.opt_cable, "list")) ||
+ (!strcmp(cl_opts.opt_cable, "l"))) {
+ cable_desc_t *cable = &cable_desc[0];
+ DEBUG_WARN("Available cables:\n");
+ for (; cable->name; cable++) {
+ DEBUG_WARN("\t%s\n", cable->name);
+ }
+ exit(0);
+ }
+ info.bmp_type = BMP_TYPE_LIBFTDI;
} else if (find_debuggers(&cl_opts, &info)) {
exit(-1);
}
@@ -269,6 +311,8 @@ void platform_init(int argc, char **argv)
exit(-1);
break;
case BMP_TYPE_LIBFTDI:
+ if (ftdi_bmp_init(&cl_opts, &info))
+ exit(-1);
break;
case BMP_TYPE_JLINK:
if (jlink_init(&info))
@@ -490,33 +534,51 @@ static void ap_decode_access(uint16_t addr, uint8_t RnW)
fprintf(stderr, "Read ");
else
fprintf(stderr, "Write ");
- switch(addr) {
- case 0x00:
- if (RnW)
- fprintf(stderr, "DP_DPIDR :");
- else
- fprintf(stderr, "DP_ABORT :");
- break;
- case 0x004: fprintf(stderr, "CTRL/STAT:");
- break;
- case 0x008:
- if (RnW)
- fprintf(stderr, "RESEND :");
- else
- fprintf(stderr, "DP_SELECT:");
- break;
- case 0x00c: fprintf(stderr, "DP_RDBUFF:");
- break;
- case 0x100: fprintf(stderr, "AP_CSW :");
- break;
- case 0x104: fprintf(stderr, "AP_TAR :");
- break;
- case 0x10c: fprintf(stderr, "AP_DRW :");
- break;
- case 0x1f8: fprintf(stderr, "AP_BASE :");
- break;
- case 0x1fc: fprintf(stderr, "AP_IDR :");
- break;
+ if (addr < 0x100) {
+ switch(addr) {
+ case 0x00:
+ if (RnW)
+ fprintf(stderr, "DP_DPIDR :");
+ else
+ fprintf(stderr, "DP_ABORT :");
+ break;
+ case 0x04: fprintf(stderr, "CTRL/STAT:");
+ break;
+ case 0x08:
+ if (RnW)
+ fprintf(stderr, "RESEND :");
+ else
+ fprintf(stderr, "DP_SELECT:");
+ break;
+ case 0x0c: fprintf(stderr, "DP_RDBUFF:");
+ break;
+ default: fprintf(stderr, "Unknown %02x :", addr);
+ }
+ } else {
+ fprintf(stderr, "AP 0x%02x ", addr >> 8);
+ switch (addr & 0xff) {
+ case 0x00: fprintf(stderr, "CSW :");
+ break;
+ case 0x04: fprintf(stderr, "TAR :");
+ break;
+ case 0x0c: fprintf(stderr, "DRW :");
+ break;
+ case 0x10: fprintf(stderr, "DB0 :");
+ break;
+ case 0x14: fprintf(stderr, "DB1 :");
+ break;
+ case 0x18: fprintf(stderr, "DB2 :");
+ break;
+ case 0x1c: fprintf(stderr, "DB3 :");
+ break;
+ case 0xf8: fprintf(stderr, "BASE :");
+ break;
+ case 0xf4: fprintf(stderr, "CFG :");
+ break;
+ case 0xfc: fprintf(stderr, "IDR :");
+ break;
+ default: fprintf(stderr, "RSVD%02x:", addr & 0xff);
+ }
}
}
diff --git a/src/platforms/hosted/platform.h b/src/platforms/hosted/platform.h
index b0e50432..e36d7b96 100644
--- a/src/platforms/hosted/platform.h
+++ b/src/platforms/hosted/platform.h
@@ -14,6 +14,9 @@ void platform_buffer_flush(void);
#define SET_IDLE_STATE(x)
#define SET_RUN_STATE(x)
+#define VENDOR_ID_BMP 0x1d50
+#define PRODUCT_ID_BMP 0x6018
+
typedef enum bmp_type_s {
BMP_TYPE_NONE = 0,
BMP_TYPE_BMP,
diff --git a/src/platforms/hosted/stlinkv2.c b/src/platforms/hosted/stlinkv2.c
index 110bbc63..9a645d6f 100644
--- a/src/platforms/hosted/stlinkv2.c
+++ b/src/platforms/hosted/stlinkv2.c
@@ -311,6 +311,7 @@ static int stlink_usb_error_check(uint8_t *data, bool verbose)
case STLINK_SWD_AP_STICKY_ERROR:
if (verbose)
DEBUG_WARN("STLINK_SWD_AP_STICKY_ERROR\n");
+ Stlink.ap_error = true;
return STLINK_ERROR_FAIL;
case STLINK_SWD_AP_STICKYORUN_ERROR:
if (verbose)
@@ -686,11 +687,10 @@ static int stlink_enter_debug_jtag(bmp_info_t *info)
static uint32_t stlink_read_coreid(void)
{
- uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
- STLINK_DEBUG_READCOREID};
- uint8_t data[4];
- send_recv(info.usb_link, cmd, 16, data, 4);
- uint32_t id = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24;
+ uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, STLINK_DEBUG_APIV2_READ_IDCODES};
+ uint8_t data[12];
+ send_recv(info.usb_link, cmd, 16, data, 12);
+ uint32_t id = data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24;
DEBUG_INFO("Read Core ID: 0x%08" PRIx32 "\n", id);
return id;
}
@@ -897,7 +897,8 @@ static void stlink_readmem(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
* Approach taken:
* Fill the memory with some fixed pattern so hopefully
* the caller notices the error*/
- DEBUG_WARN("stlink_readmem failed\n");
+ DEBUG_WARN("stlink_readmem from %" PRIx32 " to %" PRIx32 ", len %"
+ PRIx32 "failed\n", src, dest, (uint32_t) len);
memset(dest, 0xff, len);
}
DEBUG_PROBE("stlink_readmem from %" PRIx32 " to %" PRIx32 ", len %" PRIx32
@@ -1027,10 +1028,6 @@ static uint32_t stlink_ap_read(ADIv5_AP_t *ap, uint16_t addr)
return ret;
}
-struct jtag_dev_s jtag_devs[JTAG_MAX_DEVS+1];
-int jtag_dev_count;
-jtag_proc_t jtag_proc;
-
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens)
{
uint32_t idcodes[JTAG_MAX_DEVS+1];
@@ -1094,7 +1091,7 @@ int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp)
STLINK_DEBUG_ENTER_SWD_NO_RESET};
uint8_t data[2];
DEBUG_INFO("Enter SWD\n");
- send_recv(info->usb_link, cmd, 16, data, 2);
+ stlink_send_recv_retry(cmd, 16, data, 2);
if (stlink_usb_error_check(data, true))
return -1;
dp->idcode = stlink_read_coreid();
diff --git a/src/platforms/pc/cl_utils.c b/src/platforms/pc/cl_utils.c
index 38d3c729..1ff350e7 100644
--- a/src/platforms/pc/cl_utils.c
+++ b/src/platforms/pc/cl_utils.c
@@ -129,12 +129,15 @@ static void cl_help(char **argv, BMP_CL_OPTIONS_t *opt)
DEBUG_WARN("\t-s \"serial\"\t: Use dongle with (partial) "
"serial number \"serial\"\n");
DEBUG_WARN("\t-c \"string\"\t: Use ftdi dongle with type \"string\"\n");
+ DEBUG_WARN("\t\t Use \"list\" to list available cables\n");
DEBUG_WARN("Run mode related options:\n");
DEBUG_WARN("\tDefault mode is to start the debug server at :2000\n");
DEBUG_WARN("\t-j\t\t: Use JTAG. SWD is default.\n");
DEBUG_WARN("\t-C\t\t: Connect under reset\n");
DEBUG_WARN("\t-t\t\t: Scan SWD or JTAG and display information about \n"
"\t\t\t connected devices\n");
+ DEBUG_WARN("\t-e\t\t: Assume \"resistor SWD connection\" on FTDI: TDI\n"
+ "\t\t\t connected to TMS, TDO to TDI with eventual resistor\n");
DEBUG_WARN("\t-E\t\t: Erase flash until flash end or for given size\n");
DEBUG_WARN("\t-V\t\t: Verify flash against binary file\n");
DEBUG_WARN("\t-r\t\t: Read flash and write to binary file\n");
@@ -154,7 +157,7 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
int c;
opt->opt_target_dev = 1;
opt->opt_flash_size = 16 * 1024 *1024;
- while((c = getopt(argc, argv, "Ehv:d:s:I:c:CnltVta:S:jpP:rR")) != -1) {
+ while((c = getopt(argc, argv, "eEhv:d:s:I:c:CnltVta:S:jpP:rR")) != -1) {
switch(c) {
case 'c':
if (optarg)
@@ -177,6 +180,9 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
case 'C':
opt->opt_connect_under_reset = true;
break;
+ case 'e':
+ opt->external_resistor_swd = true;
+ break;
case 'd':
if (optarg)
opt->opt_device = optarg;
diff --git a/src/platforms/pc/cl_utils.h b/src/platforms/pc/cl_utils.h
index 3fedb7ec..e2bd4356 100644
--- a/src/platforms/pc/cl_utils.h
+++ b/src/platforms/pc/cl_utils.h
@@ -42,6 +42,7 @@ typedef struct BMP_CL_OPTIONS_s {
bool opt_tpwr;
bool opt_list_only;
bool opt_connect_under_reset;
+ bool external_resistor_swd;
char *opt_flash_file;
char *opt_device;
char *opt_serial;
diff --git a/src/platforms/pc/hid.c b/src/platforms/pc/hid.c
new file mode 100755
index 00000000..3d0425c5
--- /dev/null
+++ b/src/platforms/pc/hid.c
@@ -0,0 +1,1026 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ https://github.com/libusb/hidapi .
+********************************************************/
+
+#include
+
+#ifndef _NTDEF_
+typedef LONG NTSTATUS;
+#endif
+
+#ifdef __MINGW32__
+#include
+#include
+#endif
+
+#ifdef __CYGWIN__
+#include
+#define _wcsdup wcsdup
+#endif
+
+/* The maximum number of characters that can be passed into the
+ HidD_Get*String() functions without it failing.*/
+#define MAX_STRING_WCHARS 0xFFF
+
+/*#define HIDAPI_USE_DDK*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ #include
+ #include
+ #ifdef HIDAPI_USE_DDK
+ #include
+ #endif
+
+ /* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */
+ #define HID_OUT_CTL_CODE(id) \
+ CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+ #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
+ #define IOCTL_HID_GET_INPUT_REPORT HID_OUT_CTL_CODE(104)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#include
+#include
+
+
+#include "hidapi.h"
+
+#undef MIN
+#define MIN(x,y) ((x) < (y)? (x): (y))
+
+#ifdef _MSC_VER
+ /* Thanks Microsoft, but I know how to use strncpy(). */
+ #pragma warning(disable:4996)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef HIDAPI_USE_DDK
+ /* Since we're not building with the DDK, and the HID header
+ files aren't part of the SDK, we have to define all this
+ stuff here. In lookup_functions(), the function pointers
+ defined below are set. */
+ typedef struct _HIDD_ATTRIBUTES{
+ ULONG Size;
+ USHORT VendorID;
+ USHORT ProductID;
+ USHORT VersionNumber;
+ } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
+
+ typedef USHORT USAGE;
+ typedef struct _HIDP_CAPS {
+ USAGE Usage;
+ USAGE UsagePage;
+ USHORT InputReportByteLength;
+ USHORT OutputReportByteLength;
+ USHORT FeatureReportByteLength;
+ USHORT Reserved[17];
+ USHORT fields_not_used_by_hidapi[10];
+ } HIDP_CAPS, *PHIDP_CAPS;
+ typedef void* PHIDP_PREPARSED_DATA;
+ #define HIDP_STATUS_SUCCESS 0x110000
+
+ typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
+ typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length);
+ typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length);
+ typedef BOOLEAN (__stdcall *HidD_GetInputReport_)(HANDLE handle, PVOID data, ULONG length);
+ typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
+ typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
+ typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps);
+ typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
+
+ static HidD_GetAttributes_ HidD_GetAttributes;
+ static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;
+ static HidD_GetManufacturerString_ HidD_GetManufacturerString;
+ static HidD_GetProductString_ HidD_GetProductString;
+ static HidD_SetFeature_ HidD_SetFeature;
+ static HidD_GetFeature_ HidD_GetFeature;
+ static HidD_GetInputReport_ HidD_GetInputReport;
+ static HidD_GetIndexedString_ HidD_GetIndexedString;
+ static HidD_GetPreparsedData_ HidD_GetPreparsedData;
+ static HidD_FreePreparsedData_ HidD_FreePreparsedData;
+ static HidP_GetCaps_ HidP_GetCaps;
+ static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
+
+ static HMODULE lib_handle = NULL;
+ static BOOLEAN initialized = FALSE;
+#endif /* HIDAPI_USE_DDK */
+
+struct hid_device_ {
+ HANDLE device_handle;
+ BOOL blocking;
+ USHORT output_report_length;
+ size_t input_report_length;
+ void *last_error_str;
+ DWORD last_error_num;
+ BOOL read_pending;
+ char *read_buf;
+ OVERLAPPED ol;
+};
+
+static hid_device *new_hid_device()
+{
+ hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
+ dev->device_handle = INVALID_HANDLE_VALUE;
+ dev->blocking = TRUE;
+ dev->output_report_length = 0;
+ dev->input_report_length = 0;
+ dev->last_error_str = NULL;
+ dev->last_error_num = 0;
+ dev->read_pending = FALSE;
+ dev->read_buf = NULL;
+ memset(&dev->ol, 0, sizeof(dev->ol));
+ dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
+
+ return dev;
+}
+
+static void free_hid_device(hid_device *dev)
+{
+ CloseHandle(dev->ol.hEvent);
+ CloseHandle(dev->device_handle);
+ LocalFree(dev->last_error_str);
+ free(dev->read_buf);
+ free(dev);
+}
+
+static void register_error(hid_device *dev, const char *op)
+{
+ WCHAR *ptr, *msg;
+ (void) op;
+ FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPVOID)&msg, 0/*sz*/,
+ NULL);
+
+ /* Get rid of the CR and LF that FormatMessage() sticks at the
+ end of the message. Thanks Microsoft! */
+ ptr = msg;
+ while (*ptr) {
+ if (*ptr == '\r') {
+ *ptr = 0x0000;
+ break;
+ }
+ ptr++;
+ }
+
+ /* Store the message off in the Device entry so that
+ the hid_error() function can pick it up. */
+ LocalFree(dev->last_error_str);
+ dev->last_error_str = msg;
+}
+
+#ifndef HIDAPI_USE_DDK
+static int lookup_functions()
+{
+ lib_handle = LoadLibraryA("hid.dll");
+ if (lib_handle) {
+#if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1;
+ RESOLVE(HidD_GetAttributes);
+ RESOLVE(HidD_GetSerialNumberString);
+ RESOLVE(HidD_GetManufacturerString);
+ RESOLVE(HidD_GetProductString);
+ RESOLVE(HidD_SetFeature);
+ RESOLVE(HidD_GetFeature);
+ RESOLVE(HidD_GetInputReport);
+ RESOLVE(HidD_GetIndexedString);
+ RESOLVE(HidD_GetPreparsedData);
+ RESOLVE(HidD_FreePreparsedData);
+ RESOLVE(HidP_GetCaps);
+ RESOLVE(HidD_SetNumInputBuffers);
+#undef RESOLVE
+#if defined(__GNUC__)
+# pragma GCC diagnostic pop
+#endif
+ }
+ else
+ return -1;
+
+ return 0;
+}
+#endif
+
+static HANDLE open_device(const char *path, BOOL open_rw)
+{
+ HANDLE handle;
+ DWORD desired_access = (open_rw)? (GENERIC_WRITE | GENERIC_READ): 0;
+ DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
+
+ handle = CreateFileA(path,
+ desired_access,
+ share_mode,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
+ 0);
+
+ return handle;
+}
+
+int HID_API_EXPORT hid_init(void)
+{
+#ifndef HIDAPI_USE_DDK
+ if (!initialized) {
+ if (lookup_functions() < 0) {
+ hid_exit();
+ return -1;
+ }
+ initialized = TRUE;
+ }
+#endif
+ return 0;
+}
+
+int HID_API_EXPORT hid_exit(void)
+{
+#ifndef HIDAPI_USE_DDK
+ if (lib_handle)
+ FreeLibrary(lib_handle);
+ lib_handle = NULL;
+ initialized = FALSE;
+#endif
+ return 0;
+}
+
+struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+ BOOL res;
+ struct hid_device_info *root = NULL; /* return object */
+ struct hid_device_info *cur_dev = NULL;
+
+ /* Windows objects for interacting with the driver. */
+ GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };
+ SP_DEVINFO_DATA devinfo_data;
+ SP_DEVICE_INTERFACE_DATA device_interface_data;
+ SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
+ HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
+ int device_index = 0;
+ int i;
+
+ if (hid_init() < 0)
+ return NULL;
+
+ /* Initialize the Windows objects. */
+ memset(&devinfo_data, 0x0, sizeof(devinfo_data));
+ devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
+ device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+
+ /* Get information for all the devices belonging to the HID class. */
+ device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+
+ /* Iterate over each device in the HID class, looking for the right one. */
+
+ for (;;) {
+ HANDLE write_handle = INVALID_HANDLE_VALUE;
+ DWORD required_size = 0;
+ HIDD_ATTRIBUTES attrib;
+
+ res = SetupDiEnumDeviceInterfaces(device_info_set,
+ NULL,
+ &InterfaceClassGuid,
+ device_index,
+ &device_interface_data);
+
+ if (!res) {
+ /* A return of FALSE from this function means that
+ there are no more devices. */
+ break;
+ }
+
+ /* Call with 0-sized detail size, and let the function
+ tell us how long the detail struct needs to be. The
+ size is put in &required_size. */
+ res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
+ &device_interface_data,
+ NULL,
+ 0,
+ &required_size,
+ NULL);
+
+ /* Allocate a long enough structure for device_interface_detail_data. */
+ device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
+ device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
+
+ /* Get the detailed data for this device. The detail data gives us
+ the device path for this device, which is then passed into
+ CreateFile() to get a handle to the device. */
+ res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
+ &device_interface_data,
+ device_interface_detail_data,
+ required_size,
+ NULL,
+ NULL);
+
+ if (!res) {
+ /* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
+ Continue to the next device. */
+ goto cont;
+ }
+
+ /* Make sure this device is of Setup Class "HIDClass" and has a
+ driver bound to it. */
+ for (i = 0; ; i++) {
+ char driver_name[256];
+
+ /* Populate devinfo_data. This function will return failure
+ when there are no more interfaces left. */
+ res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
+ if (!res)
+ goto cont;
+
+ res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
+ SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
+ if (!res)
+ goto cont;
+
+ if ((strcmp(driver_name, "HIDClass") == 0) ||
+ (strcmp(driver_name, "Mouse") == 0) ||
+ (strcmp(driver_name, "Keyboard") == 0)) {
+ /* See if there's a driver bound. */
+ res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
+ SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
+ if (res)
+ break;
+ }
+ }
+
+ //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
+
+ /* Open a handle to the device */
+ write_handle = open_device(device_interface_detail_data->DevicePath, FALSE);
+
+ /* Check validity of write_handle. */
+ if (write_handle == INVALID_HANDLE_VALUE) {
+ /* Unable to open the device. */
+ //register_error(dev, "CreateFile");
+ goto cont_close;
+ }
+
+
+ /* Get the Vendor ID and Product ID for this device. */
+ attrib.Size = sizeof(HIDD_ATTRIBUTES);
+ HidD_GetAttributes(write_handle, &attrib);
+ //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
+
+ /* Check the VID/PID to see if we should add this
+ device to the enumeration list. */
+ if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
+ (product_id == 0x0 || attrib.ProductID == product_id)) {
+
+ #define WSTR_LEN 512
+ const char *str;
+ struct hid_device_info *tmp;
+ PHIDP_PREPARSED_DATA pp_data = NULL;
+ HIDP_CAPS caps;
+ BOOLEAN res;
+ NTSTATUS nt_res;
+ wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
+ size_t len;
+
+ /* VID/PID match. Create the record. */
+ tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
+ if (cur_dev) {
+ cur_dev->next = tmp;
+ }
+ else {
+ root = tmp;
+ }
+ cur_dev = tmp;
+
+ /* Get the Usage Page and Usage for this device. */
+ res = HidD_GetPreparsedData(write_handle, &pp_data);
+ if (res) {
+ nt_res = HidP_GetCaps(pp_data, &caps);
+ if (nt_res == HIDP_STATUS_SUCCESS) {
+ cur_dev->usage_page = caps.UsagePage;
+ cur_dev->usage = caps.Usage;
+ }
+
+ HidD_FreePreparsedData(pp_data);
+ }
+
+ /* Fill out the record */
+ cur_dev->next = NULL;
+ str = device_interface_detail_data->DevicePath;
+ if (str) {
+ len = strlen(str);
+ cur_dev->path = (char*) calloc(len+1, sizeof(char));
+ strncpy(cur_dev->path, str, len+1);
+ cur_dev->path[len] = '\0';
+ }
+ else
+ cur_dev->path = NULL;
+
+ /* Serial Number */
+ wstr[0]= 0x0000;
+ res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN-1] = 0x0000;
+ if (res) {
+ cur_dev->serial_number = _wcsdup(wstr);
+ }
+
+ /* Manufacturer String */
+ wstr[0]= 0x0000;
+ res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN-1] = 0x0000;
+ if (res) {
+ cur_dev->manufacturer_string = _wcsdup(wstr);
+ }
+
+ /* Product String */
+ wstr[0]= 0x0000;
+ res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN-1] = 0x0000;
+ if (res) {
+ cur_dev->product_string = _wcsdup(wstr);
+ }
+
+ /* VID/PID */
+ cur_dev->vendor_id = attrib.VendorID;
+ cur_dev->product_id = attrib.ProductID;
+
+ /* Release Number */
+ cur_dev->release_number = attrib.VersionNumber;
+
+ /* Interface Number. It can sometimes be parsed out of the path
+ on Windows if a device has multiple interfaces. See
+ http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or
+ search for "Hardware IDs for HID Devices" at MSDN. If it's not
+ in the path, it's set to -1. */
+ cur_dev->interface_number = -1;
+ if (cur_dev->path) {
+ char *interface_component = strstr(cur_dev->path, "&mi_");
+ if (interface_component) {
+ char *hex_str = interface_component + 4;
+ char *endptr = NULL;
+ cur_dev->interface_number = strtol(hex_str, &endptr, 16);
+ if (endptr == hex_str) {
+ /* The parsing failed. Set interface_number to -1. */
+ cur_dev->interface_number = -1;
+ }
+ }
+ }
+ }
+
+cont_close:
+ CloseHandle(write_handle);
+cont:
+ /* We no longer need the detail data. It can be freed */
+ free(device_interface_detail_data);
+
+ device_index++;
+
+ }
+
+ /* Close the device information handle. */
+ SetupDiDestroyDeviceInfoList(device_info_set);
+
+ return root;
+
+}
+
+void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
+{
+ /* TODO: Merge this with the Linux version. This function is platform-independent. */
+ struct hid_device_info *d = devs;
+ while (d) {
+ struct hid_device_info *next = d->next;
+ free(d->path);
+ free(d->serial_number);
+ free(d->manufacturer_string);
+ free(d->product_string);
+ free(d);
+ d = next;
+ }
+}
+
+
+HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
+{
+ /* TODO: Merge this functions with the Linux version. This function should be platform independent. */
+ struct hid_device_info *devs, *cur_dev;
+ const char *path_to_open = NULL;
+ hid_device *handle = NULL;
+
+ devs = hid_enumerate(vendor_id, product_id);
+ cur_dev = devs;
+ while (cur_dev) {
+ if (cur_dev->vendor_id == vendor_id &&
+ cur_dev->product_id == product_id) {
+ if (serial_number) {
+ if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ }
+ else {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ }
+ cur_dev = cur_dev->next;
+ }
+
+ if (path_to_open) {
+ /* Open the device */
+ handle = hid_open_path(path_to_open);
+ }
+
+ hid_free_enumeration(devs);
+
+ return handle;
+}
+
+HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
+{
+ hid_device *dev;
+ HIDP_CAPS caps;
+ PHIDP_PREPARSED_DATA pp_data = NULL;
+ BOOLEAN res;
+ NTSTATUS nt_res;
+
+ if (hid_init() < 0) {
+ return NULL;
+ }
+
+ dev = new_hid_device();
+
+ /* Open a handle to the device */
+ dev->device_handle = open_device(path, TRUE);
+
+ /* Check validity of write_handle. */
+ if (dev->device_handle == INVALID_HANDLE_VALUE) {
+ /* System devices, such as keyboards and mice, cannot be opened in
+ read-write mode, because the system takes exclusive control over
+ them. This is to prevent keyloggers. However, feature reports
+ can still be sent and received. Retry opening the device, but
+ without read/write access. */
+ dev->device_handle = open_device(path, FALSE);
+
+ /* Check the validity of the limited device_handle. */
+ if (dev->device_handle == INVALID_HANDLE_VALUE) {
+ /* Unable to open the device, even without read-write mode. */
+ register_error(dev, "CreateFile");
+ goto err;
+ }
+ }
+
+ /* Set the Input Report buffer size to 64 reports. */
+ res = HidD_SetNumInputBuffers(dev->device_handle, 64);
+ if (!res) {
+ register_error(dev, "HidD_SetNumInputBuffers");
+ goto err;
+ }
+
+ /* Get the Input Report length for the device. */
+ res = HidD_GetPreparsedData(dev->device_handle, &pp_data);
+ if (!res) {
+ register_error(dev, "HidD_GetPreparsedData");
+ goto err;
+ }
+ nt_res = HidP_GetCaps(pp_data, &caps);
+ if (nt_res != HIDP_STATUS_SUCCESS) {
+ register_error(dev, "HidP_GetCaps");
+ goto err_pp_data;
+ }
+ dev->output_report_length = caps.OutputReportByteLength;
+ dev->input_report_length = caps.InputReportByteLength;
+ HidD_FreePreparsedData(pp_data);
+
+ dev->read_buf = (char*) malloc(dev->input_report_length);
+
+ return dev;
+
+err_pp_data:
+ HidD_FreePreparsedData(pp_data);
+err:
+ free_hid_device(dev);
+ return NULL;
+}
+
+int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
+{
+ DWORD bytes_written;
+ BOOL res;
+
+ OVERLAPPED ol;
+ unsigned char *buf;
+ memset(&ol, 0, sizeof(ol));
+
+ /* Make sure the right number of bytes are passed to WriteFile. Windows
+ expects the number of bytes which are in the _longest_ report (plus
+ one for the report number) bytes even if the data is a report
+ which is shorter than that. Windows gives us this value in
+ caps.OutputReportByteLength. If a user passes in fewer bytes than this,
+ create a temporary buffer which is the proper size. */
+ if (length >= dev->output_report_length) {
+ /* The user passed the right number of bytes. Use the buffer as-is. */
+ buf = (unsigned char *) data;
+ } else {
+ /* Create a temporary buffer and copy the user's data
+ into it, padding the rest with zeros. */
+ buf = (unsigned char *) malloc(dev->output_report_length);
+ memcpy(buf, data, length);
+ memset(buf + length, 0, dev->output_report_length - length);
+ length = dev->output_report_length;
+ }
+
+ res = WriteFile(dev->device_handle, buf, length, NULL, &ol);
+
+ if (!res) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ /* WriteFile() failed. Return error. */
+ register_error(dev, "WriteFile");
+ bytes_written = -1;
+ goto end_of_function;
+ }
+ }
+
+ /* Wait here until the write is done. This makes
+ hid_write() synchronous. */
+ res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/);
+ if (!res) {
+ /* The Write operation failed. */
+ register_error(dev, "WriteFile");
+ bytes_written = -1;
+ goto end_of_function;
+ }
+
+end_of_function:
+ if (buf != data)
+ free(buf);
+
+ return bytes_written;
+}
+
+
+int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
+{
+ DWORD bytes_read = 0;
+ size_t copy_len = 0;
+ BOOL res;
+
+ /* Copy the handle for convenience. */
+ HANDLE ev = dev->ol.hEvent;
+
+ if (!dev->read_pending) {
+ /* Start an Overlapped I/O read. */
+ dev->read_pending = TRUE;
+ memset(dev->read_buf, 0, dev->input_report_length);
+ ResetEvent(ev);
+ res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol);
+
+ if (!res) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ /* ReadFile() has failed.
+ Clean up and return error. */
+ CancelIo(dev->device_handle);
+ dev->read_pending = FALSE;
+ goto end_of_function;
+ }
+ }
+ }
+
+ if (milliseconds >= 0) {
+ /* See if there is any data yet. */
+ res = WaitForSingleObject(ev, milliseconds);
+ if (res != WAIT_OBJECT_0) {
+ /* There was no data this time. Return zero bytes available,
+ but leave the Overlapped I/O running. */
+ return 0;
+ }
+ }
+
+ /* Either WaitForSingleObject() told us that ReadFile has completed, or
+ we are in non-blocking mode. Get the number of bytes read. The actual
+ data has been copied to the data[] array which was passed to ReadFile(). */
+ res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
+
+ /* Set pending back to false, even if GetOverlappedResult() returned error. */
+ dev->read_pending = FALSE;
+
+ if (res && bytes_read > 0) {
+ if (dev->read_buf[0] == 0x0) {
+ /* If report numbers aren't being used, but Windows sticks a report
+ number (0x0) on the beginning of the report anyway. To make this
+ work like the other platforms, and to make it work more like the
+ HID spec, we'll skip over this byte. */
+ bytes_read--;
+ copy_len = length > bytes_read ? bytes_read : length;
+ memcpy(data, dev->read_buf+1, copy_len);
+ }
+ else {
+ /* Copy the whole buffer, report number and all. */
+ copy_len = length > bytes_read ? bytes_read : length;
+ memcpy(data, dev->read_buf, copy_len);
+ }
+ }
+
+end_of_function:
+ if (!res) {
+ register_error(dev, "GetOverlappedResult");
+ return -1;
+ }
+
+ return copy_len;
+}
+
+int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
+{
+ return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
+}
+
+int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
+{
+ dev->blocking = !nonblock;
+ return 0; /* Success */
+}
+
+int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
+{
+ BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, length);
+ if (!res) {
+ register_error(dev, "HidD_SetFeature");
+ return -1;
+ }
+
+ return length;
+}
+
+
+int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+ BOOL res;
+#if 0
+ res = HidD_GetFeature(dev->device_handle, data, length);
+ if (!res) {
+ register_error(dev, "HidD_GetFeature");
+ return -1;
+ }
+ return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */
+#else
+ DWORD bytes_returned;
+
+ OVERLAPPED ol;
+ memset(&ol, 0, sizeof(ol));
+
+ res = DeviceIoControl(dev->device_handle,
+ IOCTL_HID_GET_FEATURE,
+ data, length,
+ data, length,
+ &bytes_returned, &ol);
+
+ if (!res) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ /* DeviceIoControl() failed. Return error. */
+ register_error(dev, "Send Feature Report DeviceIoControl");
+ return -1;
+ }
+ }
+
+ /* Wait here until the write is done. This makes
+ hid_get_feature_report() synchronous. */
+ res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
+ if (!res) {
+ /* The operation failed. */
+ register_error(dev, "Send Feature Report GetOverLappedResult");
+ return -1;
+ }
+
+ /* bytes_returned does not include the first byte which contains the
+ report ID. The data buffer actually contains one more byte than
+ bytes_returned. */
+ bytes_returned++;
+
+ return bytes_returned;
+#endif
+}
+
+
+int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length)
+{
+ BOOL res;
+#if 0
+ res = HidD_GetInputReport(dev->device_handle, data, length);
+ if (!res) {
+ register_error(dev, "HidD_GetInputReport");
+ return -1;
+ }
+ return length;
+#else
+ DWORD bytes_returned;
+
+ OVERLAPPED ol;
+ memset(&ol, 0, sizeof(ol));
+
+ res = DeviceIoControl(dev->device_handle,
+ IOCTL_HID_GET_INPUT_REPORT,
+ data, length,
+ data, length,
+ &bytes_returned, &ol);
+
+ if (!res) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ /* DeviceIoControl() failed. Return error. */
+ register_error(dev, "Send Input Report DeviceIoControl");
+ return -1;
+ }
+ }
+
+ /* Wait here until the write is done. This makes
+ hid_get_feature_report() synchronous. */
+ res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
+ if (!res) {
+ /* The operation failed. */
+ register_error(dev, "Send Input Report GetOverLappedResult");
+ return -1;
+ }
+
+ /* bytes_returned does not include the first byte which contains the
+ report ID. The data buffer actually contains one more byte than
+ bytes_returned. */
+ bytes_returned++;
+
+ return bytes_returned;
+#endif
+}
+
+void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
+{
+ if (!dev)
+ return;
+ CancelIo(dev->device_handle);
+ free_hid_device(dev);
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetManufacturerString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
+ if (!res) {
+ register_error(dev, "HidD_GetManufacturerString");
+ return -1;
+ }
+
+ return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetProductString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
+ if (!res) {
+ register_error(dev, "HidD_GetProductString");
+ return -1;
+ }
+
+ return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetSerialNumberString(dev->device_handle, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
+ if (!res) {
+ register_error(dev, "HidD_GetSerialNumberString");
+ return -1;
+ }
+
+ return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetIndexedString(dev->device_handle, string_index, string, sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS));
+ if (!res) {
+ register_error(dev, "HidD_GetIndexedString");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
+{
+ if (dev) {
+ if (dev->last_error_str == NULL)
+ return L"Success";
+ return (wchar_t*)dev->last_error_str;
+ }
+
+ // Global error messages are not (yet) implemented on Windows.
+ return L"hid_error for global errors is not implemented yet";
+}
+
+
+/*#define PICPGM*/
+/*#define S11*/
+#define P32
+#ifdef S11
+ unsigned short VendorID = 0xa0a0;
+ unsigned short ProductID = 0x0001;
+#endif
+
+#ifdef P32
+ unsigned short VendorID = 0x04d8;
+ unsigned short ProductID = 0x3f;
+#endif
+
+
+#ifdef PICPGM
+ unsigned short VendorID = 0x04d8;
+ unsigned short ProductID = 0x0033;
+#endif
+
+
+#if 0
+int __cdecl main(int argc, char* argv[])
+{
+ int res;
+ unsigned char buf[65];
+
+ UNREFERENCED_PARAMETER(argc);
+ UNREFERENCED_PARAMETER(argv);
+
+ /* Set up the command buffer. */
+ memset(buf,0x00,sizeof(buf));
+ buf[0] = 0;
+ buf[1] = 0x81;
+
+
+ /* Open the device. */
+ int handle = open(VendorID, ProductID, L"12345");
+ if (handle < 0)
+ printf("unable to open device\n");
+
+
+ /* Toggle LED (cmd 0x80) */
+ buf[1] = 0x80;
+ res = write(handle, buf, 65);
+ if (res < 0)
+ printf("Unable to write()\n");
+
+ /* Request state (cmd 0x81) */
+ buf[1] = 0x81;
+ write(handle, buf, 65);
+ if (res < 0)
+ printf("Unable to write() (2)\n");
+
+ /* Read requested state */
+ read(handle, buf, 65);
+ if (res < 0)
+ printf("Unable to read()\n");
+
+ /* Print out the returned buffer. */
+ for (int i = 0; i < 4; i++)
+ printf("buf[%d]: %d\n", i, buf[i]);
+
+ return 0;
+}
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/src/platforms/pc/hidapi.h b/src/platforms/pc/hidapi.h
new file mode 100644
index 00000000..ce8892e2
--- /dev/null
+++ b/src/platforms/pc/hidapi.h
@@ -0,0 +1,445 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ https://github.com/libusb/hidapi .
+********************************************************/
+
+/** @file
+ * @defgroup API hidapi API
+ */
+
+#ifndef HIDAPI_H__
+#define HIDAPI_H__
+
+#include
+
+#ifdef _WIN32
+ #define HID_API_EXPORT __declspec(dllexport)
+ #define HID_API_CALL
+#else
+ #define HID_API_EXPORT /**< API export macro */
+ #define HID_API_CALL /**< API call macro */
+#endif
+
+#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ struct hid_device_;
+ typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
+
+ /** hidapi info structure */
+ struct hid_device_info {
+ /** Platform-specific device path */
+ char *path;
+ /** Device Vendor ID */
+ unsigned short vendor_id;
+ /** Device Product ID */
+ unsigned short product_id;
+ /** Serial Number */
+ wchar_t *serial_number;
+ /** Device Release Number in binary-coded decimal,
+ also known as Device Version Number */
+ unsigned short release_number;
+ /** Manufacturer String */
+ wchar_t *manufacturer_string;
+ /** Product string */
+ wchar_t *product_string;
+ /** Usage Page for this Device/Interface
+ (Windows/Mac only). */
+ unsigned short usage_page;
+ /** Usage for this Device/Interface
+ (Windows/Mac only).*/
+ unsigned short usage;
+ /** The USB interface which this logical device
+ represents.
+
+ * Valid on both Linux implementations in all cases.
+ * Valid on the Windows implementation only if the device
+ contains more than one interface.
+ * Valid on the Mac implementation if and only if the device
+ is a USB HID device. */
+ int interface_number;
+
+ /** Pointer to the next device */
+ struct hid_device_info *next;
+ };
+
+
+ /** @brief Initialize the HIDAPI library.
+
+ This function initializes the HIDAPI library. Calling it is not
+ strictly necessary, as it will be called automatically by
+ hid_enumerate() and any of the hid_open_*() functions if it is
+ needed. This function should be called at the beginning of
+ execution however, if there is a chance of HIDAPI handles
+ being opened by different threads simultaneously.
+
+ @ingroup API
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_init(void);
+
+ /** @brief Finalize the HIDAPI library.
+
+ This function frees all of the static data associated with
+ HIDAPI. It should be called at the end of execution to avoid
+ memory leaks.
+
+ @ingroup API
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_exit(void);
+
+ /** @brief Enumerate the HID Devices.
+
+ This function returns a linked list of all the HID devices
+ attached to the system which match vendor_id and product_id.
+ If @p vendor_id is set to 0 then any vendor matches.
+ If @p product_id is set to 0 then any product matches.
+ If @p vendor_id and @p product_id are both set to 0, then
+ all HID devices will be returned.
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the types of device
+ to open.
+ @param product_id The Product ID (PID) of the types of
+ device to open.
+
+ @returns
+ This function returns a pointer to a linked list of type
+ struct #hid_device_info, containing information about the HID devices
+ attached to the system, or NULL in the case of failure. Free
+ this linked list by calling hid_free_enumeration().
+ */
+ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
+
+ /** @brief Free an enumeration Linked List
+
+ This function frees a linked list created by hid_enumerate().
+
+ @ingroup API
+ @param devs Pointer to a list of struct_device returned from
+ hid_enumerate().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
+
+ /** @brief Open a HID device using a Vendor ID (VID), Product ID
+ (PID) and optionally a serial number.
+
+ If @p serial_number is NULL, the first device with the
+ specified VID and PID is opened.
+
+ This function sets the return value of hid_error().
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the device to open.
+ @param product_id The Product ID (PID) of the device to open.
+ @param serial_number The Serial Number of the device to open
+ (Optionally NULL).
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
+
+ /** @brief Open a HID device by its path name.
+
+ The path name be determined by calling hid_enumerate(), or a
+ platform-specific path name can be used (eg: /dev/hidraw0 on
+ Linux).
+
+ This function sets the return value of hid_error().
+
+ @ingroup API
+ @param path The path name of the device to open
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
+
+ /** @brief Write an Output report to a HID device.
+
+ The first byte of @p data[] must contain the Report ID. For
+ devices which only support a single report, this must be set
+ to 0x0. The remaining bytes contain the report data. Since
+ the Report ID is mandatory, calls to hid_write() will always
+ contain one more byte than the report contains. For example,
+ if a hid report is 16 bytes long, 17 bytes must be passed to
+ hid_write(), the Report ID (or 0x0, for devices with a
+ single report), followed by the report data (16 bytes). In
+ this example, the length passed in would be 17.
+
+ hid_write() will send the data on the first OUT endpoint, if
+ one exists. If it does not, it will send the data through
+ the Control Endpoint (Endpoint 0).
+
+ This function sets the return value of hid_error().
+
+ @ingroup API
+ @param dev A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length);
+
+ /** @brief Read an Input report from a HID device with timeout.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ This function sets the return value of hid_error().
+
+ @ingroup API
+ @param dev A device handle returned from hid_open().
+ @param data A buffer to put the read data into.
+ @param length The number of bytes to read. For devices with
+ multiple reports, make sure to read an extra byte for
+ the report number.
+ @param milliseconds timeout in milliseconds or -1 for blocking wait.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error. If no packet was available to be read within
+ the timeout period, this function returns 0.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
+
+ /** @brief Read an Input report from a HID device.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ This function sets the return value of hid_error().
+
+ @ingroup API
+ @param dev A device handle returned from hid_open().
+ @param data A buffer to put the read data into.
+ @param length The number of bytes to read. For devices with
+ multiple reports, make sure to read an extra byte for
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error. If no packet was available to be read and
+ the handle is in non-blocking mode, this function returns 0.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length);
+
+ /** @brief Set the device handle to be non-blocking.
+
+ In non-blocking mode calls to hid_read() will return
+ immediately with a value of 0 if there is no data to be
+ read. In blocking mode, hid_read() will wait (block) until
+ there is data to read before returning.
+
+ Nonblocking can be turned on and off at any time.
+
+ @ingroup API
+ @param dev A device handle returned from hid_open().
+ @param nonblock enable or not the nonblocking reads
+ - 1 to enable nonblocking
+ - 0 to disable nonblocking.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock);
+
+ /** @brief Send a Feature report to the device.
+
+ Feature reports are sent over the Control endpoint as a
+ Set_Report transfer. The first byte of @p data[] must
+ contain the Report ID. For devices which only support a
+ single report, this must be set to 0x0. The remaining bytes
+ contain the report data. Since the Report ID is mandatory,
+ calls to hid_send_feature_report() will always contain one
+ more byte than the report contains. For example, if a hid
+ report is 16 bytes long, 17 bytes must be passed to
+ hid_send_feature_report(): the Report ID (or 0x0, for
+ devices which do not use numbered reports), followed by the
+ report data (16 bytes). In this example, the length passed
+ in would be 17.
+
+ This function sets the return value of hid_error().
+
+ @ingroup API
+ @param dev A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send, including
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length);
+
+ /** @brief Get a feature report from a HID device.
+
+ Set the first byte of @p data[] to the Report ID of the
+ report to be read. Make sure to allow space for this
+ extra byte in @p data[]. Upon return, the first byte will
+ still contain the Report ID, and the report data will
+ start in data[1].
+
+ This function sets the return value of hid_error().
+
+ @ingroup API
+ @param dev A device handle returned from hid_open().
+ @param data A buffer to put the read data into, including
+ the Report ID. Set the first byte of @p data[] to the
+ Report ID of the report to be read, or set it to zero
+ if your device does not use numbered reports.
+ @param length The number of bytes to read, including an
+ extra byte for the report ID. The buffer can be longer
+ than the actual report.
+
+ @returns
+ This function returns the number of bytes read plus
+ one for the report ID (which is still in the first
+ byte), or -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length);
+
+ /** @brief Get a input report from a HID device.
+
+ Set the first byte of @p data[] to the Report ID of the
+ report to be read. Make sure to allow space for this
+ extra byte in @p data[]. Upon return, the first byte will
+ still contain the Report ID, and the report data will
+ start in data[1].
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into, including
+ the Report ID. Set the first byte of @p data[] to the
+ Report ID of the report to be read, or set it to zero
+ if your device does not use numbered reports.
+ @param length The number of bytes to read, including an
+ extra byte for the report ID. The buffer can be longer
+ than the actual report.
+
+ @returns
+ This function returns the number of bytes read plus
+ one for the report ID (which is still in the first
+ byte), or -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_get_input_report(hid_device *dev, unsigned char *data, size_t length);
+
+ /** @brief Close a HID device.
+
+ This function sets the return value of hid_error().
+
+ @ingroup API
+ @param dev A device handle returned from hid_open().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev);
+
+ /** @brief Get The Manufacturer String from a HID device.
+
+ @ingroup API
+ @param dev A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Product String from a HID device.
+
+ @ingroup API
+ @param dev A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Serial Number String from a HID device.
+
+ @ingroup API
+ @param dev A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string from a HID device, based on its string index.
+
+ @ingroup API
+ @param dev A device handle returned from hid_open().
+ @param string_index The index of the string to get.
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string describing the last error which occurred.
+
+ Whether a function sets the last error is noted in its
+ documentation. These functions will reset the last error
+ to NULL before their execution.
+
+ Strings returned from hid_error() must not be freed by the user!
+
+ This function is thread-safe, and error messages are thread-local.
+
+ @ingroup API
+ @param dev A device handle returned from hid_open(),
+ or NULL to get the last non-device-specific error
+ (e.g. for errors in hid_open() itself).
+
+ @returns
+ This function returns a string containing the last error
+ which occurred or NULL if none has occurred.
+ */
+ HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *dev);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/platforms/pc/serial_unix.c b/src/platforms/pc/serial_unix.c
index 063ac850..aa7d30d3 100644
--- a/src/platforms/pc/serial_unix.c
+++ b/src/platforms/pc/serial_unix.c
@@ -67,6 +67,33 @@ static int set_interface_attribs(void)
}
return 0;
}
+
+#ifdef __APPLE__
+int serial_open(BMP_CL_OPTIONS_t *cl_opts, char *serial)
+{
+ char name[4096];
+ if (!cl_opts->opt_device) {
+ /* Try to find some BMP if0*/
+ if (!serial) {
+ DEBUG_WARN("No serial device found\n");
+ return -1;
+ } else {
+ sprintf(name, "/dev/tty.usbmodem%s1", serial);
+ }
+ } else {
+ strncpy(name, cl_opts->opt_device, sizeof(name) - 1);
+ }
+ fd = open(name, O_RDWR | O_SYNC | O_NOCTTY);
+ if (fd < 0) {
+ DEBUG_WARN("Couldn't open serial port %s\n", name);
+ return -1;
+ }
+ /* BMP only offers an USB-Serial connection with no real serial
+ * line in between. No need for baudrate or parity.!
+ */
+ return set_interface_attribs();
+}
+#else
#define BMP_IDSTRING "usb-Black_Sphere_Technologies_Black_Magic_Probe"
#define DEVICE_BY_ID "/dev/serial/by-id/"
int serial_open(BMP_CL_OPTIONS_t *cl_opts, char *serial)
@@ -130,6 +157,7 @@ int serial_open(BMP_CL_OPTIONS_t *cl_opts, char *serial)
*/
return set_interface_attribs();
}
+#endif
void serial_close(void)
{
diff --git a/src/platforms/pc/serial_win.c b/src/platforms/pc/serial_win.c
index 2424d46d..42904281 100644
--- a/src/platforms/pc/serial_win.c
+++ b/src/platforms/pc/serial_win.c
@@ -23,22 +23,64 @@
#include "remote.h"
#include "cl_utils.h"
-HANDLE hComm;
+static HANDLE hComm;
+
+static char *find_bmp_by_serial(const char *serial)
+{
+ char regpath[258];
+ /* First find the containers of the BMP comports */
+ sprintf(regpath,
+ "SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%04X&PID_%04X\\%s",
+ VENDOR_ID_BMP, PRODUCT_ID_BMP, serial);
+ HKEY hkeySection;
+ LSTATUS res;
+ res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &hkeySection);
+ if (res != ERROR_SUCCESS)
+ return NULL;
+ BYTE prefix[128];
+ DWORD maxlen = sizeof(prefix);
+ res = RegQueryValueEx(hkeySection, "ParentIdPrefix", NULL, NULL, prefix,
+ &maxlen);
+ RegCloseKey(hkeySection);
+ if (res != ERROR_SUCCESS)
+ return NULL;
+ printf("prefix %s\n", prefix);
+ sprintf(regpath,
+ "SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%04X&PID_%04X&MI_00\\%s"
+ "&0000\\Device Parameters",
+ VENDOR_ID_BMP, PRODUCT_ID_BMP, prefix);
+ printf("%s\n", regpath);
+ res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &hkeySection);
+ if (res != ERROR_SUCCESS) {
+ printf("Failuere\n");
+ return NULL;
+ }
+ BYTE port[128];
+ maxlen = sizeof(port);
+ res = RegQueryValueEx(hkeySection, "PortName", NULL, NULL, port, &maxlen);
+ RegCloseKey(hkeySection);
+ if (res != ERROR_SUCCESS)
+ return NULL;
+ printf("Portname %s\n", port);
+ return strdup((char*)port);
+}
int serial_open(BMP_CL_OPTIONS_t *cl_opts, char * serial)
{
(void) serial; /* FIXME: Does Windows allow open with USB serial no? */
+ char device[256];
+ if (!cl_opts->opt_device)
+ cl_opts->opt_device = find_bmp_by_serial(serial);
if (!cl_opts->opt_device) {
- DEBUG_WARN("Specify the serial device to use!\n");
+ DEBUG_WARN("Unexpected problems finding the device!\n");
return -1;
}
- char device[256];
- if (strstr(device, "\\\\.\\")) {
- strncpy(device, cl_opts->opt_device, sizeof(cl_opts->opt_device) - 1);
+ if (strstr(cl_opts->opt_device, "\\\\.\\")) {
+ strncpy(device, cl_opts->opt_device, sizeof(device) - 1);
} else {
strcpy(device, "\\\\.\\");
strncat(device, cl_opts->opt_device,
- sizeof(cl_opts->opt_device) - strlen(cl_opts->opt_device) - 1);
+ sizeof(device) - strlen(device) - 1);
}
hComm = CreateFile(device, //port name
GENERIC_READ | GENERIC_WRITE, //Read/Write
@@ -59,6 +101,7 @@ int serial_open(BMP_CL_OPTIONS_t *cl_opts, char * serial)
return -1;
}
dcbSerialParams.ByteSize = 8;
+ dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE;
if (!SetCommState(hComm, &dcbSerialParams)) {
DEBUG_WARN("SetCommState failed %ld\n", GetLastError());
return -1;
diff --git a/src/platforms/stlink/platform.c b/src/platforms/stlink/platform.c
index 64216e90..54b80461 100644
--- a/src/platforms/stlink/platform.c
+++ b/src/platforms/stlink/platform.c
@@ -34,8 +34,6 @@
#include
#include
-uint8_t running_status;
-
uint16_t led_idle_run;
uint16_t srst_pin;
static uint32_t rev;
diff --git a/src/remote.c b/src/remote.c
index 89887ebf..83418920 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -309,6 +309,9 @@ void remotePacketProcessHL(uint8_t i, char *packet)
remote_ap.apsel = remotehston(2, packet);
remote_ap.dp = &remote_dp;
switch (index) {
+ case REMOTE_HL_CHECK:
+ _respond(REMOTE_RESP_OK, 0);
+ break;
case REMOTE_DP_READ:
packet += 2;
uint16_t addr16 = remotehston(4, packet);
diff --git a/src/remote.h b/src/remote.h
index dfb8a6d8..550f7ebe 100644
--- a/src/remote.h
+++ b/src/remote.h
@@ -84,6 +84,7 @@
#define REMOTE_RESP_NOTSUP 'N'
/* High level protocol elements */
+#define REMOTE_HL_CHECK 'C'
#define REMOTE_HL_PACKET 'H'
#define REMOTE_DP_READ 'd'
#define REMOTE_LOW_ACCESS 'L'
@@ -142,6 +143,7 @@
#define HEX_U32(x) '%', '0', '8', 'x'
#define CHR(x) '%', 'c'
+#define REMOTE_HL_CHECK_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_HL_CHECK, REMOTE_EOM, 0 }
#define REMOTE_MEM_READ_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_MEM_READ, \
HEX_U32(address), HEX_U32(count), REMOTE_EOM, 0 }
#define REMOTE_DP_READ_STR (char []){ REMOTE_SOM, REMOTE_HL_PACKET, REMOTE_DP_READ, \
diff --git a/src/target/adiv5.c b/src/target/adiv5.c
index 63e3c75d..638c1e54 100644
--- a/src/target/adiv5.c
+++ b/src/target/adiv5.c
@@ -106,6 +106,13 @@ static const char * const cidc_debug_strings[] =
#define PIDR_PN_MASK 0x000000FFFULL /* Part number bits. */
#define PIDR_ARM_BITS 0x4000BB000ULL /* These make up the ARM JEP-106 code. */
+#define DEVTYPE_OFFSET 0xFCC /* CoreSight Device Type Register */
+#define DEVARCH_OFFSET 0xFBC /* CoreSight Device Architecture Register */
+
+#define DEVTYPE_MASK 0x000000FF
+#define DEVARCH_PRESENT (1u << 20)
+#define DEVARCH_ARCHID_MASK 0x0000FFFF
+
enum arm_arch {
aa_nosupport,
aa_cortexm,
@@ -152,9 +159,20 @@ enum arm_arch {
*
* We left out some of the Part numbers included in OpenOCD, we only include
* the ones that have ARM as the designer.
+ *
+ * To properly identify ADIv6 CoreSight components, two additional fields,
+ * DEVTYPE and ARCHID are read.
+ * The dev_type and arch_id values in the table below were found in the
+ * corresponding logic in pyOCD:
+ * https://github.com/mbedmicro/pyOCD/blob/master/pyocd/coresight/component_ids.py
+ *
+ * Additional reference on the DEVTYPE and DEVARCH registers can be found in the
+ * ARM CoreSight Architecture Specification v3.0, sections B2.3.4 and B2.3.8.
*/
static const struct {
uint16_t part_number;
+ uint8_t dev_type;
+ uint16_t arch_id;
enum arm_arch arch;
enum cid_class cidc;
#ifdef ENABLE_DEBUG
@@ -162,59 +180,73 @@ static const struct {
const char *full;
#endif
} pidr_pn_bits[] = {
- {0x000, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M3 SCS", "(System Control Space)")},
- {0x001, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 ITM", "(Instrumentation Trace Module)")},
- {0x002, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 DWT", "(Data Watchpoint and Trace)")},
- {0x003, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 FBP", "(Flash Patch and Breakpoint)")},
- {0x008, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M0 SCS", "(System Control Space)")},
- {0x00a, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M0 DWT", "(Data Watchpoint and Trace)")},
- {0x00b, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M0 BPU", "(Breakpoint Unit)")},
- {0x00c, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M4 SCS", "(System Control Space)")},
- {0x00d, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM11", "(Embedded Trace)")},
- {0x00e, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 FBP", "(Flash Patch and Breakpoint)")},
- {0x101, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("System TSGEN", "(Time Stamp Generator)")},
- {0x490, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 GIC", "(Generic Interrupt Controller)")},
- {0x4c7, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 PPB", "(Private Peripheral Bus ROM Table)")},
- {0x906, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight CTI", "(Cross Trigger)")},
- {0x907, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETB", "(Trace Buffer)")},
- {0x908, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight CSTF", "(Trace Funnel)")},
- {0x910, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM9", "(Embedded Trace)")},
- {0x912, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TPIU", "(Trace Port Interface Unit)")},
- {0x913, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ITM", "(Instrumentation Trace Macrocell)")},
- {0x914, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight SWO", "(Single Wire Output)")},
- {0x917, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight HTM", "(AHB Trace Macrocell)")},
- {0x920, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM11", "(Embedded Trace)")},
- {0x921, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A8 ETM", "(Embedded Trace)")},
- {0x922, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A8 CTI", "(Cross Trigger)")},
- {0x923, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 TPIU", "(Trace Port Interface Unit)")},
- {0x924, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 ETM", "(Embedded Trace)")},
- {0x925, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M4 ETM", "(Embedded Trace)")},
- {0x930, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-R4 ETM", "(Embedded Trace)")},
- {0x932, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight MTB-M0+", "(Simple Execution Trace)")},
- {0x941, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TPIU-Lite", "(Trace Port Interface Unit)")},
- {0x950, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight Component", "(unidentified Cortex-A9 component)")},
- {0x955, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight Component", "(unidentified Cortex-A5 component)")},
- {0x956, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A7 ETM", "(Embedded Trace)")},
- {0x95f, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PTM", "(Program Trace Macrocell)")},
- {0x961, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TMC", "(Trace Memory Controller)")},
- {0x962, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight STM", "(System Trace Macrocell)")},
- {0x963, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight STM", "(System Trace Macrocell)")},
- {0x975, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 ETM", "(Embedded Trace)")},
- {0x9a0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight PMU", "(Performance Monitoring Unit)")},
- {0x9a1, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M4 TPIU", "(Trace Port Interface Unit)")},
- {0x9a9, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 TPIU", "(Trace Port Interface Unit)")},
- {0x9a5, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A5 ETM", "(Embedded Trace)")},
- {0x9a7, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A7 PMU", "(Performance Monitor Unit)")},
- {0x9af, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PMU", "(Performance Monitor Unit)")},
- {0xc05, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A5 Debug", "(Debug Unit)")},
- {0xc07, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A7 Debug", "(Debug Unit)")},
- {0xc08, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A8 Debug", "(Debug Unit)")},
- {0xc09, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A9 Debug", "(Debug Unit)")},
- {0xc0f, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 Debug", "(Debug Unit)")}, /* support? */
- {0xc14, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-R4 Debug", "(Debug Unit)")}, /* support? */
- {0xcd0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Atmel DSU", "(Device Service Unit)")},
- {0xd21, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M33", "()")}, /* support? */
- {0xfff, aa_end, cidc_unknown, PIDR_PN_BIT_STRINGS("end", "end")}
+ {0x000, 0x00, 0, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M3 SCS", "(System Control Space)")},
+ {0x001, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 ITM", "(Instrumentation Trace Module)")},
+ {0x002, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 DWT", "(Data Watchpoint and Trace)")},
+ {0x003, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 FBP", "(Flash Patch and Breakpoint)")},
+ {0x008, 0x00, 0, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M0 SCS", "(System Control Space)")},
+ {0x00a, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M0 DWT", "(Data Watchpoint and Trace)")},
+ {0x00b, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M0 BPU", "(Breakpoint Unit)")},
+ {0x00c, 0x00, 0, aa_cortexm, cidc_gipc, PIDR_PN_BIT_STRINGS("Cortex-M4 SCS", "(System Control Space)")},
+ {0x00d, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM11", "(Embedded Trace)")},
+ {0x00e, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 FBP", "(Flash Patch and Breakpoint)")},
+ {0x101, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("System TSGEN", "(Time Stamp Generator)")},
+ {0x490, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 GIC", "(Generic Interrupt Controller)")},
+ {0x4c7, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 PPB", "(Private Peripheral Bus ROM Table)")},
+ {0x906, 0x14, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight CTI", "(Cross Trigger)")},
+ {0x907, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETB", "(Trace Buffer)")},
+ {0x908, 0x12, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight CSTF", "(Trace Funnel)")},
+ {0x910, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM9", "(Embedded Trace)")},
+ {0x912, 0x11, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TPIU", "(Trace Port Interface Unit)")},
+ {0x913, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ITM", "(Instrumentation Trace Macrocell)")},
+ {0x914, 0x11, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight SWO", "(Single Wire Output)")},
+ {0x917, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight HTM", "(AHB Trace Macrocell)")},
+ {0x920, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight ETM11", "(Embedded Trace)")},
+ {0x921, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A8 ETM", "(Embedded Trace)")},
+ {0x922, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A8 CTI", "(Cross Trigger)")},
+ {0x923, 0x11, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 TPIU", "(Trace Port Interface Unit)")},
+ {0x924, 0x13, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M3 ETM", "(Embedded Trace)")},
+ {0x925, 0x13, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M4 ETM", "(Embedded Trace)")},
+ {0x930, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-R4 ETM", "(Embedded Trace)")},
+ {0x932, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight MTB-M0+", "(Simple Execution Trace)")},
+ {0x941, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TPIU-Lite", "(Trace Port Interface Unit)")},
+ {0x950, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight Component", "(unidentified Cortex-A9 component)")},
+ {0x955, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight Component", "(unidentified Cortex-A5 component)")},
+ {0x956, 0x13, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A7 ETM", "(Embedded Trace)")},
+ {0x95f, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PTM", "(Program Trace Macrocell)")},
+ {0x961, 0x32, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight TMC", "(Trace Memory Controller)")},
+ {0x962, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight STM", "(System Trace Macrocell)")},
+ {0x963, 0x63, 0x0a63, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight STM", "(System Trace Macrocell)")},
+ {0x975, 0x13, 0x4a13, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 ETM", "(Embedded Trace)")},
+ {0x9a0, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("CoreSight PMU", "(Performance Monitoring Unit)")},
+ {0x9a1, 0x11, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M4 TPIU", "(Trace Port Interface Unit)")},
+ {0x9a9, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-M7 TPIU", "(Trace Port Interface Unit)")},
+ {0x9a5, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A5 ETM", "(Embedded Trace)")},
+ {0x9a7, 0x16, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A7 PMU", "(Performance Monitor Unit)")},
+ {0x9af, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 PMU", "(Performance Monitor Unit)")},
+ {0xc05, 0x00, 0, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A5 Debug", "(Debug Unit)")},
+ {0xc07, 0x15, 0, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A7 Debug", "(Debug Unit)")},
+ {0xc08, 0x00, 0, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A8 Debug", "(Debug Unit)")},
+ {0xc09, 0x00, 0, aa_cortexa, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-A9 Debug", "(Debug Unit)")},
+ {0xc0f, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-A15 Debug", "(Debug Unit)")}, /* support? */
+ {0xc14, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Cortex-R4 Debug", "(Debug Unit)")}, /* support? */
+ {0xcd0, 0x00, 0, aa_nosupport, cidc_unknown, PIDR_PN_BIT_STRINGS("Atmel DSU", "(Device Service Unit)")},
+ {0xd20, 0x00, 0x2a04, aa_cortexm, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(System Control Space)")},
+ {0xd20, 0x11, 0, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Trace Port Interface Unit)")},
+ {0xd20, 0x13, 0, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Embedded Trace)")},
+ {0xd20, 0x31, 0x0a31, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Micro Trace Buffer)")},
+ {0xd20, 0x00, 0x1a02, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Data Watchpoint and Trace)")},
+ {0xd20, 0x00, 0x1a03, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Breakpoint Unit)")},
+ {0xd20, 0x14, 0x1a14, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M23", "(Cross Trigger)")},
+ {0xd21, 0x00, 0x2a04, aa_cortexm, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(System Control Space)")},
+ {0xd21, 0x31, 0x0a31, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Micro Trace Buffer)")},
+ {0xd21, 0x43, 0x1a01, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Instrumentation Trace Macrocell)")},
+ {0xd21, 0x00, 0x1a02, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Data Watchpoint and Trace)")},
+ {0xd21, 0x00, 0x1a03, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Breakpoint Unit)")},
+ {0xd21, 0x14, 0x1a14, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Cross Trigger)")},
+ {0xd21, 0x13, 0x4a13, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Embedded Trace)")},
+ {0xd21, 0x11, 0, aa_nosupport, cidc_dc, PIDR_PN_BIT_STRINGS("Cortex-M33", "(Trace Port Interface Unit)")},
+ {0xfff, 0x00, 0, aa_end, cidc_unknown, PIDR_PN_BIT_STRINGS("end", "end")}
};
extern bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base);
@@ -347,6 +379,19 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
return false;
}
+ /* ADIv6: For CoreSight components, read DEVTYPE and ARCHID */
+ uint16_t arch_id = 0;
+ uint8_t dev_type = 0;
+ if (cid_class == cidc_dc) {
+ dev_type = adiv5_mem_read32(ap, addr + DEVTYPE_OFFSET) & DEVTYPE_MASK;
+
+ uint32_t devarch = adiv5_mem_read32(ap, addr + DEVARCH_OFFSET);
+
+ if (devarch & DEVARCH_PRESENT) {
+ arch_id = devarch & DEVARCH_ARCHID_MASK;
+ }
+ }
+
/* Extract part number from the part id register. */
uint16_t part_number = pidr & PIDR_PN_MASK;
/* Find the part number in our part list and run the appropriate probe
@@ -354,13 +399,15 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
*/
int i;
for (i = 0; pidr_pn_bits[i].arch != aa_end; i++) {
- if (pidr_pn_bits[i].part_number == part_number) {
+ if ((pidr_pn_bits[i].part_number == part_number)
+ && (pidr_pn_bits[i].dev_type == dev_type)
+ && (pidr_pn_bits[i].arch_id == arch_id)) {
DEBUG_INFO("%s%d 0x%" PRIx32 ": %s - %s %s (PIDR = 0x%02" PRIx32
- "%08" PRIx32 ")",
+ "%08" PRIx32 " DEVTYPE = 0x%02" PRIx8 " ARCHID = 0x%04" PRIx16 ")",
indent + 1, num_entry, addr,
cidc_debug_strings[cid_class],
pidr_pn_bits[i].type, pidr_pn_bits[i].full,
- (uint32_t)(pidr >> 32), (uint32_t)pidr);
+ (uint32_t)(pidr >> 32), (uint32_t)pidr, dev_type, arch_id);
/* Perform sanity check, if we know what to expect as
* component ID class.
*/
@@ -390,9 +437,9 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
}
if (pidr_pn_bits[i].arch == aa_end) {
DEBUG_WARN("%s0x%" PRIx32 ": %s - Unknown (PIDR = 0x%02" PRIx32
- "%08" PRIx32 ")\n",
+ "%08" PRIx32 " DEVTYPE = 0x%02" PRIx8 " ARCHID = 0x%04" PRIx16 ")\n",
indent, addr, cidc_debug_strings[cid_class],
- (uint32_t)(pidr >> 32), (uint32_t)pidr);
+ (uint32_t)(pidr >> 32), (uint32_t)pidr, dev_type, arch_id);
}
}
return res;
diff --git a/src/target/adiv5_swdp.c b/src/target/adiv5_swdp.c
index 1691a924..5097febd 100644
--- a/src/target/adiv5_swdp.c
+++ b/src/target/adiv5_swdp.c
@@ -45,11 +45,16 @@ int adiv5_swdp_scan(void)
}
#if PC_HOSTED == 1
- if (platform_swdptap_init())
+ if (platform_swdptap_init()) {
+ free(dp);
+ exit(-1);
+ }
#else
- if (swdptap_init())
-#endif
+ if (swdptap_init()) {
+ free(dp);
return -1;
+ }
+#endif
/* Switch from JTAG to SWD mode */
swd_proc.swdptap_seq_out(0xFFFFFFFF, 16);
@@ -78,7 +83,8 @@ int adiv5_swdp_scan(void)
firmware_swdp_error(dp);
adiv5_dp_init(dp);
-
+ if (!target_list)
+ free(dp);
return target_list?1:0;
}
diff --git a/src/target/cortexm.c b/src/target/cortexm.c
index fd1bde1e..10ea6352 100644
--- a/src/target/cortexm.c
+++ b/src/target/cortexm.c
@@ -269,16 +269,17 @@ static bool cortexm_forced_halt(target *t)
platform_srst_set_val(false);
uint32_t dhcsr = 0;
uint32_t start_time = platform_time_ms();
+ const uint32_t dhcsr_halted_bits = CORTEXM_DHCSR_S_HALT | CORTEXM_DHCSR_S_REGRDY |
+ CORTEXM_DHCSR_C_HALT | CORTEXM_DHCSR_C_DEBUGEN;
/* Try hard to halt the target. STM32F7 in WFI
needs multiple writes!*/
while (platform_time_ms() < start_time + cortexm_wait_timeout) {
dhcsr = target_mem_read32(t, CORTEXM_DHCSR);
- if (dhcsr == (CORTEXM_DHCSR_S_HALT | CORTEXM_DHCSR_S_REGRDY |
- CORTEXM_DHCSR_C_HALT | CORTEXM_DHCSR_C_DEBUGEN))
+ if ((dhcsr & dhcsr_halted_bits) == dhcsr_halted_bits)
break;
target_halt_request(t);
}
- if (dhcsr != 0x00030003)
+ if ((dhcsr & dhcsr_halted_bits) != dhcsr_halted_bits)
return false;
return true;
}
@@ -293,7 +294,6 @@ bool cortexm_probe(ADIv5_AP_t *ap, bool forced)
}
adiv5_ap_ref(ap);
- uint32_t identity = ap->idr & 0xff;
struct cortexm_priv *priv = calloc(1, sizeof(*priv));
if (!priv) { /* calloc failed: heap exhaustion */
DEBUG_WARN("calloc: failed in %s\n", __func__);
@@ -309,18 +309,42 @@ bool cortexm_probe(ADIv5_AP_t *ap, bool forced)
t->mem_write = cortexm_mem_write;
t->driver = cortexm_driver_str;
- switch (identity) {
- case 0x11: /* M3/M4 */
- t->core = "M3/M4";
+
+ /* The CPUID register is defined in the ARMv7-M and ARMv8-M
+ * architecture manuals. The PARTNO field is implementation defined,
+ * that is, the actual values are found in the Technical Reference Manual
+ * for each Cortex-M core.
+ */
+ uint32_t cpuid = target_mem_read32(t, CORTEXM_CPUID);
+ uint16_t partno = (cpuid >> 4) & 0xfff;
+
+ switch (partno) {
+ case 0xd21:
+ t->core = "M33";
break;
- case 0x21: /* M0 */
- t->core = "M0";
+
+ case 0xd20:
+ t->core = "M23";
break;
- case 0x31: /* M0+ */
+
+ case 0xc23:
+ t->core = "M3";
+ break;
+
+ case 0xc24:
+ t->core = "M4";
+ break;
+
+ case 0xc27:
+ t->core = "M7";
+ break;
+
+ case 0xc60:
t->core = "M0+";
break;
- case 0x01: /* M7 */
- t->core = "M7";
+
+ case 0xc20:
+ t->core = "M0";
break;
}
diff --git a/src/target/cortexm.h b/src/target/cortexm.h
index 01077620..95952f5b 100644
--- a/src/target/cortexm.h
+++ b/src/target/cortexm.h
@@ -28,6 +28,7 @@ extern long cortexm_wait_timeout;
#define CORTEXM_SCS_BASE (CORTEXM_PPB_BASE + 0xE000)
+#define CORTEXM_CPUID (CORTEXM_SCS_BASE + 0xD00)
#define CORTEXM_AIRCR (CORTEXM_SCS_BASE + 0xD0C)
#define CORTEXM_CFSR (CORTEXM_SCS_BASE + 0xD28)
#define CORTEXM_HFSR (CORTEXM_SCS_BASE + 0xD2C)
diff --git a/src/target/lpc11xx.c b/src/target/lpc11xx.c
index e734fbfd..ba2dc6a4 100644
--- a/src/target/lpc11xx.c
+++ b/src/target/lpc11xx.c
@@ -29,7 +29,8 @@
#define MIN_RAM_SIZE 1024
#define RAM_USAGE_FOR_IAP_ROUTINES 32 /* IAP routines use 32 bytes at top of ram */
-#define IAP_ENTRYPOINT 0x1fff1ff1
+#define IAP_ENTRY_MOST 0x1fff1ff1 /* all except LPC84x */
+#define IAP_ENTRY_84x 0x0f001ff1
#define IAP_RAM_BASE 0x10000000
#define LPC11XX_DEVICE_ID 0x400483F4
@@ -55,13 +56,13 @@ const struct command_s lpc11xx_cmd_list[] = {
{NULL, NULL, NULL}
};
-void lpc11xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize)
+void lpc11xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize, uint32_t iap_entry)
{
struct lpc_flash *lf = lpc_add_flash(t, addr, len);
lf->f.blocksize = erasesize;
lf->f.buf_size = IAP_PGM_CHUNKSIZE;
lf->f.write = lpc_flash_write_magic_vect;
- lf->iap_entry = IAP_ENTRYPOINT;
+ lf->iap_entry = iap_entry;
lf->iap_ram = IAP_RAM_BASE;
lf->iap_msp = IAP_RAM_BASE + MIN_RAM_SIZE - RAM_USAGE_FOR_IAP_ROUTINES;
}
@@ -108,7 +109,7 @@ lpc11xx_probe(target *t)
case 0x2980002B: /* lpc11u24x/401 */
t->driver = "LPC11xx";
target_add_ram(t, 0x10000000, 0x2000);
- lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000);
+ lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST);
target_add_commands(t, lpc11xx_cmd_list, "LPC11xx");
return true;
@@ -116,23 +117,23 @@ lpc11xx_probe(target *t)
case 0x1A24902B:
t->driver = "LPC1112";
target_add_ram(t, 0x10000000, 0x1000);
- lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x1000);
+ lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x1000, IAP_ENTRY_MOST);
return true;
case 0x1000002b: // FX LPC11U6 32 kB SRAM/256 kB flash (max)
t->driver = "LPC11U6";
target_add_ram(t, 0x10000000, 0x8000);
- lpc11xx_add_flash(t, 0x00000000, 0x40000, 0x1000);
+ lpc11xx_add_flash(t, 0x00000000, 0x40000, 0x1000, IAP_ENTRY_MOST);
return true;
case 0x3000002B:
case 0x3D00002B:
t->driver = "LPC1343";
target_add_ram(t, 0x10000000, 0x2000);
- lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x1000);
+ lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x1000, IAP_ENTRY_MOST);
return true;
case 0x00008A04: /* LPC8N04 (see UM11074 Rev.1.3 section 4.5.19) */
t->driver = "LPC8N04";
target_add_ram(t, 0x10000000, 0x2000);
- lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400);
+ lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_MOST);
target_add_commands(t, lpc11xx_cmd_list, "LPC8N04");
return true;
}
@@ -148,7 +149,7 @@ lpc11xx_probe(target *t)
case 0x00008122: /* LPC812M101JDH20 / LPC812M101JTB16 */
t->driver = "LPC81x";
target_add_ram(t, 0x10000000, 0x1000);
- lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400);
+ lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400, IAP_ENTRY_MOST);
target_add_commands(t, lpc11xx_cmd_list, "LPC81x");
return true;
case 0x00008221: /* LPC822M101JHI33 */
@@ -157,7 +158,7 @@ lpc11xx_probe(target *t)
case 0x00008242: /* LPC824M201JDH20 */
t->driver = "LPC82x";
target_add_ram(t, 0x10000000, 0x2000);
- lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400);
+ lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400, IAP_ENTRY_MOST);
target_add_commands(t, lpc11xx_cmd_list, "LPC82x");
return true;
case 0x00008441:
@@ -166,7 +167,7 @@ lpc11xx_probe(target *t)
case 0x00008444:
t->driver = "LPC844";
target_add_ram(t, 0x10000000, 0x2000);
- lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400);
+ lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400, IAP_ENTRY_84x);
return true;
case 0x00008451:
case 0x00008452:
@@ -174,7 +175,7 @@ lpc11xx_probe(target *t)
case 0x00008454:
t->driver = "LPC845";
target_add_ram(t, 0x10000000, 0x4000);
- lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400);
+ lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400, IAP_ENTRY_84x);
return true;
case 0x0003D440: /* LPC11U34/311 */
case 0x0001cc40: /* LPC11U34/421 */
@@ -186,13 +187,13 @@ lpc11xx_probe(target *t)
case 0x00007C40: /* LPC11U37FBD64/501 */
t->driver = "LPC11U3x";
target_add_ram(t, 0x10000000, 0x2000);
- lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000);
+ lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST);
return true;
case 0x00040070: /* LPC1114/333 */
case 0x00050080: /* lpc1115XL */
t->driver = "LPC1100XL";
target_add_ram(t, 0x10000000, 0x2000);
- lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000);
+ lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000, IAP_ENTRY_MOST);
return true;
}
if (idcode) {
diff --git a/src/target/stm32f1.c b/src/target/stm32f1.c
index 84fdd776..4aac170d 100644
--- a/src/target/stm32f1.c
+++ b/src/target/stm32f1.c
@@ -65,6 +65,9 @@ static int stm32f1_flash_write(struct target_flash *f,
#define FLASH_OBR (FPEC_BASE+0x1C)
#define FLASH_WRPR (FPEC_BASE+0x20)
+#define FLASH_BANK2_OFFSET 0x40
+#define FLASH_BANK_SPLIT 0x08080000
+
#define FLASH_CR_OBL_LAUNCH (1<<13)
#define FLASH_CR_OPTWRE (1 << 9)
#define FLASH_CR_STRT (1 << 6)
@@ -124,7 +127,7 @@ bool stm32f1_probe(target *t)
case 0x420: /* Value Line, Low-/Medium density */
target_add_ram(t, 0x20000000, 0x5000);
stm32f1_add_flash(t, 0x8000000, 0x20000, 0x400);
- target_add_commands(t, stm32f1_cmd_list, "STM32 LD/MD");
+ target_add_commands(t, stm32f1_cmd_list, "STM32 LD/MD/VL-LD/VL-MD");
/* Test for non-genuine parts with Core rev 2*/
ADIv5_AP_t *ap = cortexm_ap(t);
if ((ap->idr >> 28) > 1) {
@@ -139,11 +142,19 @@ bool stm32f1_probe(target *t)
case 0x414: /* High density */
case 0x418: /* Connectivity Line */
case 0x428: /* Value Line, High Density */
- t->driver = "STM32F1 high density";
+ t->driver = "STM32F1 VL density";
target_add_ram(t, 0x20000000, 0x10000);
stm32f1_add_flash(t, 0x8000000, 0x80000, 0x800);
- target_add_commands(t, stm32f1_cmd_list, "STM32 HD/CL");
+ target_add_commands(t, stm32f1_cmd_list, "STM32 HF/CL/VL-HD");
return true;
+ case 0x430: /* XL-density */
+ t->driver = "STM32F1 XL density";
+ target_add_ram(t, 0x20000000, 0x18000);
+ stm32f1_add_flash(t, 0x8000000, 0x80000, 0x800);
+ stm32f1_add_flash(t, 0x8080000, 0x80000, 0x800);
+ target_add_commands(t, stm32f1_cmd_list, "STM32 XL/VL-XL");
+ return true;
+
case 0x438: /* STM32F303x6/8 and STM32F328 */
case 0x422: /* STM32F30x */
case 0x446: /* STM32F303xD/E and STM32F398xE */
@@ -192,29 +203,37 @@ bool stm32f1_probe(target *t)
return true;
}
-static void stm32f1_flash_unlock(target *t)
+static void stm32f1_flash_unlock(target *t, uint32_t bank_offset)
{
- target_mem_write32(t, FLASH_KEYR, KEY1);
- target_mem_write32(t, FLASH_KEYR, KEY2);
+ target_mem_write32(t, FLASH_KEYR + bank_offset, KEY1);
+ target_mem_write32(t, FLASH_KEYR + bank_offset, KEY2);
}
static int stm32f1_flash_erase(struct target_flash *f,
target_addr addr, size_t len)
{
target *t = f->t;
+ target_addr end = addr + len - 1;
+ target_addr start = addr;
- stm32f1_flash_unlock(t);
-
+ if ((t->idcode == 0x430) && (end >= FLASH_BANK_SPLIT))
+ stm32f1_flash_unlock(t, FLASH_BANK2_OFFSET);
+ if (addr < FLASH_BANK_SPLIT)
+ stm32f1_flash_unlock(t, 0);
while(len) {
+ uint32_t bank_offset = 0;
+ if (addr >= FLASH_BANK_SPLIT)
+ bank_offset = FLASH_BANK2_OFFSET;
/* Flash page erase instruction */
- target_mem_write32(t, FLASH_CR, FLASH_CR_PER);
+ target_mem_write32(t, FLASH_CR + bank_offset, FLASH_CR_PER);
/* write address to FMA */
- target_mem_write32(t, FLASH_AR, addr);
+ target_mem_write32(t, FLASH_AR + bank_offset, addr);
/* Flash page erase start instruction */
- target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_PER);
+ target_mem_write32(t, FLASH_CR + bank_offset,
+ FLASH_CR_STRT | FLASH_CR_PER);
/* Read FLASH_SR to poll for BSY bit */
- while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
+ while (target_mem_read32(t, FLASH_SR + bank_offset) & FLASH_SR_BSY)
if(target_check_error(t)) {
DEBUG_WARN("stm32f1 flash erase: comm error\n");
return -1;
@@ -227,12 +246,20 @@ static int stm32f1_flash_erase(struct target_flash *f,
}
/* Check for error */
- uint32_t sr = target_mem_read32(t, FLASH_SR);
- if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) {
- DEBUG_INFO("stm32f1 flash erase error 0x%" PRIx32 "\n", sr);
- return -1;
+ if (start < FLASH_BANK_SPLIT) {
+ uint32_t sr = target_mem_read32(t, FLASH_SR);
+ if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) {
+ DEBUG_INFO("stm32f1 flash erase error 0x%" PRIx32 "\n", sr);
+ return -1;
+ }
+ }
+ if ((t->idcode == 0x430) && (end >= FLASH_BANK_SPLIT)) {
+ uint32_t sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET);
+ if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) {
+ DEBUG_INFO("stm32f1 bank 2 flash erase error 0x%" PRIx32 "\n", sr);
+ return -1;
+ }
}
-
return 0;
}
@@ -241,21 +268,49 @@ static int stm32f1_flash_write(struct target_flash *f,
{
target *t = f->t;
uint32_t sr;
- target_mem_write32(t, FLASH_CR, FLASH_CR_PG);
- cortexm_mem_write_sized(t, dest, src, len, ALIGN_HALFWORD);
- /* Read FLASH_SR to poll for BSY bit */
- /* Wait for completion or an error */
- do {
- sr = target_mem_read32(t, FLASH_SR);
- if(target_check_error(t)) {
- DEBUG_WARN("stm32f1 flash write: comm error\n");
+ size_t length = 0;
+ if (dest < FLASH_BANK_SPLIT) {
+ if ((dest + len - 1) >= FLASH_BANK_SPLIT)
+ length = FLASH_BANK_SPLIT - dest;
+ else
+ length = len;
+ target_mem_write32(t, FLASH_CR, FLASH_CR_PG);
+ cortexm_mem_write_sized(t, dest, src, length, ALIGN_HALFWORD);
+ /* Read FLASH_SR to poll for BSY bit */
+ /* Wait for completion or an error */
+ do {
+ sr = target_mem_read32(t, FLASH_SR);
+ if(target_check_error(t)) {
+ DEBUG_WARN("stm32f1 flash write: comm error\n");
+ return -1;
+ }
+ } while (sr & FLASH_SR_BSY);
+
+ if (sr & SR_ERROR_MASK) {
+ DEBUG_WARN("stm32f1 flash write error 0x%" PRIx32 "\n", sr);
return -1;
}
- } while (sr & FLASH_SR_BSY);
+ dest += length;
+ src += length;
+ }
+ length = len - length;
+ if ((t->idcode == 0x430) && length) { /* Write on bank 2 */
+ target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET, FLASH_CR_PG);
+ cortexm_mem_write_sized(t, dest, src, length, ALIGN_HALFWORD);
+ /* Read FLASH_SR to poll for BSY bit */
+ /* Wait for completion or an error */
+ do {
+ sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET);
+ if(target_check_error(t)) {
+ DEBUG_WARN("stm32f1 flash bank2 write: comm error\n");
+ return -1;
+ }
+ } while (sr & FLASH_SR_BSY);
- if (sr & SR_ERROR_MASK) {
- DEBUG_WARN("stm32f1 flash write error 0x%" PRIx32 "\n", sr);
- return -1;
+ if (sr & SR_ERROR_MASK) {
+ DEBUG_WARN("stm32f1 flash bank2 write error 0x%" PRIx32 "\n", sr);
+ return -1;
+ }
}
return 0;
}
@@ -264,7 +319,7 @@ static bool stm32f1_cmd_erase_mass(target *t, int argc, const char **argv)
{
(void)argc;
(void)argv;
- stm32f1_flash_unlock(t);
+ stm32f1_flash_unlock(t, 0);
/* Flash mass erase start instruction */
target_mem_write32(t, FLASH_CR, FLASH_CR_MER);
@@ -279,7 +334,23 @@ static bool stm32f1_cmd_erase_mass(target *t, int argc, const char **argv)
uint16_t sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
return false;
+ if (t->idcode == 0x430) {
+ stm32f1_flash_unlock(t, FLASH_BANK2_OFFSET);
+ /* Flash mass erase start instruction on bank 2*/
+ target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET, FLASH_CR_MER);
+ target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET,
+ FLASH_CR_STRT | FLASH_CR_MER);
+
+ /* Read FLASH_SR to poll for BSY bit */
+ while (target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET) & FLASH_SR_BSY)
+ if(target_check_error(t))
+ return false;
+ /* Check for error */
+ uint16_t sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET);
+ if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
+ return false;
+ }
return true;
}
@@ -359,7 +430,7 @@ static bool stm32f1_cmd_option(target *t, int argc, const char **argv)
default: flash_obp_rdp_key = FLASH_OBP_RDP_KEY;
}
rdprt = target_mem_read32(t, FLASH_OBR) & FLASH_OBR_RDPRT;
- stm32f1_flash_unlock(t);
+ stm32f1_flash_unlock(t, 0);
target_mem_write32(t, FLASH_OPTKEYR, KEY1);
target_mem_write32(t, FLASH_OPTKEYR, KEY2);