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/fet_olimex_db.o \
|
||||
drivers/jtdev.o \
|
||||
drivers/jtdev_bus_pirate.o \
|
||||
drivers/jtdev_gpio.o \
|
||||
drivers/jtaglib.o \
|
||||
drivers/pif.o \
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
|
||||
#ifndef JTDEV_H_
|
||||
#define JTDEV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct jtdev_func;
|
||||
struct jtdev {
|
||||
int port;
|
||||
|
@ -65,5 +68,6 @@ struct jtdev_func{
|
|||
|
||||
extern const struct jtdev_func jtdev_func_pif;
|
||||
extern const struct jtdev_func jtdev_func_gpio;
|
||||
extern const struct jtdev_func jtdev_func_bp;
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -449,3 +493,18 @@ const struct device_class device_gpio = {
|
|||
.erase = pif_erase,
|
||||
.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;
|
||||
/* share wiht gpio implementation */
|
||||
extern const struct device_class device_gpio;
|
||||
extern const struct device_class device_bp;
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue