Compare commits
10 Commits
jtaglib-cp
...
mehfet
Author | SHA1 | Date |
---|---|---|
Triss | bafd1465c9 | |
Triss | d6e6c91ea7 | |
Triss | a5252e13f6 | |
Triss | cba3cd4f33 | |
Triss | ce87459c07 | |
Triss | 6a2b27db13 | |
Triss | d64791bac6 | |
Triss | 6573bbb6da | |
Triss | 00f11cd9d7 | |
Triss | 7ef085140a |
|
@ -2,3 +2,5 @@
|
|||
*.o
|
||||
mspdebug
|
||||
mspdebug.exe
|
||||
inst/
|
||||
config.mk
|
||||
|
|
5
Makefile
5
Makefile
|
@ -16,6 +16,8 @@
|
|||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
-include config.mk
|
||||
|
||||
CC ?= gcc
|
||||
INSTALL = /usr/bin/install
|
||||
PREFIX ?= /usr/local
|
||||
|
@ -171,6 +173,7 @@ OBJ=\
|
|||
transport/cp210x.o \
|
||||
transport/cdc_acm.o \
|
||||
transport/ftdi.o \
|
||||
transport/mehfet_xport.o \
|
||||
transport/ti3410.o \
|
||||
transport/comport.o \
|
||||
$(BSLHID_OBJ) \
|
||||
|
@ -194,6 +197,8 @@ OBJ=\
|
|||
drivers/jtdev_bus_pirate.o \
|
||||
drivers/jtdev_gpio.o \
|
||||
drivers/jtaglib.o \
|
||||
drivers/mehfet_proto.o \
|
||||
drivers/mehfet.o \
|
||||
drivers/pif.o \
|
||||
drivers/loadbsl.o \
|
||||
drivers/loadbsl_fw.o \
|
||||
|
|
|
@ -364,7 +364,8 @@ static device_t bsl_open(const struct device_args *args)
|
|||
if (args->flags & DEVICE_FLAG_TTY)
|
||||
dev->serial = comport_open(args->path, 460800);
|
||||
else
|
||||
dev->serial = ti3410_open(args->path, args->requested_serial);
|
||||
dev->serial = ti3410_open(args->path, args->requested_serial,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
|
||||
|
||||
if (!dev->serial) {
|
||||
free(dev);
|
||||
|
|
|
@ -75,6 +75,7 @@ struct device_breakpoint {
|
|||
#define DEVICE_FLAG_DO_FWUPDATE 0x10
|
||||
#define DEVICE_FLAG_SKIP_CLOSE 0x20
|
||||
#define DEVICE_FLAG_BSL_NME 0x40 /* BSL no-mass-erase */
|
||||
#define DEVICE_FLAG_HAS_VID_PID 0x80
|
||||
|
||||
struct device_args {
|
||||
int flags;
|
||||
|
@ -88,6 +89,7 @@ struct device_args {
|
|||
int bsl_gpio_rts;
|
||||
int bsl_gpio_dtr;
|
||||
uint8_t bsl_entry_password[32];
|
||||
uint16_t vid, pid;
|
||||
};
|
||||
|
||||
struct device_class {
|
||||
|
|
|
@ -44,9 +44,11 @@ static device_t fet_open_rf2500(const struct device_args *args)
|
|||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
trans = rf2500hidapi_open(args->path, args->requested_serial);
|
||||
trans = rf2500hidapi_open(args->path, args->requested_serial,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
|
||||
#else
|
||||
trans = rf2500_open(args->path, args->requested_serial);
|
||||
trans = rf2500_open(args->path, args->requested_serial,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
|
||||
#endif
|
||||
if (!trans)
|
||||
return NULL;
|
||||
|
@ -79,8 +81,9 @@ static device_t fet_open_olimex_iso_mk2(const struct device_args *args)
|
|||
if (args->flags & DEVICE_FLAG_TTY)
|
||||
trans = comport_open(args->path, 115200);
|
||||
else
|
||||
trans = cdc_acm_open(args->path, args->requested_serial,
|
||||
115200, 0x15ba, 0x0100);
|
||||
trans = cdc_acm_open(args->path, args->requested_serial, 115200,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0100);
|
||||
|
||||
if (!trans)
|
||||
return NULL;
|
||||
|
@ -101,8 +104,9 @@ static device_t fet_open_olimex_iso_mk2(const struct device_args *args)
|
|||
trans = comport_open(args->path, 115200);
|
||||
else
|
||||
trans = cdc_acm_open(args->path,
|
||||
args->requested_serial,
|
||||
115200, 0x15ba, 0x0100);
|
||||
args->requested_serial, 115200,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0100);
|
||||
|
||||
if (!trans)
|
||||
return NULL;
|
||||
|
@ -141,8 +145,9 @@ static device_t fet_open_olimex(const struct device_args *args)
|
|||
if (args->flags & DEVICE_FLAG_TTY)
|
||||
trans = comport_open(args->path, 115200);
|
||||
else
|
||||
trans = cdc_acm_open(args->path, args->requested_serial,
|
||||
115200, 0x15ba, 0x0031);
|
||||
trans = cdc_acm_open(args->path, args->requested_serial, 115200,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0031);
|
||||
|
||||
if (!trans)
|
||||
return NULL;
|
||||
|
@ -177,8 +182,9 @@ static device_t fet_open_olimex_v1(const struct device_args *args)
|
|||
if (args->flags & DEVICE_FLAG_TTY)
|
||||
trans = comport_open(args->path, 500000);
|
||||
else
|
||||
trans = cp210x_open(args->path, args->requested_serial,
|
||||
500000, 0x15ba, 0x0002);
|
||||
trans = cp210x_open(args->path, args->requested_serial, 500000,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0002);
|
||||
|
||||
if (!trans)
|
||||
return NULL;
|
||||
|
@ -213,7 +219,9 @@ static device_t fet_open_olimex_iso(const struct device_args *args)
|
|||
trans = comport_open(args->path, 200000);
|
||||
else
|
||||
trans = ftdi_open(args->path, args->requested_serial,
|
||||
0x15ba, 0x0008, 200000);
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0008,
|
||||
200000);
|
||||
|
||||
if (!trans)
|
||||
return NULL;
|
||||
|
@ -248,7 +256,8 @@ static device_t fet_open_uif(const struct device_args *args)
|
|||
if (args->flags & DEVICE_FLAG_TTY)
|
||||
trans = comport_open(args->path, 460800);
|
||||
else
|
||||
trans = ti3410_open(args->path, args->requested_serial);
|
||||
trans = ti3410_open(args->path, args->requested_serial,
|
||||
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
|
||||
|
||||
if (!trans)
|
||||
return NULL;
|
||||
|
|
|
@ -89,11 +89,18 @@
|
|||
#define jtag_led_red_on(p) p->f->jtdev_led_red(p, 1)
|
||||
#define jtag_led_red_off(p) p->f->jtdev_led_red(p, 0)
|
||||
|
||||
#define jtag_ir_shift(p, ir) p->f->jtdev_ir_shift(p, ir)
|
||||
#define jtag_dr_shift_8(p, dr) p->f->jtdev_dr_shift_8(p, dr)
|
||||
#define jtag_dr_shift_16(p, dr) p->f->jtdev_dr_shift_16(p, dr)
|
||||
#define jtag_tms_sequence(p, bits, tms) p->f->jtdev_tms_sequence(p, bits, tms)
|
||||
#define jtag_init_dap(p) p->f->jtdev_init_dap(p)
|
||||
|
||||
/* Reset target JTAG interface and perform fuse-HW check */
|
||||
static void jtag_reset_tap(struct jtdev *p)
|
||||
static void jtag_default_reset_tap(struct jtdev *p)
|
||||
{
|
||||
int loop_counter;
|
||||
|
||||
// TODO: replace with TMS seq?
|
||||
jtag_tms_set(p);
|
||||
jtag_tck_set(p);
|
||||
|
||||
|
@ -121,7 +128,7 @@ static void jtag_reset_tap(struct jtdev *p)
|
|||
/* This function sets the target JTAG state machine
|
||||
* back into the Run-Test/Idle state after a shift access
|
||||
*/
|
||||
static void jtag_tclk_prep (struct jtdev *p)
|
||||
static void jtag_default_tclk_prep (struct jtdev *p)
|
||||
{
|
||||
/* JTAG state = Exit-DR */
|
||||
jtag_tck_clr(p);
|
||||
|
@ -141,7 +148,7 @@ static void jtag_tclk_prep (struct jtdev *p)
|
|||
* data_out: data to be shifted out
|
||||
* return : scanned TDO value
|
||||
*/
|
||||
static unsigned int jtag_shift( struct jtdev *p,
|
||||
static unsigned int jtag_default_shift( struct jtdev *p,
|
||||
unsigned char num_bits,
|
||||
unsigned int data_out )
|
||||
{
|
||||
|
@ -171,7 +178,7 @@ static unsigned int jtag_shift( struct jtdev *p,
|
|||
p->f->jtdev_tclk(p, tclk_save);
|
||||
|
||||
/* Set JTAG state back to Run-Test/Idle */
|
||||
jtag_tclk_prep(p);
|
||||
jtag_default_tclk_prep(p);
|
||||
|
||||
return data_in;
|
||||
}
|
||||
|
@ -181,7 +188,7 @@ static unsigned int jtag_shift( struct jtdev *p,
|
|||
* instruction: 8 bit instruction
|
||||
* return : scanned TDO value
|
||||
*/
|
||||
static unsigned int jtag_ir_shift(struct jtdev *p, unsigned int instruction)
|
||||
uint8_t jtag_default_ir_shift(struct jtdev *p, uint8_t instruction)
|
||||
{
|
||||
/* JTAG state = Run-Test/Idle */
|
||||
jtag_tms_set(p);
|
||||
|
@ -202,7 +209,7 @@ static unsigned int jtag_ir_shift(struct jtdev *p, unsigned int instruction)
|
|||
jtag_tck_set(p);
|
||||
|
||||
/* JTAG state = Shift-IR, Shift in TDI (8-bit) */
|
||||
return jtag_shift(p, 8, instruction);
|
||||
return jtag_default_shift(p, 8, instruction);
|
||||
|
||||
/* JTAG state = Run-Test/Idle */
|
||||
}
|
||||
|
@ -211,7 +218,7 @@ static unsigned int jtag_ir_shift(struct jtdev *p, unsigned int instruction)
|
|||
* data : 8 bit data
|
||||
* return: scanned TDO value
|
||||
*/
|
||||
static unsigned int jtag_dr_shift_8(struct jtdev *p, unsigned int data)
|
||||
uint8_t jtag_default_dr_shift_8(struct jtdev *p, uint8_t data)
|
||||
{
|
||||
/* JTAG state = Run-Test/Idle */
|
||||
jtag_tms_set(p);
|
||||
|
@ -228,7 +235,7 @@ static unsigned int jtag_dr_shift_8(struct jtdev *p, unsigned int data)
|
|||
jtag_tck_set(p);
|
||||
|
||||
/* JTAG state = Shift-DR, Shift in TDI (16-bit) */
|
||||
return jtag_shift(p, 8, data);
|
||||
return jtag_default_shift(p, 8, data);
|
||||
|
||||
/* JTAG state = Run-Test/Idle */
|
||||
}
|
||||
|
@ -237,7 +244,7 @@ static unsigned int jtag_dr_shift_8(struct jtdev *p, unsigned int data)
|
|||
* data : 16 bit data
|
||||
* return: scanned TDO value
|
||||
*/
|
||||
static unsigned int jtag_dr_shift_16(struct jtdev *p, unsigned int data)
|
||||
uint16_t jtag_default_dr_shift_16(struct jtdev *p, uint16_t data)
|
||||
{
|
||||
/* JTAG state = Run-Test/Idle */
|
||||
jtag_tms_set(p);
|
||||
|
@ -254,11 +261,46 @@ static unsigned int jtag_dr_shift_16(struct jtdev *p, unsigned int data)
|
|||
jtag_tck_set(p);
|
||||
|
||||
/* JTAG state = Shift-DR, Shift in TDI (16-bit) */
|
||||
return jtag_shift(p, 16, data);
|
||||
return jtag_default_shift(p, 16, data);
|
||||
|
||||
/* JTAG state = Run-Test/Idle */
|
||||
}
|
||||
|
||||
void jtag_default_tms_sequence(struct jtdev *p, int bits, unsigned int value)
|
||||
{
|
||||
for (int i = 0; i < bits; ++i) {
|
||||
jtag_tck_clr(p);
|
||||
if (value & (1u << i))
|
||||
jtag_tms_set(p);
|
||||
else
|
||||
jtag_tms_clr(p);
|
||||
jtag_tck_set(p);
|
||||
}
|
||||
}
|
||||
|
||||
void jtag_default_init_dap(struct jtdev *p)
|
||||
{
|
||||
jtag_rst_clr(p);
|
||||
p->f->jtdev_power_on(p);
|
||||
jtag_tdi_set(p);
|
||||
jtag_tms_set(p);
|
||||
jtag_tck_set(p);
|
||||
jtag_tclk_set(p);
|
||||
|
||||
jtag_rst_set(p);
|
||||
jtag_tst_clr(p);
|
||||
|
||||
jtag_tst_set(p);
|
||||
jtag_rst_clr(p);
|
||||
jtag_tst_clr(p);
|
||||
|
||||
jtag_tst_set(p);
|
||||
|
||||
p->f->jtdev_connect(p);
|
||||
jtag_rst_set(p);
|
||||
jtag_default_reset_tap(p);
|
||||
}
|
||||
|
||||
/* Set target CPU JTAG state machine into the instruction fetch state
|
||||
* return: 1 - instruction fetch was set
|
||||
* 0 - otherwise
|
||||
|
@ -378,22 +420,25 @@ static int jtag_verify_psa(struct jtdev *p,
|
|||
|
||||
/* Clock through the PSA */
|
||||
jtag_tclk_set(p);
|
||||
jtag_tck_clr(p);
|
||||
jtag_tms_set(p);
|
||||
jtag_tck_set(p); /* Select DR scan */
|
||||
jtag_tck_clr(p);
|
||||
jtag_tms_clr(p);
|
||||
jtag_tck_set(p); /* Capture DR */
|
||||
jtag_tck_clr(p);
|
||||
jtag_tck_set(p); /* Shift DR */
|
||||
jtag_tck_clr(p);
|
||||
jtag_tms_set(p);
|
||||
jtag_tck_set(p); /* Exit DR */
|
||||
jtag_tck_clr(p);
|
||||
jtag_tck_set(p);
|
||||
jtag_tms_clr(p);
|
||||
jtag_tck_clr(p);
|
||||
jtag_tck_set(p);
|
||||
|
||||
jtag_tms_sequence(p, 6, 0x19); // TMS=1 0 0 1 1 0 ; 6 clocks
|
||||
// jtag_tck_clr(p);
|
||||
// jtag_tms_set(p);
|
||||
// jtag_tck_set(p); /* Select DR scan */
|
||||
// jtag_tck_clr(p);
|
||||
// jtag_tms_clr(p);
|
||||
// jtag_tck_set(p); /* Capture DR */
|
||||
// jtag_tck_clr(p);
|
||||
// jtag_tck_set(p); /* Shift DR */
|
||||
// jtag_tck_clr(p);
|
||||
// jtag_tms_set(p);
|
||||
// jtag_tck_set(p); /* Exit DR */
|
||||
// jtag_tck_clr(p);
|
||||
// jtag_tck_set(p);
|
||||
// jtag_tms_clr(p);
|
||||
// jtag_tck_clr(p);
|
||||
// jtag_tck_set(p);
|
||||
|
||||
jtag_tclk_clr(p);
|
||||
}
|
||||
|
||||
|
@ -414,25 +459,7 @@ unsigned int jtag_init(struct jtdev *p)
|
|||
{
|
||||
unsigned int jtag_id;
|
||||
|
||||
jtag_rst_clr(p);
|
||||
p->f->jtdev_power_on(p);
|
||||
jtag_tdi_set(p);
|
||||
jtag_tms_set(p);
|
||||
jtag_tck_set(p);
|
||||
jtag_tclk_set(p);
|
||||
|
||||
jtag_rst_set(p);
|
||||
jtag_tst_clr(p);
|
||||
|
||||
jtag_tst_set(p);
|
||||
jtag_rst_clr(p);
|
||||
jtag_tst_clr(p);
|
||||
|
||||
jtag_tst_set(p);
|
||||
|
||||
p->f->jtdev_connect(p);
|
||||
jtag_rst_set(p);
|
||||
jtag_reset_tap(p);
|
||||
jtag_init_dap(p);
|
||||
|
||||
/* Check fuse */
|
||||
if (jtag_is_fuse_blown(p)) {
|
||||
|
@ -988,17 +1015,25 @@ address_t jtag_read_reg(struct jtdev *p, int reg)
|
|||
jtag_tclk_set(p);
|
||||
jtag_tclk_clr(p);
|
||||
jtag_tclk_set(p);
|
||||
jtag_tclk_clr(p);
|
||||
jtag_tclk_set(p);
|
||||
/* older code did an extra clock cycle -- don't do this! will put the
|
||||
* current instruction word on the data bus instead of the register value
|
||||
* on the G2452, making it useless. the clock cycles are still required to
|
||||
* move to the next instruction, but those should be done later. */
|
||||
/*jtag_tclk_clr(p);
|
||||
jtag_tclk_set(p);*/
|
||||
|
||||
/* Read databus which contains the registers value */
|
||||
jtag_ir_shift(p, IR_DATA_CAPTURE);
|
||||
value = jtag_dr_shift_16(p, 0x0000);
|
||||
|
||||
jtag_tclk_clr(p);
|
||||
|
||||
/* JTAG controls RW & BYTE */
|
||||
jtag_ir_shift(p, IR_CNTRL_SIG_16BIT);
|
||||
jtag_dr_shift_16(p, 0x2401);
|
||||
|
||||
jtag_tclk_set(p);
|
||||
|
||||
/* Return value read from register */
|
||||
return value;
|
||||
}
|
||||
|
@ -1155,3 +1190,40 @@ int jtag_get_config_fuses( struct jtdev *p )
|
|||
|
||||
return jtag_dr_shift_8(p, 0);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
int jtag_refresh_bps(const char *module, device_t dev, struct jtdev *p)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
struct device_breakpoint *bp;
|
||||
address_t addr;
|
||||
ret = 0;
|
||||
|
||||
for (i = 0; i < dev->max_breakpoints; i++) {
|
||||
bp = &dev->breakpoints[i];
|
||||
|
||||
printc_dbg("%s: refresh breakpoint %d: type=%d "
|
||||
"addr=%04x flags=%04x\n", module,
|
||||
i, bp->type, bp->addr, bp->flags);
|
||||
|
||||
if ( (bp->flags & DEVICE_BP_DIRTY) &&
|
||||
(bp->type == DEVICE_BPTYPE_BREAK) ) {
|
||||
addr = bp->addr;
|
||||
|
||||
if ( !(bp->flags & DEVICE_BP_ENABLED) ) {
|
||||
addr = 0;
|
||||
}
|
||||
|
||||
if ( jtag_set_breakpoint (p, i, addr) == 0) {
|
||||
printc_err("%s: failed to refresh "
|
||||
"breakpoint #%d\n", module, i);
|
||||
ret = -1;
|
||||
} else {
|
||||
bp->flags &= ~DEVICE_BP_DIRTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "device.h"
|
||||
#include "jtdev.h"
|
||||
#include "util.h"
|
||||
|
||||
|
@ -117,4 +118,14 @@ unsigned int jtag_set_breakpoint(struct jtdev *p,
|
|||
unsigned int jtag_cpu_state(struct jtdev *p);
|
||||
int jtag_get_config_fuses(struct jtdev *p);
|
||||
|
||||
/* Default low-level JTAG routines for jtdev implementations that don't have
|
||||
* their own implementations of these routines */
|
||||
uint8_t jtag_default_ir_shift(struct jtdev *p, uint8_t ir);
|
||||
uint8_t jtag_default_dr_shift_8(struct jtdev *p, uint8_t dr);
|
||||
uint16_t jtag_default_dr_shift_16(struct jtdev *p, uint16_t dr);
|
||||
void jtag_default_tms_sequence(struct jtdev *p, int bits, unsigned int value);
|
||||
void jtag_default_init_dap(struct jtdev *p);
|
||||
|
||||
int jtag_refresh_bps(const char *driver, device_t dev, struct jtdev *p);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "jtdev.h"
|
||||
#include "jtaglib.h"
|
||||
#include "output.h"
|
||||
|
||||
#if defined(__linux__) || \
|
||||
|
@ -354,6 +354,12 @@ const struct jtdev_func jtdev_func_pif = {
|
|||
.jtdev_tclk_get = jtpif_tclk_get,
|
||||
.jtdev_tclk_strobe = jtpif_tclk_strobe,
|
||||
.jtdev_led_green = jtpif_led_green,
|
||||
.jtdev_led_red = jtpif_led_red
|
||||
.jtdev_led_red = jtpif_led_red,
|
||||
|
||||
.jtdev_ir_shift = jtag_default_ir_shift,
|
||||
.jtdev_dr_shift_8 = jtag_default_dr_shift_8,
|
||||
.jtdev_dr_shift_16 = jtag_default_dr_shift_16,
|
||||
.jtdev_tms_sequence= jtag_default_tms_sequence,
|
||||
.jtdev_init_dap = jtag_default_init_dap
|
||||
};
|
||||
|
||||
|
|
|
@ -64,6 +64,21 @@ struct jtdev_func{
|
|||
void (*jtdev_led_green)(struct jtdev *p, int out);
|
||||
void (*jtdev_led_red)(struct jtdev *p, int out);
|
||||
|
||||
// * reset tap (+fuse check)
|
||||
// * irshift
|
||||
// * drshift8
|
||||
// * drshift16
|
||||
// * tclk clr/set
|
||||
// * PSA needs special treatment! (or just replace with TMS sequence?)
|
||||
// * jtag_init: idk but it needs something. maybe just special-case it
|
||||
// TODO: need something to signal when we can switch clock speed for TCLK bursts
|
||||
|
||||
/* Optional functions implementing higher-level stuff */
|
||||
uint8_t (*jtdev_ir_shift)(struct jtdev *p, uint8_t ir);
|
||||
uint8_t (*jtdev_dr_shift_8)(struct jtdev *p, uint8_t dr);
|
||||
uint16_t (*jtdev_dr_shift_16)(struct jtdev *p, uint16_t dr);
|
||||
void (*jtdev_tms_sequence)(struct jtdev *p, int bits, unsigned int value);
|
||||
void (*jtdev_init_dap)(struct jtdev *p);
|
||||
};
|
||||
|
||||
extern const struct jtdev_func jtdev_func_pif;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "jtdev.h"
|
||||
#include "jtaglib.h"
|
||||
#include "output.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
|
@ -186,7 +186,8 @@ static void jtbp_close(struct jtdev *p)
|
|||
|
||||
out_buff = 0x0f;
|
||||
// Don't care if this fails, user can just power cycle the bus pirate
|
||||
if(write(p->port, &out_buff, 1));
|
||||
if(write(p->port, &out_buff, 1))
|
||||
;
|
||||
|
||||
close(p->port);
|
||||
}
|
||||
|
@ -351,6 +352,12 @@ const struct jtdev_func jtdev_func_bp = {
|
|||
.jtdev_tclk_get = jtbp_tclk_get,
|
||||
.jtdev_tclk_strobe = jtbp_tclk_strobe,
|
||||
.jtdev_led_green = jtbp_led_green,
|
||||
.jtdev_led_red = jtbp_led_red
|
||||
.jtdev_led_red = jtbp_led_red,
|
||||
|
||||
.jtdev_ir_shift = jtag_default_ir_shift,
|
||||
.jtdev_dr_shift_8 = jtag_default_dr_shift_8,
|
||||
.jtdev_dr_shift_16 = jtag_default_dr_shift_16,
|
||||
.jtdev_tms_sequence= jtag_default_tms_sequence,
|
||||
.jtdev_init_dap = jtag_default_init_dap
|
||||
};
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include "jtdev.h"
|
||||
#include "jtaglib.h"
|
||||
#include "output.h"
|
||||
|
||||
#if defined(__linux__) || \
|
||||
|
@ -263,5 +263,11 @@ const struct jtdev_func jtdev_func_gpio = {
|
|||
.jtdev_tclk_get = jtgpio_tclk_get,
|
||||
.jtdev_tclk_strobe = jtgpio_tclk_strobe,
|
||||
.jtdev_led_green = jtgpio_led_green,
|
||||
.jtdev_led_red = jtgpio_led_red
|
||||
.jtdev_led_red = jtgpio_led_red,
|
||||
|
||||
.jtdev_ir_shift = jtag_default_ir_shift,
|
||||
.jtdev_dr_shift_8 = jtag_default_dr_shift_8,
|
||||
.jtdev_dr_shift_16 = jtag_default_dr_shift_16,
|
||||
.jtdev_tms_sequence= jtag_default_tms_sequence,
|
||||
.jtdev_init_dap = jtag_default_init_dap
|
||||
};
|
||||
|
|
|
@ -0,0 +1,639 @@
|
|||
/* MSPDebug - debugging tool for MSP430 MCUs
|
||||
* Copyright (C) 2021 sys64738@disroot.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "output.h"
|
||||
#include "ctrlc.h"
|
||||
#include "jtaglib.h"
|
||||
#include "mehfet_proto.h"
|
||||
#include "mehfet_xport.h"
|
||||
|
||||
#include "mehfet.h"
|
||||
|
||||
|
||||
struct mehfet_device {
|
||||
struct device base;
|
||||
struct jtdev jtag;
|
||||
transport_t trans;
|
||||
enum mehfet_conn connstat;
|
||||
};
|
||||
|
||||
|
||||
/*extern void __builtin_trap(void);*/
|
||||
#define NO_LL_JTAG_BP 0
|
||||
#define no_ll_jtag() \
|
||||
do { \
|
||||
printc_err("mehfet: %s: low-lewel JTAG function not implemented!\n", __func__); \
|
||||
p->failed = 1; \
|
||||
if (NO_LL_JTAG_BP) /*__builtin_trap()*/; \
|
||||
} while (0) \
|
||||
|
||||
|
||||
#define JTMF_GET_DEV(p) ((struct mehfet_device*)((size_t)(p) - \
|
||||
offsetof(struct mehfet_device, jtag))) \
|
||||
|
||||
|
||||
static int jtmf_open(struct jtdev* p, const char* device)
|
||||
{
|
||||
printc_err("mehfet: %s should not get called.\n", __func__);
|
||||
p->failed = 1;
|
||||
return -1;
|
||||
}
|
||||
static void jtmf_close(struct jtdev* p)
|
||||
{
|
||||
printc_err("mehfet: %s should not get called.\n", __func__);
|
||||
p->failed = 1;
|
||||
}
|
||||
static void jtmf_power_on(struct jtdev* p)
|
||||
{
|
||||
printc_err("mehfet: %s should not get called.\n", __func__);
|
||||
p->failed = 1;
|
||||
}
|
||||
static void jtmf_power_off(struct jtdev* p)
|
||||
{
|
||||
printc_err("mehfet: %s should not get called.\n", __func__);
|
||||
p->failed = 1;
|
||||
}
|
||||
static void jtmf_connect(struct jtdev* p)
|
||||
{
|
||||
printc_err("mehfet: %s should not get called.\n", __func__);
|
||||
p->failed = 1;
|
||||
}
|
||||
static void jtmf_release(struct jtdev* p)
|
||||
{
|
||||
printc_err("mehfet: %s should not get called.\n", __func__);
|
||||
p->failed = 1;
|
||||
}
|
||||
|
||||
static void jtmf_tck(struct jtdev* p, int _) { (void)_; no_ll_jtag(); }
|
||||
static void jtmf_tms(struct jtdev* p, int _) { (void)_; no_ll_jtag(); }
|
||||
static void jtmf_tdi(struct jtdev* p, int _) { (void)_; no_ll_jtag(); }
|
||||
static void jtmf_rst(struct jtdev* p, int _) { (void)_; no_ll_jtag(); }
|
||||
static void jtmf_tst(struct jtdev* p, int _) { (void)_; no_ll_jtag(); }
|
||||
static int jtmf_tdo_get(struct jtdev* p) { no_ll_jtag(); return 0; }
|
||||
|
||||
static void jtmf_tclk(struct jtdev* p, int out)
|
||||
{
|
||||
struct mehfet_device* d = JTMF_GET_DEV(p);
|
||||
|
||||
int r = mehfet_cmd_tclk_edge(d->trans, out);
|
||||
if (r < 0) p->failed = 1;
|
||||
}
|
||||
static int jtmf_tclk_get(struct jtdev* p)
|
||||
{
|
||||
struct mehfet_device* d = JTMF_GET_DEV(p);
|
||||
int ret = 1;
|
||||
|
||||
enum mehfet_lines lines = 0;
|
||||
int r = mehfet_cmd_get_old_lines(d->trans, &lines);
|
||||
if (r < 0) {
|
||||
p->failed = 1;
|
||||
} else {
|
||||
ret = (lines & mehfet_line_tclk) ? 1 : 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
static void jtmf_tclk_strobe(struct jtdev* p, unsigned int count)
|
||||
{
|
||||
struct mehfet_device* d = JTMF_GET_DEV(p);
|
||||
|
||||
int r = mehfet_cmd_tclk_burst(d->trans, count);
|
||||
if (r < 0) p->failed = 1;
|
||||
}
|
||||
|
||||
/* MehFET has no leds */
|
||||
static void jtmf_led_green(struct jtdev* p, int out) { (void)p; (void)out; }
|
||||
static void jtmf_led_red (struct jtdev* p, int out) { (void)p; (void)out; }
|
||||
|
||||
static uint8_t jtmf_ir_shift(struct jtdev *p, uint8_t ir)
|
||||
{
|
||||
struct mehfet_device* d = JTMF_GET_DEV(p);
|
||||
|
||||
uint8_t ret = 0;
|
||||
int r = mehfet_cmd_irshift(d->trans, ir, &ret);
|
||||
if (r < 0) p->failed = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
static uint8_t jtmf_dr_shift_8(struct jtdev *p, uint8_t dr)
|
||||
{
|
||||
struct mehfet_device* d = JTMF_GET_DEV(p);
|
||||
|
||||
uint8_t ret = 0;
|
||||
int r = mehfet_cmd_drshift(d->trans, 8, &dr, &ret);
|
||||
if (r < 0) p->failed = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
static uint16_t jtmf_dr_shift_16(struct jtdev *p, uint16_t dr)
|
||||
{
|
||||
struct mehfet_device* d = JTMF_GET_DEV(p);
|
||||
|
||||
uint8_t inbuf[2] = { dr & 0xff, (dr >> 8) & 0xff };
|
||||
uint8_t outbuf[2];
|
||||
int r = mehfet_cmd_drshift(d->trans, 16, inbuf, outbuf);
|
||||
if (r < 0) p->failed = 1;
|
||||
|
||||
return outbuf[0] | ((uint16_t)outbuf[1] << 8);
|
||||
}
|
||||
static void jtmf_tms_sequence(struct jtdev *p, int bits, unsigned int value)
|
||||
{
|
||||
struct mehfet_device* d = JTMF_GET_DEV(p);
|
||||
|
||||
enum mehfet_lines lines = 0;
|
||||
int r = mehfet_cmd_get_old_lines(d->trans, &lines);
|
||||
if (r < 0) {
|
||||
p->failed = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t dbuf[4] = { value & 0xff, (value >> 8) & 0xff,
|
||||
(value >> 16) & 0xff, (value >> 24) & 0xff };
|
||||
r = mehfet_cmd_tms_seq(d->trans, lines & mehfet_line_tdi, bits, dbuf);
|
||||
if (r < 0) p->failed = 1;
|
||||
}
|
||||
static void jtmf_init_dap(struct jtdev *p)
|
||||
{
|
||||
struct mehfet_device* dev = JTMF_GET_DEV(p);
|
||||
|
||||
enum mehfet_resettap_status stat = 0;
|
||||
int r = mehfet_cmd_reset_tap(dev->trans, mehfet_rsttap_do_reset
|
||||
| mehfet_rsttap_fuse_do, &stat);
|
||||
|
||||
if (r < 0) p->failed = 1;
|
||||
}
|
||||
|
||||
|
||||
static const struct jtdev_func jtdev_func_mehfet = {
|
||||
.jtdev_open = jtmf_open,
|
||||
.jtdev_close = jtmf_close,
|
||||
.jtdev_power_on = jtmf_power_on,
|
||||
.jtdev_power_off = jtmf_power_off,
|
||||
.jtdev_connect = jtmf_connect,
|
||||
.jtdev_release = jtmf_release,
|
||||
.jtdev_tck = jtmf_tck,
|
||||
.jtdev_tms = jtmf_tms,
|
||||
.jtdev_tdi = jtmf_tdi,
|
||||
.jtdev_rst = jtmf_rst,
|
||||
.jtdev_tst = jtmf_tst,
|
||||
.jtdev_tdo_get = jtmf_tdo_get,
|
||||
.jtdev_tclk = jtmf_tclk,
|
||||
.jtdev_tclk_get = jtmf_tclk_get,
|
||||
.jtdev_tclk_strobe = jtmf_tclk_strobe,
|
||||
.jtdev_led_green = jtmf_led_green,
|
||||
.jtdev_led_red = jtmf_led_red,
|
||||
|
||||
.jtdev_ir_shift = jtmf_ir_shift,
|
||||
.jtdev_dr_shift_8 = jtmf_dr_shift_8,
|
||||
.jtdev_dr_shift_16 = jtmf_dr_shift_16,
|
||||
.jtdev_tms_sequence= jtmf_tms_sequence,
|
||||
.jtdev_init_dap = jtmf_init_dap
|
||||
};
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
// TODO: these five are kinda copied from pif.c, should be deduplicated
|
||||
|
||||
static int read_words(device_t dev_base, const struct chipinfo_memory *m,
|
||||
address_t addr, address_t len, uint8_t *data)
|
||||
{
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: read_words: addr=0x%04x, len=0x%x\n", addr, len);
|
||||
#endif
|
||||
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
struct jtdev *p = &dev->jtag;
|
||||
|
||||
for (unsigned int index = 0; index < len; index += 2) {
|
||||
unsigned int word = jtag_read_mem(p, 16, addr+index);
|
||||
data[index ] = word & 0x00ff;
|
||||
data[index+1] = (word >> 8) & 0x00ff;
|
||||
}
|
||||
|
||||
return p->failed ? -1 : len;
|
||||
}
|
||||
|
||||
static int write_ram_word(struct jtdev *p, address_t addr, uint16_t value)
|
||||
{
|
||||
jtag_write_mem(p, 16, addr, value);
|
||||
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
|
||||
static int write_flash_block(struct jtdev *p, address_t addr,
|
||||
address_t len, const uint8_t *data)
|
||||
{
|
||||
uint16_t* word = malloc( len / 2 * sizeof(*word) );
|
||||
if (!word) {
|
||||
pr_error("mehfet: failed to allocate memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < len/2; i++) {
|
||||
word[i]=data[2*i] + (((uint16_t)data[2*i+1]) << 8);
|
||||
}
|
||||
jtag_write_flash(p, addr, len/2, word);
|
||||
|
||||
free(word);
|
||||
|
||||
return p->failed ? -1 : 0;
|
||||
}
|
||||
|
||||
/* Write a word-aligned block to any kind of memory.
|
||||
* returns the number of bytes written or -1 on failure
|
||||
*/
|
||||
static int write_words(device_t dev_base, const struct chipinfo_memory *m,
|
||||
address_t addr, address_t len, const uint8_t *data)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
struct jtdev *p = &dev->jtag;
|
||||
int r;
|
||||
|
||||
if (m->type != CHIPINFO_MEMTYPE_FLASH) {
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: write_words: addr=0x%04x, len=0x%x data=0x%04x\n",
|
||||
addr, len, r16le(data));
|
||||
if (len != 2) {
|
||||
printc_dbg("mehfet: WARN: write_words: len != 2! but 0x%04x\n", len);
|
||||
__builtin_trap();
|
||||
}
|
||||
#endif
|
||||
len = 2;
|
||||
r = write_ram_word(p, addr, r16le(data));
|
||||
} else {
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: write_flash_block: addr=0x%04x, len=0x%x\n", addr, len);
|
||||
#endif
|
||||
r = write_flash_block(p, addr, len, data);
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
printc_err("mehfet: write_words at address 0x%x failed\n", addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static int mehfet_readmem(device_t dev_base, address_t addr,
|
||||
uint8_t *mem, address_t len)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
dev->jtag.failed = 0;
|
||||
return readmem(dev_base, addr, mem, len, read_words);
|
||||
}
|
||||
|
||||
static int mehfet_writemem(device_t dev_base, address_t addr,
|
||||
const uint8_t *mem, address_t len)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
dev->jtag.failed = 0;
|
||||
return writemem(dev_base, addr, mem, len, write_words, read_words);
|
||||
}
|
||||
|
||||
static int mehfet_setregs(device_t dev_base, const address_t *regs)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: set regs\n");
|
||||
#endif
|
||||
for (int i = 0; i < DEVICE_NUM_REGS; i++) {
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: [%d] = 0x%04x\n", i, regs[i]);
|
||||
#endif
|
||||
jtag_write_reg(&dev->jtag, i, regs[i]);
|
||||
}
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
static int mehfet_getregs(device_t dev_base, address_t *regs)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: get regs\n");
|
||||
#endif
|
||||
for (int i = 0; i < DEVICE_NUM_REGS; i++) {
|
||||
regs[i] = jtag_read_reg(&dev->jtag, i);
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: [%d] = 0x%04x\n", i, regs[i]);
|
||||
#endif
|
||||
}
|
||||
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
static int mehfet_ctl(device_t dev_base, device_ctl_t type)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
switch (type) {
|
||||
case DEVICE_CTL_RESET:
|
||||
/* perform soft reset */
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: soft reset (PUC)\n");
|
||||
#endif
|
||||
jtag_execute_puc(&dev->jtag);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_RUN:
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: set breakpoints\n");
|
||||
#endif
|
||||
/* transfer changed breakpoints to device */
|
||||
if (jtag_refresh_bps("mehfet", &dev->base, &dev->jtag) < 0) return -1;
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: run @ current PC\n");
|
||||
#endif
|
||||
/* start program execution at current PC */
|
||||
jtag_release_device(&dev->jtag, 0xffff);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_HALT:
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: halt\n");
|
||||
#endif
|
||||
/* take device under JTAG control */
|
||||
jtag_get_device(&dev->jtag);
|
||||
break;
|
||||
|
||||
case DEVICE_CTL_STEP:
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: single-step\n");
|
||||
#endif
|
||||
/* execute next instruction at current PC */
|
||||
jtag_single_step(&dev->jtag);
|
||||
break;
|
||||
|
||||
default:
|
||||
printc_err("mehfet: unsupported operation %d\n", type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
static device_status_t mehfet_poll(device_t dev_base)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
if (delay_ms(100) < 0 || ctrlc_check())
|
||||
return DEVICE_STATUS_INTR;
|
||||
|
||||
int r = jtag_cpu_state(&dev->jtag);
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: cpu state: %d\n", r);
|
||||
#endif
|
||||
|
||||
if (r == 1) return DEVICE_STATUS_HALTED;
|
||||
|
||||
return DEVICE_STATUS_RUNNING;
|
||||
}
|
||||
|
||||
static int mehfet_erase(device_t dev_base, device_erase_type_t type,
|
||||
address_t addr)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
dev->jtag.failed = 0;
|
||||
|
||||
switch (type) {
|
||||
case DEVICE_ERASE_MAIN:
|
||||
jtag_erase_flash(&dev->jtag, JTAG_ERASE_MAIN, addr);
|
||||
break;
|
||||
case DEVICE_ERASE_ALL:
|
||||
jtag_erase_flash(&dev->jtag, JTAG_ERASE_MASS, addr);
|
||||
break;
|
||||
case DEVICE_ERASE_SEGMENT:
|
||||
jtag_erase_flash(&dev->jtag, JTAG_ERASE_SGMT, addr);
|
||||
break;
|
||||
default: return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: erase flash %d at %04x: %s\n", type, addr, dev->jtag.failed ? "failed" : "succeeded");
|
||||
#endif
|
||||
|
||||
return dev->jtag.failed ? -1 : 0;
|
||||
}
|
||||
|
||||
static int mehfet_getconfigfuses(device_t dev_base)
|
||||
{
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
int r = jtag_get_config_fuses(&dev->jtag);
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: get_config_fuses: %d\n", r);
|
||||
#endif
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
static int check_dev_ok(struct mehfet_device* dev, const struct device_args* args,
|
||||
enum mehfet_conn* useconn) {
|
||||
transport_t t = dev->trans;
|
||||
struct mehfet_info info;
|
||||
int r;
|
||||
|
||||
r = mehfet_cmd_info(t, &info);
|
||||
if (r < 0) return r;
|
||||
|
||||
printc_dbg("mehfet: MehFET %s\n", info.devicename);
|
||||
free(info.devicename);
|
||||
|
||||
if (info.proto_version < MEHFET_PROTO_VER_MIN_SUPPORTED) {
|
||||
printc_err("mehfet: device has protocol version %04x, "
|
||||
"need at least %04x\n", info.proto_version,
|
||||
MEHFET_PROTO_VER_MIN_SUPPORTED);
|
||||
return -1;
|
||||
}
|
||||
if (info.proto_version > MEHFET_PROTO_VER) {
|
||||
printc_err("mehfet: device has newer protocol version %04x "
|
||||
"supporting at most %04x\n", info.proto_version,
|
||||
MEHFET_PROTO_VER);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (args->flags & DEVICE_FLAG_JTAG) {
|
||||
if (!(info.caps & (mehfet_cap_jtag_noentry | mehfet_cap_jtag_entryseq))) {
|
||||
printc_err("mehfet: Cannot do JTAG, device doesn't have the capability\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// devices that don't need one will probably work when given an entry
|
||||
// sequence. no good way of doing a proper autodetect sadly
|
||||
if (info.caps & mehfet_cap_jtag_entryseq)
|
||||
*useconn = mehfet_conn_jtag_entryseq;
|
||||
else
|
||||
*useconn = mehfet_conn_jtag_noentry;
|
||||
} else {
|
||||
if (!(info.caps & mehfet_cap_sbw_entryseq)) {
|
||||
printc_err("mehfet: Cannot do Spy-Bi-Wire, device doesn't have the capability\n");
|
||||
return -1;
|
||||
}
|
||||
*useconn = mehfet_conn_sbw_entryseq;
|
||||
}
|
||||
|
||||
if (args->flags & DEVICE_FLAG_FORCE_RESET)
|
||||
*useconn |= mehfet_conn_nrstmask;
|
||||
|
||||
mehfet_transport_set_buf_size(t, (int)info.packet_buf_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_device(struct mehfet_device* dev) {
|
||||
printc_dbg("Starting JTAG\n");
|
||||
|
||||
unsigned int jtagid = jtag_init(&dev->jtag);
|
||||
if (dev->jtag.failed) return -1;
|
||||
|
||||
printc("JTAG ID: 0x%02x\n", jtagid);
|
||||
if (jtagid != 0x89 && jtagid != 0x91) {
|
||||
printc_err("mehfet: unexpected JTAG ID: 0x%02x\n", jtagid);
|
||||
jtag_release_device(&dev->jtag, 0xfffe);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// JTAG fuse check has been performed, so we can now switch to a
|
||||
// higher-speed physical transport suitable for ~350 kHz TCLK strobes used
|
||||
// in (and required for) flash programming
|
||||
int r = mehfet_cmd_set_clkspeed(dev->trans, true);
|
||||
if (r < 0) {
|
||||
jtag_release_device(&dev->jtag, 0xfffe);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void mehfet_destroy(device_t dev_base) {
|
||||
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
|
||||
|
||||
if (!dev) return;
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: releasing device & disconnecting\n");
|
||||
#endif
|
||||
|
||||
if (dev->trans) {
|
||||
jtag_release_device(&dev->jtag, 0xfffe); // 0xfffe=reset address : POR
|
||||
|
||||
mehfet_cmd_disconnect(dev->trans);
|
||||
|
||||
dev->trans->ops->destroy(dev->trans);
|
||||
dev->trans = NULL;
|
||||
}
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
static device_t mehfet_open(const struct device_args* args) {
|
||||
struct mehfet_device* dev;
|
||||
int r;
|
||||
|
||||
if ((args->flags & DEVICE_FLAG_TTY)) {
|
||||
printc_err("mehfet: this driver does not support TTY access\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev = calloc(1, sizeof(*dev));
|
||||
if (!dev) {
|
||||
printc_err("mehfet: malloc: %s\n", last_error());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev->base.type = &device_mehfet;
|
||||
dev->base.max_breakpoints = 2; // TODO
|
||||
dev->base.need_probe = 1; // TODO
|
||||
dev->jtag.f = &jtdev_func_mehfet;
|
||||
|
||||
// the MehFET currently doesn't have a designated PID, so we can't really
|
||||
// default to one.
|
||||
dev->trans = mehfet_transport_open(args->path,
|
||||
((args->flags & DEVICE_FLAG_HAS_VID_PID) ? &args->vid : NULL),
|
||||
((args->flags & DEVICE_FLAG_HAS_VID_PID) ? &args->pid : NULL),
|
||||
args->requested_serial);
|
||||
if (!dev->trans) goto FAIL;
|
||||
|
||||
enum mehfet_conn useconn;
|
||||
r = check_dev_ok(dev, args, &useconn);
|
||||
if (r < 0) goto FAIL;
|
||||
|
||||
r = mehfet_cmd_connect(dev->trans, useconn);
|
||||
if (r < 0) goto FAIL;
|
||||
|
||||
r = mehfet_cmd_status(dev->trans, &dev->connstat);
|
||||
if (r < 0) goto FAIL;
|
||||
|
||||
if (dev->connstat != (useconn & mehfet_conn_typemask)) {
|
||||
printc_err("mehfet: could not create connection to device\n");
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
r = init_device(dev);
|
||||
if (r < 0) goto FAIL;
|
||||
|
||||
#ifdef DEBUG_MEHFET_DRIVER
|
||||
printc_dbg("mehfet: device opened\n");
|
||||
#endif
|
||||
|
||||
return (device_t)dev;
|
||||
|
||||
FAIL:
|
||||
mehfet_destroy((device_t)dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct device_class device_mehfet = {
|
||||
.name = "mehfet",
|
||||
.help = "MehFET USB JTAG/SBW device",
|
||||
.open = mehfet_open,
|
||||
.destroy = mehfet_destroy,
|
||||
.readmem = mehfet_readmem,
|
||||
.writemem = mehfet_writemem,
|
||||
.getregs = mehfet_getregs,
|
||||
.setregs = mehfet_setregs,
|
||||
.ctl = mehfet_ctl,
|
||||
.poll = mehfet_poll,
|
||||
.erase = mehfet_erase,
|
||||
.getconfigfuses = mehfet_getconfigfuses
|
||||
};
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/* MSPDebug - debugging tool for MSP430 MCUs
|
||||
* Copyright (C) 2021, sys64738@disroot.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MEHFET_H_
|
||||
#define MEHFET_H_
|
||||
|
||||
#include "device.h"
|
||||
|
||||
extern const struct device_class device_mehfet;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,473 @@
|
|||
/* MSPDebug - debugging tool for MSP430 MCUs
|
||||
* Copyright (C) 2021 sys64738@disroot.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mehfet_xport.h"
|
||||
#include "output.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "mehfet_proto.h"
|
||||
|
||||
// TODO: replace '64' by transport buf size
|
||||
|
||||
int mehfet_cmd_info(transport_t t, struct mehfet_info* info) {
|
||||
if (!info) return -1;
|
||||
|
||||
uint8_t buf[64];
|
||||
int r;
|
||||
|
||||
r = mehfet_send_raw(t, mehfet_info, 0, NULL);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("Info", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len < 8) {
|
||||
printc_err("mehfet: Info response too short: %d < 8\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
info->caps = buf[0] | ((uint32_t)buf[1] << 8)
|
||||
| ((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24);
|
||||
info->proto_version = buf[4] | ((uint16_t)buf[5] << 8);
|
||||
info->packet_buf_size = 1u << buf[6];
|
||||
// buf[7]: reserved
|
||||
|
||||
if (len > 9) { // len includes the null terminator
|
||||
char* str = calloc(len - 8, 1);
|
||||
memcpy(str, &buf[8], len - 8);
|
||||
str[len - 9] = 0;
|
||||
|
||||
info->devicename = str;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: Info(): '%s' caps=0x%x, protover=0x%04x, pktsize=0x%x\n",
|
||||
info->devicename ? info->devicename : "<none>",
|
||||
info->caps, info->proto_version, info->packet_buf_size);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mehfet_cmd_status(transport_t t, enum mehfet_conn* ret) {
|
||||
if (!ret) return -1;
|
||||
|
||||
uint8_t buf[64];
|
||||
int r;
|
||||
|
||||
r = mehfet_send_raw(t, mehfet_status, 0, NULL);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("Status", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != 1) {
|
||||
printc_err("mehfet: Status response wrong length: %d != 1\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ret = buf[0];
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: Status(): %hhu\n", *ret);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mehfet_cmd_connect(transport_t t, enum mehfet_conn conn) {
|
||||
uint8_t buf[64];
|
||||
int r;
|
||||
|
||||
buf[0] = conn;
|
||||
r = mehfet_send_raw(t, mehfet_connect, 1, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("Connect", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != 0) {
|
||||
printc_err("mehfet: Connect response wrong length: %d != 0\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: Connect(0x%x)\n", conn);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mehfet_cmd_disconnect(transport_t t) {
|
||||
uint8_t buf[64];
|
||||
int r;
|
||||
|
||||
r = mehfet_send_raw(t, mehfet_disconnect, 0, NULL);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("Disconnect", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != 0) {
|
||||
printc_err("mehfet: Disconnect response wrong length: %d != 0\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: Disconnect()\n");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mehfet_cmd_delay(transport_t t, bool us, bool exact, uint32_t time) {
|
||||
if (time >= (1u << 30)) return -1; // too large
|
||||
|
||||
uint8_t buf[64];
|
||||
int r;
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) buf[i] = (time >> (i*8)) & 0xff;
|
||||
if (us) buf[3] |= 0x40;
|
||||
if (exact) buf[3] |= 0x80;
|
||||
|
||||
r = mehfet_send_raw(t, mehfet_delay, 4, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("Delay", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != 0) {
|
||||
printc_err("mehfet: Delay response wrong length: %d != 0\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: Delay(us=%c exact=%c time=%u)\n",
|
||||
us?'t':'f', exact?'t':'f', time);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mehfet_cmd_set_clkspeed(transport_t t, bool fast) {
|
||||
uint8_t buf[64];
|
||||
int r;
|
||||
|
||||
buf[0] = fast ? 0xff : 0;
|
||||
r = mehfet_send_raw(t, mehfet_set_clkspeed, 1, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("SetClkSpeed", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != 0) {
|
||||
printc_err("mehfet: SetClkSpeed response wrong length: %d != 0\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: SetClkSpeed(%s)\n", fast?"fast":"slow");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mehfet_cmd_get_old_lines(transport_t t, enum mehfet_lines* lines) {
|
||||
if (!lines) return -1;
|
||||
|
||||
uint8_t buf[64];
|
||||
int r;
|
||||
|
||||
r = mehfet_send_raw(t, mehfet_get_old_lines, 0, NULL);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("GetOldLines", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != 1) {
|
||||
printc_err("mehfet: GetOldLines response wrong length: %d != 1\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*lines = buf[0];
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: GetOldLines(): 0x%x\n", *lines);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mehfet_cmd_tdio_seq(transport_t t, uint32_t nbits, bool tms, const uint8_t* tdi, uint8_t* tdo) {
|
||||
if (!tdi || !tdo || !nbits) return -1;
|
||||
|
||||
int r;
|
||||
uint32_t nbytes = (nbits + 7) >> 3;
|
||||
uint8_t buf[(nbytes + 5) < 64 ? 64 : (nbytes + 5)]; // need min for recv
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) buf[i] = (nbits >> (i*8)) & 0xff;
|
||||
buf[4] = tms ? 0xff : 0;
|
||||
memcpy(&buf[5], tdi, nbytes);
|
||||
|
||||
r = mehfet_send_raw(t, mehfet_tdio_seq, nbytes + 5, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf; // is a max len
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("TdioSequence", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != nbytes) {
|
||||
printc_err("mehfet: TdioSequence response wrong length: %d != %d\n",
|
||||
len, nbytes);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(tdo, buf, nbytes);
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: TdioSequence(%u, TMS=%c):\n", nbits, tms?'1':'0');
|
||||
debug_hexdump("\tTDI", tdi, nbytes);
|
||||
debug_hexdump("\tTDO", tdo, nbytes);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mehfet_cmd_tms_seq(transport_t t, uint32_t nbits, bool tdi, const uint8_t* tms) {
|
||||
if (!tms || !nbits) return -1;
|
||||
|
||||
int r;
|
||||
uint32_t nbytes = (nbits + 7) >> 3;
|
||||
uint8_t buf[(nbytes + 5) < 64 ? 64 : (nbytes + 5)]; // need min for recv
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) buf[i] = (nbits >> (i*8)) & 0xff;
|
||||
buf[4] = tdi ? 0xff : 0;
|
||||
memcpy(&buf[5], tms, nbytes);
|
||||
|
||||
r = mehfet_send_raw(t, mehfet_tdio_seq, sizeof buf, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf; // is a max len
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("TmsSequence", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != 0) {
|
||||
printc_err("mehfet: TmsSequence response wrong length: %d != 0\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: TmsSequence(%u, TDI=%c):\n", nbits, tdi?'1':'0');
|
||||
debug_hexdump("\tTMS", tms, nbytes);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mehfet_cmd_tclk_edge(transport_t t, bool newtclk) {
|
||||
uint8_t buf[64];
|
||||
int r;
|
||||
|
||||
buf[0] = newtclk ? 0xff : 0;
|
||||
r = mehfet_send_raw(t, mehfet_tclk_edge, 1, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("TclkEdge", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != 0) {
|
||||
printc_err("mehfet: TclkEdge response wrong length: %d != 0\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: TclkEdge(TCLK=%c)\n", newtclk?'H':'L');
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mehfet_cmd_tclk_burst(transport_t t, uint32_t ncyc) {
|
||||
uint8_t buf[64];
|
||||
int r;
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) buf[i] = (ncyc >> (i*8)) & 0xff;
|
||||
r = mehfet_send_raw(t, mehfet_tclk_burst, 4, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("TclkBurst", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != 0) {
|
||||
printc_err("mehfet: TclkBurst response wrong length: %d != 0\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: TclkBurst(ncyc=%u)\n", ncyc);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mehfet_cmd_reset_tap(transport_t t, enum mehfet_resettap_flags flags,
|
||||
enum mehfet_resettap_status* tstat) {
|
||||
if (!tstat) return -1;
|
||||
|
||||
uint8_t buf[64];
|
||||
int r;
|
||||
|
||||
buf[0] = flags;
|
||||
r = mehfet_send_raw(t, mehfet_reset_tap, 1, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("ResetTAP", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != 1) {
|
||||
printc_err("mehfet: ResetTAP response wrong length: %d != 1\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*tstat = buf[0];
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: ResetTAP(flags=0x%x) = 0x%x\n", flags, *tstat);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t bitswap_nyb(uint8_t in) {
|
||||
return ((in >> 3) & 1) | ((in >> 1) & 2) | ((in << 1) & 4) | ((in << 3) & 8);
|
||||
}
|
||||
static uint8_t bitswap(uint8_t in) {
|
||||
return (bitswap_nyb(in&0xf) << 4) | bitswap_nyb(in>>4);
|
||||
}
|
||||
|
||||
int mehfet_cmd_irshift(transport_t t, uint8_t newir, uint8_t* oldir) {
|
||||
if (!oldir) return -1;
|
||||
|
||||
// NOTE: jtaglib.c uses bitswapped IR values, while MehFET uses values from
|
||||
// the SLAU320 PDF, so we need to perform a bitswap here
|
||||
newir = bitswap(newir);
|
||||
|
||||
uint8_t buf[64];
|
||||
int r;
|
||||
|
||||
buf[0] = newir;
|
||||
r = mehfet_send_raw(t, mehfet_irshift, 1, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("IRshift", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != 1) {
|
||||
printc_err("mehfet: IRshift response wrong length: %d != 1\n", len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*oldir = buf[0];
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: IRshift(new=0x%02x) = 0x%02x\n", newir, *oldir);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
int mehfet_cmd_drshift(transport_t t, uint32_t nbits, const uint8_t* newdr, uint8_t* olddr) {
|
||||
if (!newdr || !olddr) return -1;
|
||||
|
||||
uint32_t nbytes = (nbits + 7) >> 3;
|
||||
uint8_t buf[(nbytes + 4) < 64 ? 64 : (nbytes + 4)];
|
||||
int r;
|
||||
|
||||
for (size_t i = 0; i < 4; ++i) buf[i] = (nbits >> (i * 8)) & 0xff;
|
||||
memcpy(&buf[4], newdr, nbytes);
|
||||
r = mehfet_send_raw(t, mehfet_drshift, nbytes + 4, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
uint8_t stat = 0;
|
||||
int len = sizeof buf;
|
||||
r = mehfet_recv_raw(t, &stat, &len, buf);
|
||||
if (r < 0) return r;
|
||||
r = mehfet_err_on_stat("DRshift", stat, len, buf);
|
||||
if (r < 0) return r;
|
||||
|
||||
if (len != (int)nbytes) {
|
||||
printc_err("mehfet: DRshift response wrong length: %d != %u\n", len, nbytes);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(olddr, buf, nbytes);
|
||||
|
||||
#ifdef DEBUG_MEHFET_PROTO_DRIVER
|
||||
printc_dbg("mehfet: DRshift(nbits=%u):\n", nbits);
|
||||
debug_hexdump("\tin ", newdr, nbytes);
|
||||
debug_hexdump("\tout", olddr, nbytes);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
/* MSPDebug - debugging tool for MSP430 MCUs
|
||||
* Copyright (C) 2021 sys64738@disroot.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MEHFET_PROTO_H_
|
||||
#define MEHFET_PROTO_H_
|
||||
|
||||
#include "transport.h"
|
||||
|
||||
#define MEHFET_PROTO_VER 0x0001
|
||||
#define MEHFET_PROTO_VER_MIN_SUPPORTED 0x0001
|
||||
|
||||
enum mehfet_cmd {
|
||||
mehfet_info = 0x01,
|
||||
mehfet_status = 0x02,
|
||||
mehfet_connect = 0x03,
|
||||
mehfet_disconnect = 0x04,
|
||||
mehfet_delay = 0x05,
|
||||
mehfet_set_clkspeed = 0x06,
|
||||
mehfet_get_old_lines = 0x07,
|
||||
mehfet_tdio_seq = 0x08,
|
||||
mehfet_tms_seq = 0x09,
|
||||
mehfet_tclk_edge = 0x0a,
|
||||
mehfet_tclk_burst = 0x0b,
|
||||
mehfet_reset_tap = 0x0c,
|
||||
mehfet_irshift = 0x0d,
|
||||
mehfet_drshift = 0x0e,
|
||||
};
|
||||
|
||||
enum mehfet_caps {
|
||||
mehfet_cap_jtag_noentry = 1<<0,
|
||||
mehfet_cap_jtag_entryseq = 1<<1,
|
||||
mehfet_cap_sbw_entryseq = 1<<2,
|
||||
|
||||
mehfet_cap_has_reset_tap = 1<< 8,
|
||||
mehfet_cap_has_irshift = 1<< 9,
|
||||
mehfet_cap_has_drshift = 1<<10,
|
||||
mehfet_cap_has_loop = 1<<11,
|
||||
};
|
||||
|
||||
enum mehfet_conn {
|
||||
mehfet_conn_none = 0,
|
||||
mehfet_conn_auto = 0,
|
||||
|
||||
mehfet_conn_jtag_noentry = 1,
|
||||
mehfet_conn_jtag_entryseq = 2,
|
||||
mehfet_conn_sbw_entryseq = 3,
|
||||
|
||||
mehfet_conn_typemask = 0x7f,
|
||||
mehfet_conn_nrstmask = 0x80
|
||||
};
|
||||
|
||||
enum mehfet_lines {
|
||||
mehfet_line_tclk = 1<<0,
|
||||
mehfet_line_tms = 1<<1,
|
||||
mehfet_line_tdi = 1<<2
|
||||
};
|
||||
|
||||
enum mehfet_resettap_flags {
|
||||
mehfet_rsttap_do_reset = 1<<0, // reset TAP to run-test/idle state
|
||||
mehfet_rsttap_fuse_do = 1<<1, // perform fuse check procedure (TMS pulses) on target
|
||||
mehfet_rsttap_fuse_read = 1<<2, // check whether the JTAG fuse has been blown
|
||||
};
|
||||
enum mehfet_resettap_status {
|
||||
mehfet_rsttap_fuse_blown = 0x80
|
||||
};
|
||||
|
||||
struct mehfet_info {
|
||||
char* devicename;
|
||||
enum mehfet_caps caps;
|
||||
uint32_t packet_buf_size;
|
||||
uint16_t proto_version;
|
||||
};
|
||||
|
||||
|
||||
int mehfet_cmd_info(transport_t t, struct mehfet_info* info);
|
||||
int mehfet_cmd_status(transport_t t, enum mehfet_conn* stat);
|
||||
int mehfet_cmd_connect(transport_t t, enum mehfet_conn conn);
|
||||
int mehfet_cmd_disconnect(transport_t t);
|
||||
int mehfet_cmd_delay(transport_t t, bool us, bool exact, uint32_t time);
|
||||
int mehfet_cmd_set_clkspeed(transport_t t, bool fast);
|
||||
int mehfet_cmd_get_old_lines(transport_t t, enum mehfet_lines* lines);
|
||||
|
||||
int mehfet_cmd_tdio_seq(transport_t t, uint32_t nbits, bool tms, const uint8_t* tdi, uint8_t* tdo);
|
||||
int mehfet_cmd_tms_seq(transport_t t, uint32_t nbits, bool tdi, const uint8_t* tms);
|
||||
int mehfet_cmd_tclk_edge(transport_t t, bool newtclk);
|
||||
int mehfet_cmd_tclk_burst(transport_t t, uint32_t ncyc);
|
||||
|
||||
int mehfet_cmd_reset_tap(transport_t t, enum mehfet_resettap_flags flags, enum mehfet_resettap_status* stat);
|
||||
int mehfet_cmd_irshift(transport_t t, uint8_t newir, uint8_t* oldir);
|
||||
int mehfet_cmd_drshift(transport_t t, uint32_t nbits, const uint8_t* newdr, uint8_t* olddr);
|
||||
|
||||
#endif
|
||||
|
|
@ -144,43 +144,6 @@ static int init_device(struct jtdev *p)
|
|||
|
||||
/*===== MSPDebug Device interface ============================================*/
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int refresh_bps(struct pif_device *dev)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
struct device_breakpoint *bp;
|
||||
address_t addr;
|
||||
ret = 0;
|
||||
|
||||
for (i = 0; i < dev->base.max_breakpoints; i++) {
|
||||
bp = &dev->base.breakpoints[i];
|
||||
|
||||
printc_dbg("refresh breakpoint %d: type=%d "
|
||||
"addr=%04x flags=%04x\n",
|
||||
i, bp->type, bp->addr, bp->flags);
|
||||
|
||||
if ( (bp->flags & DEVICE_BP_DIRTY) &&
|
||||
(bp->type == DEVICE_BPTYPE_BREAK) ) {
|
||||
addr = bp->addr;
|
||||
|
||||
if ( !(bp->flags & DEVICE_BP_ENABLED) ) {
|
||||
addr = 0;
|
||||
}
|
||||
|
||||
if ( jtag_set_breakpoint (&dev->jtag, i, addr) == 0) {
|
||||
printc_err("pif: failed to refresh "
|
||||
"breakpoint #%d\n", i);
|
||||
ret = -1;
|
||||
} else {
|
||||
bp->flags &= ~DEVICE_BP_DIRTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
static int pif_readmem( device_t dev_base,
|
||||
address_t addr,
|
||||
|
@ -246,7 +209,7 @@ static int pif_ctl(device_t dev_base, device_ctl_t type)
|
|||
|
||||
case DEVICE_CTL_RUN:
|
||||
/* transfer changed breakpoints to device */
|
||||
if (refresh_bps(dev) < 0) {
|
||||
if (jtag_refresh_bps("pif", &dev->base, &dev->jtag) < 0) {
|
||||
return -1;
|
||||
}
|
||||
/* start program execution at current PC */
|
||||
|
|
14
mspdebug.man
14
mspdebug.man
|
@ -52,6 +52,10 @@ section \fBDRIVERS\fR below for details.
|
|||
.IP "\-U \fIbus\fR:\fIdevice\fR"
|
||||
Specify a particular USB device to connect to. Without this option,
|
||||
the first device of the appropriate type is opened.
|
||||
.IP "\-V \fIvid\fR:\fIpid\fR"
|
||||
Specify a VID and PID of the USB device to connect to, or override the
|
||||
default VID and PID. Some drives, such as \fBmehfet\fR, require this option,
|
||||
while others have a default VID and PID which can be overridden.
|
||||
.IP "\-s \fIserial\fR"
|
||||
Specify a particular USB device serial number to connect to. Use this
|
||||
option to distinguish between multiple devices of the same type.
|
||||
|
@ -230,6 +234,13 @@ There are reports of this operation causing an erase of info A in some
|
|||
devices. Use at your own risk.
|
||||
.IP "\fBbus-pirate\fR"
|
||||
Raw JTAG using Bus Pirate devices.
|
||||
.IP "\fBmehfet\fR"
|
||||
Connect to a MehFET USB-based debugging protocol-capable device. It can
|
||||
support both JTAG and Spy-Bi-Wire. For now, only 16-bit CPUs (that is,
|
||||
non-430X or Xv2) are suppored, as with the \fBpif\fR, \fBgpio\fR,
|
||||
\fBbus-pirate\fR and \fBgoodfet\fR rivers.
|
||||
|
||||
For documentation on the USB protocol, see the \fBSEE ALSO\fR section.
|
||||
.SH COMMANDS
|
||||
MSPDebug can accept commands either through an interactive prompt, or
|
||||
non-interactively when specified on the command line. The supported
|
||||
|
@ -826,6 +837,9 @@ Firmware image for the TI3410 USB interface chip. This file is only
|
|||
required for raw USB access to FET430UIF or eZ430 devices.
|
||||
.SH SEE ALSO
|
||||
\fBnm\fR(1), \fBgdb\fR(1), \fBobjcopy\fR(1)
|
||||
|
||||
\fBmehfet\fR protocol documentation can be found at the following URL:
|
||||
https://git.lain.faith/sys64738/DragonProbe/wiki/MehFET-USB-protocol
|
||||
.SH BUGS
|
||||
If you find any bugs, you should report them to the author at
|
||||
dlbeer@gmail.com. It would help if you could include a transcript
|
||||
|
|
|
@ -0,0 +1,407 @@
|
|||
/* MSPDebug - debugging tool for MSP430 MCUs
|
||||
* Copyright (C) 2021 sys64738@disroot.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mehfet_xport.h"
|
||||
#include "util.h"
|
||||
#include "usbutil.h"
|
||||
#include "output.h"
|
||||
|
||||
struct mehfet_transport {
|
||||
struct transport base;
|
||||
struct usb_dev_handle *handle;
|
||||
int epin, epout;
|
||||
int buf_size;
|
||||
};
|
||||
|
||||
|
||||
#define TIMEOUT_S 30
|
||||
#define REQ_TIMEOUT_MS 100
|
||||
|
||||
|
||||
static int open_device(struct mehfet_transport *tr, struct usb_device *dev)
|
||||
{
|
||||
#ifdef __linux__
|
||||
int driver;
|
||||
char drv_name[128];
|
||||
#endif
|
||||
|
||||
// first, find the right interface (and associated endpoints) of the USB device
|
||||
|
||||
int config = 0, itf = 0;
|
||||
bool has = false;
|
||||
|
||||
for (config = 0; config < dev->descriptor.bNumConfigurations; ++config) {
|
||||
struct usb_config_descriptor* cd = &dev->config[config];
|
||||
|
||||
for (itf = 0; itf < cd->bNumInterfaces; ++itf) {
|
||||
struct usb_interface_descriptor* id = &cd->interface[itf].altsetting[0];
|
||||
|
||||
if (id->bInterfaceClass == USB_CLASS_VENDOR_SPEC
|
||||
&& id->bInterfaceSubClass == '4'
|
||||
&& id->bInterfaceProtocol == '3') {
|
||||
// here I'd like to check for the "MehFET" substring in the
|
||||
// interface's iInterface string, but I can't really figure out
|
||||
// how to do that, so I'll just assume this is enough checking.
|
||||
|
||||
if (id->bNumEndpoints != 2) continue; // this should be 2
|
||||
for (size_t i = 0; i < id->bNumEndpoints; ++i) {
|
||||
struct usb_endpoint_descriptor* ed = &id->endpoint[i];
|
||||
|
||||
if ((ed->bmAttributes & USB_ENDPOINT_TYPE_MASK)
|
||||
!= USB_ENDPOINT_TYPE_BULK)
|
||||
break;
|
||||
|
||||
if (ed->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
|
||||
tr->epin = ed->bEndpointAddress; // input endpoint
|
||||
else
|
||||
tr->epout = ed->bEndpointAddress; // output endpoint
|
||||
}
|
||||
|
||||
if (tr->epin != 0 && tr->epout != 0) {
|
||||
has = true;
|
||||
goto break_outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break_outer:
|
||||
|
||||
if (!has) {
|
||||
printc_err("mehfet transport: USB device %s has no MehFET interface.\n",
|
||||
dev->filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printc_dbg("mehfet transport: trying to open %s\n", dev->filename);
|
||||
tr->handle = usb_open(dev);
|
||||
if (!tr->handle) {
|
||||
printc_err("mehfet transport: can't open device: %s\n",
|
||||
usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
driver = usb_get_driver_np(tr->handle, itf, drv_name, sizeof(drv_name));
|
||||
if (driver >= 0) {
|
||||
printc_dbg("Detaching kernel driver \"%s\"\n", drv_name);
|
||||
if (usb_detach_kernel_driver_np(tr->handle, itf) < 0)
|
||||
printc_err("warning: mehfet transport: can't detach "
|
||||
"kernel driver: %s\n", usb_strerror());
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __Windows__
|
||||
if (usb_set_configuration(tr->handle, config) < 0) {
|
||||
printc_err("mehfet transport: can't set configuration: %s\n",
|
||||
usb_strerror());
|
||||
usb_close(tr->handle);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (usb_claim_interface(tr->handle, itf) < 0) {
|
||||
printc_err("mehfet transport: can't claim interface: %s\n",
|
||||
usb_strerror());
|
||||
usb_close(tr->handle);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tr_destroy(transport_t tr_base)
|
||||
{
|
||||
struct mehfet_transport *tr = (struct mehfet_transport *)tr_base;
|
||||
|
||||
usb_close(tr->handle);
|
||||
free(tr);
|
||||
}
|
||||
|
||||
static int tr_recv(transport_t tr_base, uint8_t *databuf, int max_len)
|
||||
{
|
||||
struct mehfet_transport *tr = (struct mehfet_transport *)tr_base;
|
||||
time_t deadline = time(NULL) + TIMEOUT_S;
|
||||
char tmpbuf[tr->buf_size];
|
||||
|
||||
if (max_len > tr->buf_size)
|
||||
max_len = tr->buf_size;
|
||||
|
||||
while (time(NULL) < deadline) {
|
||||
int r = usb_bulk_read(tr->handle, tr->epin,
|
||||
tmpbuf, max_len,
|
||||
TIMEOUT_S * 1000);
|
||||
|
||||
if (r <= 0) {
|
||||
printc_err("mehfet transport: usb_bulk_read: %s\n",
|
||||
usb_strerror());
|
||||
asm volatile("int3");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(databuf, tmpbuf, r);
|
||||
#ifdef DEBUG_MEHFET_TRANSPORT
|
||||
printc_dbg("mehfet transport: tr_recv: flags = %02x %02x\n",
|
||||
tmpbuf[0], tmpbuf[1]);
|
||||
debug_hexdump("mehfet transport: tr_recv", databuf, r);
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
printc_err("mehfet transport: timed out while receiving data\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int tr_send(transport_t tr_base, const uint8_t *databuf, int len)
|
||||
{
|
||||
struct mehfet_transport *tr = (struct mehfet_transport *)tr_base;
|
||||
|
||||
#ifdef DEBUG_MEHFET
|
||||
debug_hexdump("mehfet transport: tr_send", databuf, len);
|
||||
#endif
|
||||
while (len) {
|
||||
int r = usb_bulk_write(tr->handle, tr->epout,
|
||||
(char *)databuf, len,
|
||||
TIMEOUT_S * 1000);
|
||||
|
||||
if (r <= 0) {
|
||||
printc_err("mehfet transport: usb_bulk_write: %s\n",
|
||||
usb_strerror());
|
||||
return -1;
|
||||
}
|
||||
|
||||
databuf += r;
|
||||
len -= r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tr_flush(transport_t tr_base)
|
||||
{
|
||||
(void)tr_base;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tr_set_modem(transport_t tr_base, transport_modem_t state)
|
||||
{
|
||||
(void)tr_base; (void)state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct transport_class mehfet_class = {
|
||||
.destroy = tr_destroy,
|
||||
.send = tr_send,
|
||||
.recv = tr_recv,
|
||||
.flush = tr_flush,
|
||||
.set_modem = tr_set_modem
|
||||
};
|
||||
|
||||
transport_t mehfet_transport_open(const char *devpath,
|
||||
const uint16_t* vendor, const uint16_t* product,
|
||||
const char *requested_serial)
|
||||
{
|
||||
struct mehfet_transport *tr = malloc(sizeof(*tr));
|
||||
struct usb_device *dev = NULL;
|
||||
|
||||
if (!tr) {
|
||||
pr_error("mehfet transport: can't allocate memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tr->base.ops = &mehfet_class;
|
||||
|
||||
usb_init();
|
||||
usb_find_busses();
|
||||
usb_find_devices();
|
||||
|
||||
if (devpath)
|
||||
dev = usbutil_find_by_loc(devpath);
|
||||
else if (vendor && product)
|
||||
dev = usbutil_find_by_id(*vendor, *product, requested_serial);
|
||||
|
||||
if (!dev) {
|
||||
printc_err("mehfet: no USB device found.%s\n",
|
||||
vendor ? "" : " (Did you forget to specify a VID:PID?)");
|
||||
free(tr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tr->buf_size = 64; // initial conservative value, will get updated later
|
||||
|
||||
if (open_device(tr, dev) < 0) {
|
||||
printc_err("mehfet: failed to open device\n");
|
||||
free(tr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &tr->base;
|
||||
}
|
||||
|
||||
|
||||
void mehfet_transport_set_buf_size(transport_t tr_base, int buf_size)
|
||||
{
|
||||
struct mehfet_transport *tr = (struct mehfet_transport *)tr_base;
|
||||
|
||||
tr->buf_size = buf_size;
|
||||
}
|
||||
int mehfet_transport_get_buf_size(transport_t tr_base)
|
||||
{
|
||||
struct mehfet_transport *tr = (struct mehfet_transport *)tr_base;
|
||||
|
||||
return tr->buf_size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int mehfet_send_raw(transport_t xport, uint8_t cmd, int datalen, const void* data) {
|
||||
if (datalen < 0) return -1;
|
||||
if (data && !datalen) return -1;
|
||||
if (!data && datalen) return -1;
|
||||
|
||||
uint8_t buf[1+4+datalen];
|
||||
|
||||
buf[0] = cmd;
|
||||
int i, len2;
|
||||
for (i = 0, len2 = datalen; i < 4 && len2; ++i, len2 >>= 7) {
|
||||
buf[0] |= 0x80; // command has payload data
|
||||
|
||||
if (i == 3) {
|
||||
buf[i+1] = len2;
|
||||
} else {
|
||||
buf[i+1] = len2 & 0x7f;
|
||||
if (len2 >> 7) buf[i+1] |= 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
if (data && datalen) memcpy(&buf[i+1], data, datalen);
|
||||
|
||||
return xport->ops->send(xport, buf, datalen + 1 + i);
|
||||
}
|
||||
|
||||
int mehfet_recv_raw(transport_t xport, uint8_t* stat, int* datalen, void* data) {
|
||||
struct mehfet_transport *tr = (struct mehfet_transport *)xport;
|
||||
uint8_t rawbuf[tr->buf_size];
|
||||
|
||||
int nmax = 5, ndata = 0, nfetch;
|
||||
if (datalen) {
|
||||
ndata = *datalen;
|
||||
nmax = ndata + 5;
|
||||
}
|
||||
nfetch = nmax;
|
||||
if (nmax > tr->buf_size) {
|
||||
nmax = tr->buf_size;
|
||||
/*printc_err("mehfet transport: bug: asking for more data (%d) than "
|
||||
"in the device buffer size (%d)\n", nmax, tr->buf_size);
|
||||
return -1;*/
|
||||
}
|
||||
|
||||
int r = xport->ops->recv(xport, rawbuf, nfetch);
|
||||
if (r < 0) return r;
|
||||
if (r < 1) {
|
||||
printc_err("mehfet transport: no status byte received\n");
|
||||
return -1;
|
||||
}
|
||||
assert(r <= nfetch);
|
||||
|
||||
uint8_t statv = rawbuf[0];
|
||||
|
||||
uint32_t reallen = 0;
|
||||
uint8_t lastbyte = statv;
|
||||
int i;
|
||||
for (i = 0; i < 4 && (lastbyte & 0x80) /*&& i + 1 < r*/; ++i) {
|
||||
if (r < i + 2) {
|
||||
printc_err("mehfet transport: not enough lenght bytes received (%d)\n", r);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lastbyte = rawbuf[i + 1];
|
||||
|
||||
uint8_t mask = (i == 3) ? 0xff : 0x7f;
|
||||
reallen |= (lastbyte & mask) << (i * 7);
|
||||
}
|
||||
|
||||
if ((int)reallen > nmax && data) {
|
||||
printc_err("mehfet transport: too much data returned (%d vs %d)\n",
|
||||
(int)reallen, nmax);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nrecvdata = r - 1 - i;
|
||||
assert(nrecvdata >= 0);
|
||||
|
||||
if (nrecvdata && data) memcpy(data, &rawbuf[i+1], nrecvdata);
|
||||
// now we can use rawbuf for other purposes
|
||||
|
||||
int off = r;
|
||||
int ntodo = (int)reallen - nrecvdata;
|
||||
while (ntodo > 0) { // more data bytes following in this logical packet
|
||||
int thisblock = tr->buf_size;
|
||||
if (thisblock > ntodo) thisblock = ntodo;
|
||||
|
||||
r = xport->ops->recv(xport, rawbuf, thisblock);
|
||||
if (r < 0) return r;
|
||||
assert(r < thisblock);
|
||||
|
||||
memcpy(&((char*)data)[off], rawbuf, thisblock);
|
||||
ntodo -= r;
|
||||
off += r;
|
||||
}
|
||||
|
||||
if (stat) *stat = statv & 0x7f;
|
||||
if (datalen) *datalen = (int)reallen;
|
||||
|
||||
return (int)reallen;
|
||||
}
|
||||
|
||||
int mehfet_err_on_stat(const char* pre, uint8_t stat, int datalen, const void* data) {
|
||||
if (stat == mehfet_ok) return 0;
|
||||
|
||||
const char* d = (const char*)data;
|
||||
switch (stat) {
|
||||
case mehfet_badargs:
|
||||
printc_err("mehfet: %s: %s\n", pre,
|
||||
datalen ? d : "bad argument sent to command");
|
||||
break;
|
||||
case mehfet_nocaps:
|
||||
printc_err("mehfet: %s: %s\n", pre,
|
||||
datalen ? d : "device doesn't have the command capability");
|
||||
break;
|
||||
case mehfet_badstate:
|
||||
printc_err("mehfet: %s: %s\n", pre,
|
||||
datalen ? d : "device in wrong state to execute command");
|
||||
break;
|
||||
case mehfet_invalidcmd:
|
||||
printc_err("mehfet: %s: %s\n", pre,
|
||||
datalen ? d : "invalid command");
|
||||
break;
|
||||
case mehfet_error:
|
||||
printc_err("mehfet: %s: %s\n", pre, datalen ? d : "unspecified error");
|
||||
break;
|
||||
default:
|
||||
printc_err("mehfet: %s: unknown error %hhu\n", pre, stat);
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/* MSPDebug - debugging tool for MSP430 MCUs
|
||||
* Copyright (C) 2021 sys64738@disroot.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef MEHFET_TRANSPORT_H_
|
||||
#define MEHFET_TRANSPORT_H_
|
||||
|
||||
#include "transport.h"
|
||||
|
||||
enum mehfet_status {
|
||||
mehfet_ok = 0x00,
|
||||
|
||||
mehfet_badargs = 0x7b,
|
||||
mehfet_nocaps = 0x7c,
|
||||
mehfet_badstate = 0x7d,
|
||||
mehfet_invalidcmd = 0x7e,
|
||||
mehfet_error = 0x7f
|
||||
};
|
||||
|
||||
|
||||
/* Search the USB bus for the first MehFET device and initialize it.
|
||||
* If successful, return a transport object. Otherwise, return NULL.
|
||||
*
|
||||
* A particular USB device or serial number may be specified.
|
||||
*/
|
||||
transport_t mehfet_transport_open(const char *usb_device,
|
||||
const uint16_t* vendor, const uint16_t* product,
|
||||
const char *requested_serial);
|
||||
|
||||
int mehfet_transport_get_buf_size(transport_t xport);
|
||||
void mehfet_transport_set_buf_size(transport_t xport, int buf_size);
|
||||
|
||||
int mehfet_send_raw(transport_t xport, uint8_t cmd, int datalen, const void* data);
|
||||
int mehfet_recv_raw(transport_t xport, uint8_t* stat, int* datalen, void* data);
|
||||
|
||||
int mehfet_err_on_stat(const char* pre, uint8_t stat, int datalen, const void* data);
|
||||
|
||||
#endif
|
|
@ -228,7 +228,8 @@ static const struct transport_class rf2500_transport = {
|
|||
.set_modem = usbtr_set_modem
|
||||
};
|
||||
|
||||
transport_t rf2500_open(const char *devpath, const char *requested_serial)
|
||||
transport_t rf2500_open(const char *devpath, const char *requested_serial,
|
||||
int has_vid_pid, uint16_t vid, uint16_t pid)
|
||||
{
|
||||
struct rf2500_transport *tr = malloc(sizeof(*tr));
|
||||
struct usb_device *dev;
|
||||
|
@ -248,7 +249,8 @@ transport_t rf2500_open(const char *devpath, const char *requested_serial)
|
|||
if (devpath)
|
||||
dev = usbutil_find_by_loc(devpath);
|
||||
else
|
||||
dev = usbutil_find_by_id(USB_FET_VENDOR, USB_FET_PRODUCT,
|
||||
dev = usbutil_find_by_id(has_vid_pid ? vid : USB_FET_VENDOR,
|
||||
has_vid_pid ? pid : USB_FET_PRODUCT,
|
||||
requested_serial);
|
||||
|
||||
if (!dev) {
|
||||
|
|
|
@ -27,7 +27,9 @@
|
|||
*
|
||||
* A particular device may be specified in bus:dev form.
|
||||
*/
|
||||
transport_t rf2500_open(const char *dev_path, const char *requested_serial);
|
||||
transport_t rf2500hidapi_open(const char *dev_path, const char *requested_serial);
|
||||
transport_t rf2500_open(const char *dev_path, const char *requested_serial,
|
||||
int has_vid_pid, uint16_t vid, uint16_t pid);
|
||||
transport_t rf2500hidapi_open(const char *dev_path, const char *requested_serial,
|
||||
int has_vid_pid, uint16_t vid, uint16_t pid);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -161,7 +161,8 @@ static const wchar_t * get_wc(const char *c)
|
|||
return wc;
|
||||
}
|
||||
|
||||
transport_t rf2500hidapi_open(const char *devpath, const char *requested_serial)
|
||||
transport_t rf2500hidapi_open(const char *devpath, const char *requested_serial,
|
||||
int has_vid_pid, uint16_t vid, uint16_t pid)
|
||||
{
|
||||
struct rf2500_transport *tr = malloc(sizeof(*tr));
|
||||
hid_device *handle;
|
||||
|
@ -186,7 +187,8 @@ transport_t rf2500hidapi_open(const char *devpath, const char *requested_serial)
|
|||
} else {
|
||||
wc_serial = NULL;
|
||||
}
|
||||
handle = hid_open(USB_FET_VENDOR, USB_FET_PRODUCT, wc_serial);
|
||||
handle = hid_open(has_vid_pid ? vid : USB_FET_VENDOR,
|
||||
has_vid_pid ? pid : USB_FET_PRODUCT, wc_serial);
|
||||
if ( wc_serial ) {
|
||||
free((wchar_t *)wc_serial);
|
||||
}
|
||||
|
|
|
@ -559,7 +559,8 @@ static const struct transport_class ti3410_transport = {
|
|||
.set_modem = ti3410_set_modem
|
||||
};
|
||||
|
||||
transport_t ti3410_open(const char *devpath, const char *requested_serial)
|
||||
transport_t ti3410_open(const char *devpath, const char *requested_serial,
|
||||
int has_vid_pid, uint16_t vid, uint16_t pid)
|
||||
{
|
||||
struct ti3410_transport *tr = malloc(sizeof(*tr));
|
||||
struct usb_device *dev;
|
||||
|
@ -578,7 +579,8 @@ transport_t ti3410_open(const char *devpath, const char *requested_serial)
|
|||
if (devpath)
|
||||
dev = usbutil_find_by_loc(devpath);
|
||||
else
|
||||
dev = usbutil_find_by_id(USB_FET_VENDOR, USB_FET_PRODUCT,
|
||||
dev = usbutil_find_by_id(has_vid_pid ? vid : USB_FET_VENDOR,
|
||||
has_vid_pid ? pid : USB_FET_PRODUCT,
|
||||
requested_serial);
|
||||
|
||||
if (!dev) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
/* This function is for opening an eZ430-F2013 or FET430UIF device via
|
||||
* libusb.
|
||||
*/
|
||||
transport_t ti3410_open(const char *dev_path, const char *requested_serial);
|
||||
transport_t ti3410_open(const char *dev_path, const char *requested_serial,
|
||||
int has_vid_pid, uint16_t vid, uint16_t pid);
|
||||
|
||||
#endif
|
||||
|
|
21
ui/main.c
21
ui/main.c
|
@ -58,6 +58,7 @@
|
|||
#include "fet3.h"
|
||||
#include "rom_bsl.h"
|
||||
#include "chipinfo.h"
|
||||
#include "mehfet.h"
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
#include <sys/cygwin.h>
|
||||
|
@ -92,7 +93,8 @@ static const struct device_class *const driver_table[] = {
|
|||
&device_loadbsl,
|
||||
&device_ezfet,
|
||||
&device_rom_bsl,
|
||||
&device_bp
|
||||
&device_bp,
|
||||
&device_mehfet,
|
||||
};
|
||||
|
||||
static const char *version_text =
|
||||
|
@ -114,6 +116,9 @@ static void usage(const char *progname)
|
|||
" Connect via the given tty device, rather than USB.\n"
|
||||
" -U bus:dev\n"
|
||||
" Specify a particular USB device to connect to.\n"
|
||||
" -V vid:pid\n"
|
||||
" Specify a particular vid:pid par of a USB to connect to, instead of\n"
|
||||
" a driver-specific default.\n"
|
||||
" -s serial\n"
|
||||
" Specify a particular device serial number to connect to.\n"
|
||||
" -j\n"
|
||||
|
@ -328,7 +333,7 @@ static int parse_cmdline_args(int argc, char **argv,
|
|||
int opt;
|
||||
int want_usb = 0;
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "d:jv:nU:s:qC:",
|
||||
while ((opt = getopt_long(argc, argv, "d:jv:nUV:s:qC:",
|
||||
longopts, NULL)) >= 0)
|
||||
switch (opt) {
|
||||
case 'C':
|
||||
|
@ -398,6 +403,18 @@ static int parse_cmdline_args(int argc, char **argv,
|
|||
want_usb = 1;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
// optarg is in "vid:pid" format, which we now need to parse
|
||||
if (sscanf(optarg, "%04hx:%04hx", &args->devarg.vid, &args->devarg.pid) == 2) {
|
||||
args->devarg.flags |= DEVICE_FLAG_HAS_VID_PID;
|
||||
want_usb = 1;
|
||||
} else {
|
||||
printc("Invalid -V option specified: %s."
|
||||
"Format should be '<vid>:<pid>'\n", optarg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
args->devarg.requested_serial = optarg;
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue