mspdebug/drivers/jtdev_bus_pirate.c

365 lines
8.7 KiB
C

/* 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 "jtaglib.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,
.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_dr_shift_20 = jtag_default_dr_shift_20,
.jtdev_tms_sequence= jtag_default_tms_sequence,
.jtdev_init_dap = jtag_default_init_dap
};