Compare commits

...

10 Commits

25 changed files with 1961 additions and 116 deletions

2
.gitignore vendored
View File

@ -2,3 +2,5 @@
*.o
mspdebug
mspdebug.exe
inst/
config.mk

View File

@ -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 \

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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
};

View File

@ -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;

View File

@ -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
};

View File

@ -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
};

639
drivers/mehfet.c Normal file
View File

@ -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
};

27
drivers/mehfet.h Normal file
View File

@ -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

473
drivers/mehfet_proto.c Normal file
View File

@ -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;
}

108
drivers/mehfet_proto.h Normal file
View File

@ -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

View File

@ -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 */

View File

@ -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

407
transport/mehfet_xport.c Normal file
View File

@ -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;
}

52
transport/mehfet_xport.h Normal file
View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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);
}

View File

@ -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) {

View File

@ -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

View File

@ -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;