mehfet boilerplate, also fix bug in VID/PID stuff

This commit is contained in:
Triss 2021-10-05 22:00:06 +02:00
parent 7ef085140a
commit 00f11cd9d7
12 changed files with 1254 additions and 16 deletions

View File

@ -173,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) \
@ -196,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

@ -365,7 +365,7 @@ static device_t bsl_open(const struct device_args *args)
dev->serial = comport_open(args->path, 460800);
else
dev->serial = ti3410_open(args->path, args->requested_serial,
args->has_vid_pid, args->vid, args->pid);
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
if (!dev->serial) {
free(dev);

View File

@ -90,7 +90,6 @@ struct device_args {
int bsl_gpio_dtr;
uint8_t bsl_entry_password[32];
uint16_t vid, pid;
int has_vid_pid;
};
struct device_class {

View File

@ -45,10 +45,10 @@ static device_t fet_open_rf2500(const struct device_args *args)
#if defined(__APPLE__)
trans = rf2500hidapi_open(args->path, args->requested_serial,
args->has_vid_pid, args->vid, args->pid);
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
#else
trans = rf2500_open(args->path, args->requested_serial,
args->has_vid_pid, args->vid, args->pid);
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
#endif
if (!trans)
return NULL;
@ -82,8 +82,8 @@ 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,
args->has_vid_pid ? args->vid : 0x15ba,
args->has_vid_pid ? args->pid : 0x0100);
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0100);
if (!trans)
return NULL;
@ -105,8 +105,8 @@ static device_t fet_open_olimex_iso_mk2(const struct device_args *args)
else
trans = cdc_acm_open(args->path,
args->requested_serial, 115200,
args->has_vid_pid ? args->vid : 0x15ba,
args->has_vid_pid ? args->pid : 0x0100);
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0100);
if (!trans)
return NULL;
@ -146,8 +146,8 @@ static device_t fet_open_olimex(const struct device_args *args)
trans = comport_open(args->path, 115200);
else
trans = cdc_acm_open(args->path, args->requested_serial, 115200,
args->has_vid_pid ? args->vid : 0x15ba,
args->has_vid_pid ? args->pid : 0x0031);
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0031);
if (!trans)
return NULL;
@ -183,8 +183,8 @@ static device_t fet_open_olimex_v1(const struct device_args *args)
trans = comport_open(args->path, 500000);
else
trans = cp210x_open(args->path, args->requested_serial, 500000,
args->has_vid_pid ? args->vid : 0x15ba,
args->has_vid_pid ? args->pid : 0x0002);
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->vid : 0x15ba,
(args->flags & DEVICE_FLAG_HAS_VID_PID) ? args->pid : 0x0002);
if (!trans)
return NULL;
@ -219,8 +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,
args->has_vid_pid ? args->vid : 0x15ba,
args->has_vid_pid ? args->pid : 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;
@ -256,7 +257,7 @@ static device_t fet_open_uif(const struct device_args *args)
trans = comport_open(args->path, 460800);
else
trans = ti3410_open(args->path, args->requested_serial,
args->has_vid_pid, args->vid, args->pid);
(args->flags & DEVICE_FLAG_HAS_VID_PID), args->vid, args->pid);
if (!trans)
return NULL;

View File

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

208
drivers/mehfet.c Normal file
View File

@ -0,0 +1,208 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "output.h"
#include "ctrlc.h"
#include "mehfet_proto.h"
#include "mehfet_xport.h"
#include "mehfet.h"
struct mehfet_device {
struct device base;
transport_t trans;
enum mehfet_conn connstat;
};
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 void mehfet_destroy(device_t dev_base) {
struct mehfet_device* dev = (struct mehfet_device*)dev_base;
if (dev->trans) {
dev->trans->ops->destroy(dev->trans);
dev->trans = NULL;
}
// TODO:
// * release device (POR?)
// * Disconnect
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
// 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;
}
// TODO:
// * GetDevice stuff
//
// => TODO: slau320 routines!
return (device_t)dev;
FAIL:
mehfet_destroy((device_t)dev);
return NULL;
}
static int mehfet_readmem(device_t dev_base, address_t addr,
uint8_t *mem, address_t len)
{
return -1;
}
static int mehfet_writemem(device_t dev_base, address_t addr,
const uint8_t *mem, address_t len)
{
return -1;
}
static int mehfet_setregs(device_t dev_base, const address_t *regs)
{
(void)dev_base;
(void)regs;
return -1;
}
static int mehfet_getregs(device_t dev_base, address_t *regs)
{
(void)dev_base;
(void)regs;
return -1;
}
static int mehfet_ctl(device_t dev_base, device_ctl_t type)
{
return -1;
}
static device_status_t mehfet_poll(device_t dev_base)
{
return DEVICE_STATUS_RUNNING;
}
static int mehfet_erase(device_t dev_base, device_erase_type_t type,
address_t addr)
{
return -1;
}
static int mehfet_getconfigfuses(device_t dev_base)
{
return -1;
}
const struct device_class device_mehfet = {
.name = "mehfet",
.help = "MehFET USB 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

444
drivers/mehfet_proto.c Normal file
View File

@ -0,0 +1,444 @@
#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_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_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_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_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_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_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_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_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_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_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_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_DRIVER
printc_dbg("mehfet: ResetTAP(flags=0x%x) = 0x%x\n", flags, *tstat);
#endif
return 0;
}
int mehfet_cmd_irshift(transport_t t, uint8_t newir, uint8_t* oldir) {
if (!oldir) return -1;
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_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_DRIVER
printc_dbg("mehfet: IRshift(nbits=%u):\n", nbits);
debug_hexdump("\tin ", newdr, nbytes);
debug_hexdump("\tout", olddr, nbytes);
#endif
return 0;
}

95
drivers/mehfet_proto.h Normal file
View File

@ -0,0 +1,95 @@
#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,
mehfet_loop = 0x0f,
};
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);
// TODO: Loop
#endif

406
transport/mehfet_xport.c Normal file
View File

@ -0,0 +1,406 @@
/* 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());
return -1;
}
if (r > 2) {
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) {
free(tr);
return NULL;
}
tr->buf_size = 64; // initial conservative value, will get updated later
if (open_device(tr, dev) < 0) {
printc_err("ftdi: 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

@ -58,6 +58,7 @@
#include "fet3.h"
#include "rom_bsl.h"
#include "chipinfo.h"
#include "mehfet.h"
#ifdef __CYGWIN__
#include <sys/cygwin.h>
@ -93,6 +94,7 @@ static const struct device_class *const driver_table[] = {
&device_ezfet,
&device_rom_bsl,
&device_bp,
&device_mehfet,
};
static const char *version_text =