Add a bus pirate driver.
This is extremely slow at programming things, but is very useful for unbricking an MSP-FET430UIF if you have a bus pirate and no other programmers around.
This commit is contained in:
parent
8a1afe6c91
commit
682d7ecc9c
1
Makefile
1
Makefile
|
@ -176,6 +176,7 @@ OBJ=\
|
||||||
drivers/devicelist.o \
|
drivers/devicelist.o \
|
||||||
drivers/fet_olimex_db.o \
|
drivers/fet_olimex_db.o \
|
||||||
drivers/jtdev.o \
|
drivers/jtdev.o \
|
||||||
|
drivers/jtdev_bus_pirate.o \
|
||||||
drivers/jtdev_gpio.o \
|
drivers/jtdev_gpio.o \
|
||||||
drivers/jtaglib.o \
|
drivers/jtaglib.o \
|
||||||
drivers/pif.o \
|
drivers/pif.o \
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
|
|
||||||
#ifndef JTDEV_H_
|
#ifndef JTDEV_H_
|
||||||
#define JTDEV_H_
|
#define JTDEV_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
struct jtdev_func;
|
struct jtdev_func;
|
||||||
struct jtdev {
|
struct jtdev {
|
||||||
int port;
|
int port;
|
||||||
|
@ -65,5 +68,6 @@ struct jtdev_func{
|
||||||
|
|
||||||
extern const struct jtdev_func jtdev_func_pif;
|
extern const struct jtdev_func jtdev_func_pif;
|
||||||
extern const struct jtdev_func jtdev_func_gpio;
|
extern const struct jtdev_func jtdev_func_gpio;
|
||||||
|
extern const struct jtdev_func jtdev_func_bp;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,356 @@
|
||||||
|
/* MSPDebug - debugging tool for MSP430 MCUs
|
||||||
|
* Copyright (C) 2009-2012 Daniel Beer
|
||||||
|
* Copyright (C) 2012 Peter Bägel
|
||||||
|
*
|
||||||
|
* ppdev/ppi abstraction inspired by uisp src/DARPA.C
|
||||||
|
* originally written by Sergey Larin;
|
||||||
|
* corrected by Denis Chertykov, Uros Platise and Marek Michalkiewicz.
|
||||||
|
*
|
||||||
|
* 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 <stdint.h>
|
||||||
|
#include "jtdev.h"
|
||||||
|
#include "output.h"
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
/*===== includes =============================================================*/
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/*===== private symbols ======================================================*/
|
||||||
|
|
||||||
|
/*--- bus pirate pins ---*/
|
||||||
|
#define BP_CS ((unsigned char)0x01)
|
||||||
|
#define BP_MISO ((unsigned char)0x02)
|
||||||
|
#define BP_CLK ((unsigned char)0x04)
|
||||||
|
#define BP_MOSI ((unsigned char)0x08)
|
||||||
|
#define BP_AUX ((unsigned char)0x10)
|
||||||
|
#define BP_PULLUP ((unsigned char)0x20)
|
||||||
|
#define BP_POWER ((unsigned char)0x40)
|
||||||
|
|
||||||
|
/*--- bus pirate binary commands ---*/
|
||||||
|
#define CMD_ENTER_BB ((unsigned char)0x00)
|
||||||
|
#define CMD_LEAVE_BB ((unsigned char)0x0f)
|
||||||
|
#define CMD_CONFIG_PIN_DIR(x) ((unsigned char)0x40 | (x & 0x1f))
|
||||||
|
#define CMD_WRITE_PINS(x) ((unsigned char)0x80 | (x & 0x7f))
|
||||||
|
|
||||||
|
/*--- JTAG signal mapping ---*/
|
||||||
|
#define TDO BP_MISO
|
||||||
|
#define TDI BP_MOSI
|
||||||
|
#define TMS BP_CS
|
||||||
|
#define POWER BP_POWER
|
||||||
|
#define RESET BP_AUX
|
||||||
|
#define TCK BP_CLK
|
||||||
|
|
||||||
|
/*===== public functions =====================================================*/
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
static void do_bus_pirate_data(struct jtdev *p)
|
||||||
|
{
|
||||||
|
char res;
|
||||||
|
char out_buff, in_buff;
|
||||||
|
int buffered;
|
||||||
|
|
||||||
|
out_buff = CMD_WRITE_PINS(p->data_register);
|
||||||
|
|
||||||
|
ioctl(p->port, TIOCINQ, &buffered);
|
||||||
|
if(buffered != 0) {
|
||||||
|
pr_error("jtdev: extraneous bytes available on serial port, flushing it");
|
||||||
|
tcflush(p->port, TCIFLUSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(write(p->port, &out_buff, 1) < 1) {
|
||||||
|
pr_error("jtdev: failed writing to serial port");
|
||||||
|
p->failed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = read(p->port, &in_buff, 1);
|
||||||
|
p->data_register &= ~TDO;
|
||||||
|
p->data_register |= in_buff & TDO;
|
||||||
|
|
||||||
|
// TODO: Handle failure, try again if we don't receive
|
||||||
|
if (res < 1) {
|
||||||
|
pr_error("jtdev: no response with in data");
|
||||||
|
p->failed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jtbp_open(struct jtdev *p, const char *device)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char in_buff, out_buff;
|
||||||
|
struct termios tio;
|
||||||
|
const char* response = "BBIO1";
|
||||||
|
|
||||||
|
p->port = open(device, O_RDWR | O_NOCTTY);
|
||||||
|
if (p->port < 0) {
|
||||||
|
printc_err("jtdev: can't open %s: %s\n",
|
||||||
|
device, last_error());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&tio, 0, sizeof(tio));
|
||||||
|
|
||||||
|
tio.c_cflag = B115200 | CS8 | CLOCAL | CREAD;
|
||||||
|
tio.c_iflag = IGNPAR;
|
||||||
|
tio.c_oflag = 0;
|
||||||
|
tio.c_lflag = 0;
|
||||||
|
|
||||||
|
tio.c_cc[VTIME] = 1;
|
||||||
|
tio.c_cc[VMIN] = 0;
|
||||||
|
|
||||||
|
tcflush(p->port, TCIFLUSH);
|
||||||
|
tcsetattr(p->port, TCSANOW, &tio);
|
||||||
|
|
||||||
|
// If it's in the middle of spewing something, let it finish
|
||||||
|
while(read(p->port, &in_buff, 1) != 0);
|
||||||
|
|
||||||
|
out_buff = 0;
|
||||||
|
|
||||||
|
for(i=0; i<20; ++i) {
|
||||||
|
if(write(p->port, &out_buff, 1) < 1) {
|
||||||
|
pr_error("jtdev: failed writing to serial port");
|
||||||
|
p->failed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(read(p->port, &in_buff, 1) > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == 20) {
|
||||||
|
printc_err("jtdev: bus pirate failed to enter bit bang mode\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(in_buff != *response) {
|
||||||
|
printc_err("jtdev: bus pirate: got bad response %c\n", in_buff);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
++response;
|
||||||
|
|
||||||
|
for(i=0; i<4; ++i, ++response) {
|
||||||
|
if(read(p->port, &in_buff, 1) <= 0) {
|
||||||
|
printc_err("jtdev: bus pirate: got no response\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(in_buff != *response) {
|
||||||
|
printc_err("jtdev: bus pirate: got bad response %c\n", in_buff);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out_buff = CMD_CONFIG_PIN_DIR(TDO);
|
||||||
|
if(write(p->port, &out_buff, 1) < 1) {
|
||||||
|
pr_error("jtdev: failed writing to serial port");
|
||||||
|
p->failed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(read(p->port, &in_buff, 1) <= 0) {
|
||||||
|
printc_err("jtdev: bus pirate: got no response\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
p->data_register = 0;
|
||||||
|
p->control_register = 0;
|
||||||
|
p->failed = 0;
|
||||||
|
|
||||||
|
do_bus_pirate_data(p);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_close(struct jtdev *p)
|
||||||
|
{
|
||||||
|
char out_buff;
|
||||||
|
|
||||||
|
out_buff = 0x0f;
|
||||||
|
// Don't care if this fails, user can just power cycle the bus pirate
|
||||||
|
if(write(p->port, &out_buff, 1));
|
||||||
|
|
||||||
|
close(p->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_power_on(struct jtdev *p)
|
||||||
|
{
|
||||||
|
/* power supply on */
|
||||||
|
p->data_register |= POWER;
|
||||||
|
do_bus_pirate_data(p);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_power_off(struct jtdev *p)
|
||||||
|
{
|
||||||
|
/* power supply off */
|
||||||
|
p->data_register &= ~(POWER | RESET);
|
||||||
|
do_bus_pirate_data(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_connect(struct jtdev *p)
|
||||||
|
{
|
||||||
|
// unsure what this function does, I presume my setup w/ bus pirate is
|
||||||
|
// "always enabled"
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_release(struct jtdev *p)
|
||||||
|
{
|
||||||
|
// unsure what this function does, I presume my setup w/ bus pirate is
|
||||||
|
// "always enabled"
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_tck(struct jtdev *p, int out)
|
||||||
|
{
|
||||||
|
if (out)
|
||||||
|
p->data_register |= TCK;
|
||||||
|
else
|
||||||
|
p->data_register &= ~TCK;
|
||||||
|
|
||||||
|
do_bus_pirate_data(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_tms(struct jtdev *p, int out)
|
||||||
|
{
|
||||||
|
if (out)
|
||||||
|
p->data_register |= TMS;
|
||||||
|
else
|
||||||
|
p->data_register &= ~TMS;
|
||||||
|
|
||||||
|
do_bus_pirate_data(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_tdi(struct jtdev *p, int out)
|
||||||
|
{
|
||||||
|
if (out)
|
||||||
|
p->data_register |= TDI;
|
||||||
|
else
|
||||||
|
p->data_register &= ~TDI;
|
||||||
|
|
||||||
|
do_bus_pirate_data(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_rst(struct jtdev *p, int out)
|
||||||
|
{
|
||||||
|
if (out)
|
||||||
|
p->data_register |= RESET;
|
||||||
|
else
|
||||||
|
p->data_register &= ~RESET;
|
||||||
|
|
||||||
|
do_bus_pirate_data(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_tst(struct jtdev *p, int out)
|
||||||
|
{
|
||||||
|
// Test not supported on bus pirate
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jtbp_tdo_get(struct jtdev *p)
|
||||||
|
{
|
||||||
|
do_bus_pirate_data(p);
|
||||||
|
|
||||||
|
return (p->data_register & TDO) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_tclk(struct jtdev *p, int out)
|
||||||
|
{
|
||||||
|
jtbp_tdi(p, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jtbp_tclk_get(struct jtdev *p)
|
||||||
|
{
|
||||||
|
do_bus_pirate_data(p);
|
||||||
|
|
||||||
|
return (p->data_register & TDI) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_tclk_strobe(struct jtdev *p, unsigned int count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
jtbp_tclk(p, 1);
|
||||||
|
jtbp_tclk(p, 0);
|
||||||
|
|
||||||
|
if (p->failed)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_led_green(struct jtdev *p, int out)
|
||||||
|
{
|
||||||
|
// TCLK not supported by bus pirate
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_led_red(struct jtdev *p, int out)
|
||||||
|
{
|
||||||
|
// TCLK not supported by bus pirate
|
||||||
|
}
|
||||||
|
#else /* __linux__ */
|
||||||
|
static int jtbp_open(struct jtdev *p, const char *device)
|
||||||
|
{
|
||||||
|
printc_err("jtdev: driver is not supported on this platform\n");
|
||||||
|
p->failed = 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void jtbp_close(struct jtdev *p) { }
|
||||||
|
|
||||||
|
static void jtbp_power_on(struct jtdev *p) { }
|
||||||
|
static void jtbp_power_off(struct jtdev *p) { }
|
||||||
|
static void jtbp_connect(struct jtdev *p) { }
|
||||||
|
static void jtbp_release(struct jtdev *p) { }
|
||||||
|
|
||||||
|
static void jtbp_tck(struct jtdev *p, int out) { }
|
||||||
|
static void jtbp_tms(struct jtdev *p, int out) { }
|
||||||
|
static void jtbp_tdi(struct jtdev *p, int out) { }
|
||||||
|
static void jtbp_rst(struct jtdev *p, int out) { }
|
||||||
|
static void jtbp_tst(struct jtdev *p, int out) { }
|
||||||
|
static int jtbp_tdo_get(struct jtdev *p) { return 0; }
|
||||||
|
|
||||||
|
static void jtbp_tclk(struct jtdev *p, int out) { }
|
||||||
|
static int jtbp_tclk_get(struct jtdev *p) { return 0; }
|
||||||
|
static void jtbp_tclk_strobe(struct jtdev *p, unsigned int count) { }
|
||||||
|
|
||||||
|
static void jtbp_led_green(struct jtdev *p, int out) { }
|
||||||
|
static void jtbp_led_red(struct jtdev *p, int out) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const struct jtdev_func jtdev_func_bp = {
|
||||||
|
.jtdev_open = jtbp_open,
|
||||||
|
.jtdev_close = jtbp_close,
|
||||||
|
.jtdev_power_on = jtbp_power_on,
|
||||||
|
.jtdev_power_off = jtbp_power_off,
|
||||||
|
.jtdev_connect = jtbp_connect,
|
||||||
|
.jtdev_release = jtbp_release,
|
||||||
|
.jtdev_tck = jtbp_tck,
|
||||||
|
.jtdev_tms = jtbp_tms,
|
||||||
|
.jtdev_tdi = jtbp_tdi,
|
||||||
|
.jtdev_rst = jtbp_rst,
|
||||||
|
.jtdev_tst = jtbp_tst,
|
||||||
|
.jtdev_tdo_get = jtbp_tdo_get,
|
||||||
|
.jtdev_tclk = jtbp_tclk,
|
||||||
|
.jtdev_tclk_get = jtbp_tclk_get,
|
||||||
|
.jtdev_tclk_strobe = jtbp_tclk_strobe,
|
||||||
|
.jtdev_led_green = jtbp_led_green,
|
||||||
|
.jtdev_led_red = jtbp_led_red
|
||||||
|
};
|
||||||
|
|
|
@ -407,6 +407,50 @@ static device_t gpio_open(const struct device_args *args)
|
||||||
return &dev->base;
|
return &dev->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
static device_t bp_open(const struct device_args *args)
|
||||||
|
{
|
||||||
|
struct pif_device *dev;
|
||||||
|
|
||||||
|
if (!(args->flags & DEVICE_FLAG_TTY)) {
|
||||||
|
printc_err("bp: this driver does not support raw USB access\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(args->flags & DEVICE_FLAG_JTAG)) {
|
||||||
|
printc_err("bp: this driver does not support Spy-Bi-Wire\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = malloc(sizeof(*dev));
|
||||||
|
if (!dev) {
|
||||||
|
printc_err("bp: malloc: %s\n", last_error());
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(dev, 0, sizeof(*dev));
|
||||||
|
dev->base.type = &device_pif;
|
||||||
|
dev->base.max_breakpoints = 2; //supported by all devices
|
||||||
|
dev->base.need_probe = 1;
|
||||||
|
(&dev->jtag)->f = &jtdev_func_bp;
|
||||||
|
|
||||||
|
if ((&dev->jtag)->f->jtdev_open(&dev->jtag, args->path) < 0) {
|
||||||
|
printc_err("bp: can't open port\n");
|
||||||
|
free(dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (init_device(&dev->jtag) < 0) {
|
||||||
|
printc_err("bp: initialization failed\n");
|
||||||
|
free(dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &dev->base;
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
static void pif_destroy(device_t dev_base)
|
static void pif_destroy(device_t dev_base)
|
||||||
{
|
{
|
||||||
|
@ -449,3 +493,18 @@ const struct device_class device_gpio = {
|
||||||
.erase = pif_erase,
|
.erase = pif_erase,
|
||||||
.getconfigfuses = pif_getconfigfuses
|
.getconfigfuses = pif_getconfigfuses
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const struct device_class device_bp = {
|
||||||
|
.name = "bus-pirate",
|
||||||
|
.help = "Bus Pirate JTAG, MISO-TDO, MOSI-TDI, CS-TMS, AUX-RESET, CLK-TCK",
|
||||||
|
.open = bp_open,
|
||||||
|
.destroy = pif_destroy,
|
||||||
|
.readmem = pif_readmem,
|
||||||
|
.writemem = pif_writemem,
|
||||||
|
.getregs = pif_getregs,
|
||||||
|
.setregs = pif_setregs,
|
||||||
|
.ctl = pif_ctl,
|
||||||
|
.poll = pif_poll,
|
||||||
|
.erase = pif_erase,
|
||||||
|
.getconfigfuses = pif_getconfigfuses
|
||||||
|
};
|
||||||
|
|
|
@ -32,5 +32,6 @@
|
||||||
extern const struct device_class device_pif;
|
extern const struct device_class device_pif;
|
||||||
/* share wiht gpio implementation */
|
/* share wiht gpio implementation */
|
||||||
extern const struct device_class device_gpio;
|
extern const struct device_class device_gpio;
|
||||||
|
extern const struct device_class device_bp;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -90,7 +90,8 @@ static const struct device_class *const driver_table[] = {
|
||||||
&device_gpio,
|
&device_gpio,
|
||||||
&device_loadbsl,
|
&device_loadbsl,
|
||||||
&device_ezfet,
|
&device_ezfet,
|
||||||
&device_rom_bsl
|
&device_rom_bsl,
|
||||||
|
&device_bp
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *version_text =
|
static const char *version_text =
|
||||||
|
|
Loading…
Reference in New Issue