From 682d7ecc9ce77f6b4c258606b34ed90084fbd6e4 Mon Sep 17 00:00:00 2001 From: Alex Orange Date: Wed, 14 Jun 2017 13:53:03 -0600 Subject: [PATCH] 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. --- Makefile | 1 + drivers/jtdev.h | 4 + drivers/jtdev_bus_pirate.c | 356 +++++++++++++++++++++++++++++++++++++ drivers/pif.c | 59 ++++++ drivers/pif.h | 1 + ui/main.c | 3 +- 6 files changed, 423 insertions(+), 1 deletion(-) create mode 100644 drivers/jtdev_bus_pirate.c diff --git a/Makefile b/Makefile index b2a06ec..415cbe6 100644 --- a/Makefile +++ b/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 \ diff --git a/drivers/jtdev.h b/drivers/jtdev.h index 37d2987..88bd52b 100644 --- a/drivers/jtdev.h +++ b/drivers/jtdev.h @@ -19,6 +19,9 @@ #ifndef JTDEV_H_ #define JTDEV_H_ + +#include + 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 diff --git a/drivers/jtdev_bus_pirate.c b/drivers/jtdev_bus_pirate.c new file mode 100644 index 0000000..1c94f9c --- /dev/null +++ b/drivers/jtdev_bus_pirate.c @@ -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 +#include "jtdev.h" +#include "output.h" + +#if defined(__linux__) +/*===== includes =============================================================*/ + +#include +#include +#include +#include +#include + +#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 + +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 +}; + diff --git a/drivers/pif.c b/drivers/pif.c index 919e0b6..0b07753 100644 --- a/drivers/pif.c +++ b/drivers/pif.c @@ -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 +}; diff --git a/drivers/pif.h b/drivers/pif.h index e5def7d..e10b75a 100644 --- a/drivers/pif.h +++ b/drivers/pif.h @@ -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 diff --git a/ui/main.c b/ui/main.c index a0e5085..f9be59a 100644 --- a/ui/main.c +++ b/ui/main.c @@ -90,7 +90,8 @@ static const struct device_class *const driver_table[] = { &device_gpio, &device_loadbsl, &device_ezfet, - &device_rom_bsl + &device_rom_bsl, + &device_bp }; static const char *version_text =