summaryrefslogtreecommitdiffstats
path: root/buspirate_spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'buspirate_spi.c')
-rw-r--r--buspirate_spi.c269
1 files changed, 170 insertions, 99 deletions
diff --git a/buspirate_spi.c b/buspirate_spi.c
index eee8daa41..72c28b0ad 100644
--- a/buspirate_spi.c
+++ b/buspirate_spi.c
@@ -16,6 +16,7 @@
#include <stdio.h>
#include <strings.h>
#include <string.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
@@ -50,26 +51,28 @@ static int buspirate_serialport_setup(char *dev)
#define sp_flush_incoming(...) 0
#endif
-static unsigned char *bp_commbuf = NULL;
-static int bp_commbufsize = 0;
+struct bp_spi_data {
+ unsigned char *commbuf;
+ int commbufsize;
+};
-static int buspirate_commbuf_grow(int bufsize)
+static int buspirate_commbuf_grow(int bufsize, unsigned char **bp_commbuf, int *bp_commbufsize)
{
unsigned char *tmpbuf;
/* Never shrink. realloc() calls are expensive. */
- if (bufsize <= bp_commbufsize)
+ if (bufsize <= *bp_commbufsize)
return 0;
- tmpbuf = realloc(bp_commbuf, bufsize);
+ tmpbuf = realloc(*bp_commbuf, bufsize);
if (!tmpbuf) {
/* Keep the existing buffer because memory is already tight. */
msg_perr("Out of memory!\n");
return ERROR_OOM;
}
- bp_commbuf = tmpbuf;
- bp_commbufsize = bufsize;
+ *bp_commbuf = tmpbuf;
+ *bp_commbufsize = bufsize;
return 0;
}
@@ -128,40 +131,10 @@ static int buspirate_wait_for_string(unsigned char *buf, const char *key)
return ret;
}
-static struct spi_master spi_master_buspirate = {
- .features = SPI_MASTER_4BA,
- .max_data_read = MAX_DATA_UNSPECIFIED,
- .max_data_write = MAX_DATA_UNSPECIFIED,
- .command = NULL,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
-};
-
-static const struct buspirate_speeds spispeeds[] = {
- {"30k", 0x0},
- {"125k", 0x1},
- {"250k", 0x2},
- {"1M", 0x3},
- {"2M", 0x4},
- {"2.6M", 0x5},
- {"4M", 0x6},
- {"8M", 0x7},
- {NULL, 0x0}
-};
-
-static const struct buspirate_speeds serialspeeds[] = {
- {"115200", 115200},
- {"230400", 230400},
- {"250000", 250000},
- {"2000000", 2000000},
- {"2M", 2000000},
- {NULL, 0}
-};
-
static int buspirate_spi_shutdown(void *data)
{
+ struct bp_spi_data *bp_data = data;
+ unsigned char *const bp_commbuf = bp_data->commbuf;
int ret = 0, ret2 = 0;
/* No need to allocate a buffer here, we know that bp_commbuf is at least DEFAULT_BUFSIZE big. */
@@ -189,30 +162,64 @@ out_shutdown:
/* Keep the oldest error, it is probably the best indicator. */
if (ret2 && !ret)
ret = ret2;
- bp_commbufsize = 0;
+
free(bp_commbuf);
- bp_commbuf = NULL;
if (ret)
msg_pdbg("Bus Pirate shutdown failed.\n");
else
msg_pdbg("Bus Pirate shutdown completed.\n");
+ free(data);
return ret;
}
+static struct spi_master spi_master_buspirate = {
+ .features = SPI_MASTER_4BA,
+ .max_data_read = MAX_DATA_UNSPECIFIED,
+ .max_data_write = MAX_DATA_UNSPECIFIED,
+ .command = NULL,
+ .read = default_spi_read,
+ .write_256 = default_spi_write_256,
+ .shutdown = buspirate_spi_shutdown,
+};
+
+static const struct buspirate_speeds spispeeds[] = {
+ {"30k", 0x0},
+ {"125k", 0x1},
+ {"250k", 0x2},
+ {"1M", 0x3},
+ {"2M", 0x4},
+ {"2.6M", 0x5},
+ {"4M", 0x6},
+ {"8M", 0x7},
+ {NULL, 0x0}
+};
+
+static const struct buspirate_speeds serialspeeds[] = {
+ {"115200", 115200},
+ {"230400", 230400},
+ {"250000", 250000},
+ {"2000000", 2000000},
+ {"2M", 2000000},
+ {NULL, 0}
+};
+
static int buspirate_spi_send_command_v1(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr, unsigned char *readarr)
{
unsigned int i = 0;
int ret = 0;
+ struct bp_spi_data *bp_data = flash->mst->spi.data;
if (writecnt > 16 || readcnt > 16 || (readcnt + writecnt) > 16)
return SPI_INVALID_LENGTH;
/* 3 bytes extra for CS#, len, CS#. */
- if (buspirate_commbuf_grow(writecnt + readcnt + 3))
+ if (buspirate_commbuf_grow(writecnt + readcnt + 3, &bp_data->commbuf, &bp_data->commbufsize))
return ERROR_OOM;
+ unsigned char *const bp_commbuf = bp_data->commbuf;
+
/* Assert CS# */
bp_commbuf[i++] = 0x02;
@@ -257,6 +264,7 @@ static int buspirate_spi_send_command_v2(const struct flashctx *flash, unsigned
const unsigned char *writearr, unsigned char *readarr)
{
int i = 0, ret = 0;
+ struct bp_spi_data *bp_data = flash->mst->spi.data;
if (writecnt > 4096 || readcnt > 4096 || (readcnt + writecnt) > 4096)
return SPI_INVALID_LENGTH;
@@ -264,9 +272,11 @@ static int buspirate_spi_send_command_v2(const struct flashctx *flash, unsigned
/* 5 bytes extra for command, writelen, readlen.
* 1 byte extra for Ack/Nack.
*/
- if (buspirate_commbuf_grow(max(writecnt + 5, readcnt + 1)))
+ if (buspirate_commbuf_grow(max(writecnt + 5, readcnt + 1), &bp_data->commbuf, &bp_data->commbufsize))
return ERROR_OOM;
+ unsigned char *const bp_commbuf = bp_data->commbuf;
+
/* Combined SPI write/read. */
bp_commbuf[i++] = 0x04;
bp_commbuf[i++] = (writecnt >> 8) & 0xff;
@@ -302,7 +312,7 @@ static int buspirate_spi_send_command_v2(const struct flashctx *flash, unsigned
*/
#define BP_DIVISOR(baud) ((4000000/(baud)) - 1)
-int buspirate_spi_init(void)
+static int buspirate_spi_init(const struct programmer_cfg *cfg)
{
char *tmp;
char *dev;
@@ -315,9 +325,13 @@ int buspirate_spi_init(void)
int spispeed = 0x7;
int serialspeed_index = -1;
int ret = 0;
- int pullup = 0;
+ bool pullup = false;
+ bool psu = false;
+ bool aux = true;
+ unsigned char *bp_commbuf;
+ int bp_commbufsize;
- dev = extract_programmer_param("dev");
+ dev = extract_programmer_param_str(cfg, "dev");
if (dev && !strlen(dev)) {
free(dev);
dev = NULL;
@@ -327,7 +341,7 @@ int buspirate_spi_init(void)
return 1;
}
- tmp = extract_programmer_param("spispeed");
+ tmp = extract_programmer_param_str(cfg, "spispeed");
if (tmp) {
for (i = 0; spispeeds[i].name; i++) {
if (!strncasecmp(spispeeds[i].name, tmp, strlen(spispeeds[i].name))) {
@@ -341,7 +355,7 @@ int buspirate_spi_init(void)
free(tmp);
/* Extract serialspeed parameter */
- tmp = extract_programmer_param("serialspeed");
+ tmp = extract_programmer_param_str(cfg, "serialspeed");
if (tmp) {
for (i = 0; serialspeeds[i].name; i++) {
if (!strncasecmp(serialspeeds[i].name, tmp, strlen(serialspeeds[i].name))) {
@@ -354,10 +368,10 @@ int buspirate_spi_init(void)
}
free(tmp);
- tmp = extract_programmer_param("pullups");
+ tmp = extract_programmer_param_str(cfg, "pullups");
if (tmp) {
if (strcasecmp("on", tmp) == 0)
- pullup = 1;
+ pullup = true;
else if (strcasecmp("off", tmp) == 0)
; // ignore
else
@@ -365,11 +379,32 @@ int buspirate_spi_init(void)
}
free(tmp);
+ tmp = extract_programmer_param_str(cfg, "psus");
+ if (tmp) {
+ if (strcasecmp("on", tmp) == 0)
+ psu = true;
+ else if (strcasecmp("off", tmp) == 0)
+ ; // ignore
+ else
+ msg_perr("Invalid psus state, not enabling.\n");
+ }
+ free(tmp);
+
+ tmp = extract_programmer_param_str(cfg, "aux");
+ if (tmp) {
+ if (strcasecmp("high", tmp) == 0)
+ ; /* Default */
+ else if (strcasecmp("low", tmp) == 0)
+ aux = false;
+ else
+ msg_perr("Invalid AUX state, driving high by default.\n");
+ }
+ free(tmp);
+
/* Default buffer size is 19: 16 bytes data, 3 bytes control. */
#define DEFAULT_BUFSIZE (16 + 3)
bp_commbuf = malloc(DEFAULT_BUFSIZE);
if (!bp_commbuf) {
- bp_commbufsize = 0;
msg_perr("Out of memory!\n");
free(dev);
return ERROR_OOM;
@@ -379,18 +414,19 @@ int buspirate_spi_init(void)
ret = buspirate_serialport_setup(dev);
free(dev);
if (ret) {
- bp_commbufsize = 0;
free(bp_commbuf);
- bp_commbuf = NULL;
return ret;
}
- if (register_shutdown(buspirate_spi_shutdown, NULL) != 0) {
- bp_commbufsize = 0;
+
+ struct bp_spi_data *bp_data = calloc(1, sizeof(*bp_data));
+ if (!bp_data) {
+ msg_perr("Unable to allocate space for SPI master data\n");
free(bp_commbuf);
- bp_commbuf = NULL;
return 1;
}
+ bp_data->commbuf = bp_commbuf;
+ bp_data->commbufsize = bp_commbufsize;
/* This is the brute force version, but it should work.
* It is likely to fail if a previous flashrom run was aborted during a write with the new SPI commands
@@ -403,7 +439,7 @@ int buspirate_spi_init(void)
/* Send the command, don't read the response. */
ret = buspirate_sendrecv(bp_commbuf, 1, 0);
if (ret)
- return ret;
+ goto init_err_cleanup_exit;
/* The old way to handle responses from a Bus Pirate already in BBIO mode was to flush any
* response which came in over serial. Unfortunately that does not work reliably on Linux
* with FTDI USB-serial.
@@ -416,19 +452,19 @@ int buspirate_spi_init(void)
}
/* We know that 20 commands of \0 should elicit at least one BBIO1 response. */
if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
- return ret;
+ goto init_err_cleanup_exit;
/* Reset the Bus Pirate. */
bp_commbuf[0] = 0x0f;
/* Send the command, don't read the response. */
if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_wait_for_string(bp_commbuf, "irate ")))
- return ret;
+ goto init_err_cleanup_exit;
/* Read the hardware version string. Last byte of the buffer is reserved for \0. */
for (i = 0; i < DEFAULT_BUFSIZE - 1; i++) {
if ((ret = buspirate_sendrecv(bp_commbuf + i, 0, 1)))
- return ret;
+ goto init_err_cleanup_exit;
if (strchr("\r\n\t ", bp_commbuf[i]))
break;
}
@@ -449,11 +485,11 @@ int buspirate_spi_init(void)
msg_pdbg("\n");
if ((ret = buspirate_wait_for_string(bp_commbuf, "irmware ")))
- return ret;
+ goto init_err_cleanup_exit;
/* Read the firmware version string. Last byte of the buffer is reserved for \0. */
for (i = 0; i < DEFAULT_BUFSIZE - 1; i++) {
if ((ret = buspirate_sendrecv(bp_commbuf + i, 0, 1)))
- return ret;
+ goto init_err_cleanup_exit;
if (strchr("\r\n\t ", bp_commbuf[i]))
break;
}
@@ -474,21 +510,26 @@ int buspirate_spi_init(void)
msg_pdbg("\n");
if ((ret = buspirate_wait_for_string(bp_commbuf, "HiZ>")))
- return ret;
+ goto init_err_cleanup_exit;
/* Tell the user about missing SPI binary mode in firmware 2.3 and older. */
if (BP_FWVERSION(fw_version_major, fw_version_minor) < BP_FWVERSION(2, 4)) {
msg_pinfo("Bus Pirate firmware 2.3 and older does not support binary SPI access.\n");
msg_pinfo("Please upgrade to the latest firmware (at least 2.4).\n");
- return SPI_PROGRAMMER_ERROR;
+ ret = SPI_PROGRAMMER_ERROR;
+ goto init_err_cleanup_exit;
}
/* Use fast SPI mode in firmware 5.5 and newer. */
if (BP_FWVERSION(fw_version_major, fw_version_minor) >= BP_FWVERSION(5, 5)) {
msg_pdbg("Using SPI command set v2.\n");
/* Sensible default buffer size. */
- if (buspirate_commbuf_grow(260 + 5))
- return ERROR_OOM;
+ if (buspirate_commbuf_grow(260 + 5, &bp_commbuf, &bp_commbufsize)) {
+ ret = ERROR_OOM;
+ goto init_err_cleanup_exit;
+ }
+ bp_data->commbuf = bp_commbuf;
+ bp_data->commbufsize = bp_commbufsize;
spi_master_buspirate.max_data_read = 2048;
spi_master_buspirate.max_data_write = 256;
spi_master_buspirate.command = buspirate_spi_send_command_v2;
@@ -497,8 +538,12 @@ int buspirate_spi_init(void)
msg_pinfo("Reading/writing a flash chip may take hours.\n");
msg_pinfo("It is recommended to upgrade to firmware 5.5 or newer.\n");
/* Sensible default buffer size. */
- if (buspirate_commbuf_grow(16 + 3))
- return ERROR_OOM;
+ if (buspirate_commbuf_grow(16 + 3, &bp_commbuf, &bp_commbufsize)) {
+ ret = ERROR_OOM;
+ goto init_err_cleanup_exit;
+ }
+ bp_data->commbuf = bp_commbuf;
+ bp_data->commbufsize = bp_commbufsize;
spi_master_buspirate.max_data_read = 12;
spi_master_buspirate.max_data_write = 12;
spi_master_buspirate.command = buspirate_spi_send_command_v1;
@@ -538,37 +583,37 @@ int buspirate_spi_init(void)
/* Enter baud rate configuration mode */
cnt = snprintf((char *)bp_commbuf, DEFAULT_BUFSIZE, "b\n");
if ((ret = buspirate_sendrecv(bp_commbuf, cnt, 0)))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_wait_for_string(bp_commbuf, ">")))
- return ret;
+ goto init_err_cleanup_exit;
/* Enter manual clock divisor entry mode */
cnt = snprintf((char *)bp_commbuf, DEFAULT_BUFSIZE, "10\n");
if ((ret = buspirate_sendrecv(bp_commbuf, cnt, 0)))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_wait_for_string(bp_commbuf, ">")))
- return ret;
+ goto init_err_cleanup_exit;
/* Set the clock divisor to the value calculated from the user's input */
cnt = snprintf((char *)bp_commbuf, DEFAULT_BUFSIZE, "%d\n",
BP_DIVISOR(serialspeeds[serialspeed_index].speed));
if ((ret = buspirate_sendrecv(bp_commbuf, cnt, 0)))
- return ret;
+ goto init_err_cleanup_exit;
sleep(1);
/* Reconfigure the host's serial baud rate to the new value */
if ((ret = serialport_config(sp_fd, serialspeeds[serialspeed_index].speed))) {
msg_perr("Unable to configure system baud rate to specified value.");
- return ret;
+ goto init_err_cleanup_exit;
}
/* Return to the main prompt */
bp_commbuf[0] = ' ';
if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_wait_for_string(bp_commbuf, "HiZ>")))
- return ret;
+ goto init_err_cleanup_exit;
msg_pdbg("Serial speed is %d baud\n", serialspeeds[serialspeed_index].speed);
}
@@ -581,81 +626,107 @@ int buspirate_spi_init(void)
for (i = 0; i < 20; i++) {
bp_commbuf[0] = 0x00;
if ((ret = buspirate_sendrecv(bp_commbuf, 1, 0)))
- return ret;
+ goto init_err_cleanup_exit;
}
if ((ret = buspirate_wait_for_string(bp_commbuf, "BBIO")))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
- return ret;
+ goto init_err_cleanup_exit;
msg_pdbg("Raw bitbang mode version %c\n", bp_commbuf[0]);
if (bp_commbuf[0] != '1') {
msg_perr("Can't handle raw bitbang mode version %c!\n", bp_commbuf[0]);
- return 1;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
/* Enter raw SPI mode */
bp_commbuf[0] = 0x01;
ret = buspirate_sendrecv(bp_commbuf, 1, 0);
if (ret)
- return 1;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_wait_for_string(bp_commbuf, "SPI")))
- return ret;
+ goto init_err_cleanup_exit;
if ((ret = buspirate_sendrecv(bp_commbuf, 0, 1)))
- return ret;
+ goto init_err_cleanup_exit;
msg_pdbg("Raw SPI mode version %c\n", bp_commbuf[0]);
if (bp_commbuf[0] != '1') {
msg_perr("Can't handle raw SPI mode version %c!\n", bp_commbuf[0]);
- return 1;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
- /* Initial setup (SPI peripherals config): Enable power, CS high, AUX */
- bp_commbuf[0] = 0x40 | 0x0b;
- if (pullup == 1) {
+ /* Initial setup (SPI peripherals config): Enable power, CS high */
+ bp_commbuf[0] = 0x40 | 0x09;
+ if (pullup) {
bp_commbuf[0] |= (1 << 2);
msg_pdbg("Enabling pull-up resistors.\n");
}
+ if (psu) {
+ bp_commbuf[0] |= (1 << 3);
+ msg_pdbg("Enabling PSUs.\n");
+ }
+ if (aux) {
+ bp_commbuf[0] |= (1 << 1);
+ msg_pdbg("Driving AUX high.\n");
+ } else {
+ msg_pdbg("Driving AUX low.\n");
+ }
ret = buspirate_sendrecv(bp_commbuf, 1, 1);
if (ret)
- return 1;
+ goto init_err_cleanup_exit;
if (bp_commbuf[0] != 0x01) {
msg_perr("Protocol error while setting power/CS/AUX(/Pull-up resistors)!\n");
- return 1;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
/* Set SPI speed */
bp_commbuf[0] = 0x60 | spispeed;
ret = buspirate_sendrecv(bp_commbuf, 1, 1);
if (ret)
- return 1;
+ goto init_err_cleanup_exit;
if (bp_commbuf[0] != 0x01) {
msg_perr("Protocol error while setting SPI speed!\n");
- return 1;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
/* Set SPI config: output type, idle, clock edge, sample */
bp_commbuf[0] = 0x80 | 0xa;
- if (pullup == 1) {
+ if (pullup) {
bp_commbuf[0] &= ~(1 << 3);
msg_pdbg("Pull-ups enabled, so using HiZ pin output! (Open-Drain mode)\n");
}
ret = buspirate_sendrecv(bp_commbuf, 1, 1);
if (ret)
- return 1;
+ goto init_err_cleanup_exit;
if (bp_commbuf[0] != 0x01) {
msg_perr("Protocol error while setting SPI config!\n");
- return 1;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
/* De-assert CS# */
bp_commbuf[0] = 0x03;
ret = buspirate_sendrecv(bp_commbuf, 1, 1);
if (ret)
- return 1;
+ goto init_err_cleanup_exit;
if (bp_commbuf[0] != 0x01) {
msg_perr("Protocol error while raising CS#!\n");
- return 1;
+ ret = 1;
+ goto init_err_cleanup_exit;
}
- register_spi_master(&spi_master_buspirate);
+ return register_spi_master(&spi_master_buspirate, bp_data);
- return 0;
+init_err_cleanup_exit:
+ buspirate_spi_shutdown(bp_data);
+ return ret;
}
+
+const struct programmer_entry programmer_buspirate_spi = {
+ .name = "buspirate_spi",
+ .type = OTHER,
+ /* FIXME */
+ .devs.note = "Dangerous Prototypes Bus Pirate\n",
+ .init = buspirate_spi_init,
+};