Adds support for the Altera USB Blaster programming dongle in SPI mode. It has only been tested against a cheap clone ($10, unclear origin), and so is marked as not tested. It should also support several variants which are present on Altera dev boards (PID 6002,6003...), although I believe these are hardwired to their targets.
Signed-off-by: James Laird jhl@mafipulation.org Index: Makefile =================================================================== --- Makefile (revision 1548) +++ Makefile (working copy) @@ -84,7 +84,7 @@ else override CONFIG_SERPROG = no endif -# Dediprog and FT2232 are not supported under DOS (missing USB support). +# Dediprog, FT2232 and USB Blaster are not supported under DOS (missing USB support). ifeq ($(CONFIG_DEDIPROG), yes) UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes else @@ -95,7 +95,12 @@ else override CONFIG_FT2232_SPI = no endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes +else +override CONFIG_USBBLASTER_SPI = no endif +endif
# FIXME: Should we check for Cygwin/MSVC as well? ifeq ($(TARGET_OS), MinGW) @@ -196,7 +201,7 @@ else override CONFIG_SERPROG = no endif -# Dediprog and FT2232 are not supported with libpayload (missing libusb support) +# Dediprog, FT2232 and USB Blaster are not supported with libpayload (missing libusb support) ifeq ($(CONFIG_DEDIPROG), yes) UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes else @@ -207,7 +212,12 @@ else override CONFIG_FT2232_SPI = no endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes +else +override CONFIG_USBBLASTER_SPI = no endif +endif
ifneq ($(TARGET_OS), Linux) ifeq ($(CONFIG_LINUX_SPI), yes) @@ -344,6 +354,9 @@ # Enable Linux spidev interface by default. We disable it on non-Linux targets. CONFIG_LINUX_SPI ?= yes
+# Always enable USB Blaster SPI for now. +CONFIG_USBBLASTER_SPI ?= yes + # Disable wiki printing by default. It is only useful if you have wiki access. CONFIG_PRINT_WIKI ?= no
@@ -430,14 +443,31 @@ NEED_PCI := yes endif
+# This is a totally ugly hack. +WANT_LIBFTDI := no +HAVE_LIBFTDI := $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && echo "yes") ifeq ($(CONFIG_FT2232_SPI), yes) -FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") -# This is a totally ugly hack. -FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_FT2232_SPI=1'") -FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)") -PROGRAMMER_OBJS += ft2232_spi.o + WANT_LIBFTDI := yes + ifeq ($(HAVE_LIBFTDI), yes) + FEATURE_CFLAGS += -DCONFIG_FT2232_SPI=1 + PROGRAMMER_OBJS += ft2232_spi.o + endif endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes) + WANT_LIBFTDI := yes + ifeq ($(HAVE_LIBFTDI), yes) + FEATURE_CFLAGS += -DCONFIG_USBBLASTER_SPI=1 + PROGRAMMER_OBJS += usbblaster_spi.o + endif +endif
+ifeq ($(WANT_LIBFTDI), yes) + ifeq ($(WANT_LIBFTDI), yes) + FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") + FEATURE_LIBS += $(FTDILIBS) + endif +endif + ifeq ($(CONFIG_DUMMY), yes) FEATURE_CFLAGS += -D'CONFIG_DUMMY=1' PROGRAMMER_OBJS += dummyflasher.o @@ -700,7 +730,7 @@
features: compiler @echo "FEATURES := yes" > .features.tmp -ifeq ($(CONFIG_FT2232_SPI), yes) +ifeq ($(WANT_LIBFTDI), yes) @printf "Checking for FTDI support... " @echo "$$FTDI_TEST" > .featuretest.c @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >/dev/null 2>&1 && \ Index: README =================================================================== --- README (revision 1548) +++ README (working copy) @@ -45,8 +45,8 @@ To build flashrom you need to install the following software:
* pciutils+libpci (if you want support for mainboard or PCI device flashing) - * libusb (if you want FT2232 or Dediprog support) - * libftdi (if you want FT2232 support) + * libusb (if you want FT2232, Dediprog or USB Blaster support) + * libftdi (if you want FT2232 or USB Blaster support)
Linux et al:
Index: usbblaster_spi.c =================================================================== --- usbblaster_spi.c (revision 0) +++ usbblaster_spi.c (working copy) @@ -0,0 +1,258 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2012 James Laird jhl@mafipulation.org + * + * 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; version 2 of the License. + * + * 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 + */ + +/* + * Device should be connected as per "active serial" mode: + * + * +---------+------+-----------+ + * | SPI | Pin | Altera | + * +---------+------+-----------+ + * | SCLK | 1 | DCLK | + * | GND | 2,10 | GND | + * | VCC | 4 | VCC(TRGT) | + * | MISO | 7 | ASDO | + * | /CS | 8 | nCS | + * | MOSI | 9 | ASDI | + * +---------+------+-----------+ + */ + +#if CONFIG_USBBLASTER_SPI == 1 + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include "flash.h" +#include "programmer.h" +#include "spi.h" +#include <ftdi.h> + +/* Please keep sorted by vendor ID, then device ID. */ + +#define ALTERA_VID 0x09fb +#define ALTERA_USBBLASTER_PID 0x6001 + +const struct usbdev_status devs_usbblasterspi[] = { + {ALTERA_VID, ALTERA_USBBLASTER_PID, NT, "Altera", "USB Blaster"}, + {}, +}; + +static const struct spi_programmer spi_programmer_usbblaster; + +static struct ftdi_context ftdic; + +// command bytes +#define BIT_BYTE (1<<7) // byte mode (rather than bitbang) +#define BIT_READ (1<<6) // read request + +#define BIT_LED (1<<5) +#define BIT_CS (1<<3) +#define BIT_CLK (1<<0) +#define BIT_TMS (1<<1) + +#define BITS_OTHER 0 + +// The programmer shifts bits in the wrong order for SPI. +static unsigned char reverse[] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + + +/* Returns 0 upon success, a negative number upon errors. */ +int usbblaster_spi_init(void) +{ + if (ftdi_init(&ftdic) < 0) + return -1; + + if (ftdi_usb_open(&ftdic, ALTERA_VID, ALTERA_USBBLASTER_PID) < 0) { + msg_perr("Failed to open USB Blaster: %s\n", ftdic.error_str); + return -1; + } + + if (ftdi_usb_reset(&ftdic) < 0) { + msg_perr("Blaster reset failed\n"); + return -1; + } + + if (ftdi_set_latency_timer(&ftdic, 2) < 0) { + msg_perr("Blaster set latency timer failed\n"); + return -1; + } + + if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 || + ftdi_read_data_set_chunksize(&ftdic, 64) < 0) { + msg_perr("Blaster set chunk size failed\n"); + return -1; + } + unsigned char buf[65]; + memset(buf, 0, sizeof(buf)); + buf[sizeof(buf)-1] = BIT_LED | BITS_OTHER | BIT_CS; + if (ftdi_write_data(&ftdic, buf, sizeof(buf)) < 0) { + msg_perr("Blaster reset write failed\n"); + return -1; + } + if (ftdi_read_data(&ftdic, buf, sizeof(buf)) < 0) { + msg_perr("Blaster reset read failed\n"); + return -1; + } + + register_spi_programmer(&spi_programmer_usbblaster); + return 0; +} + +/* Returns 0 upon success, a negative number upon errors. */ +static int usbblaster_spi_send_command(struct flashctx *flash, + unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, + unsigned char *readarr) +{ + unsigned char cmd; + unsigned char buf[64]; + unsigned char tms_state = 0; + int i; + // assert /CS + cmd = BIT_LED | BITS_OTHER; + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + + while (writecnt) { + unsigned int n_write = writecnt; + if (n_write > 63) + n_write = 63; + + msg_pspew("writing %d-byte packet\n", n_write); + + cmd = BIT_BYTE | (unsigned char)n_write; + buf[0] = cmd; + for (i=0; i<n_write; i++) { + buf[i+1] = reverse[writearr[i]]; + } + if (ftdi_write_data(&ftdic, buf, n_write+1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + cmd = BIT_LED | BITS_OTHER | (tms_state ^= BIT_TMS); + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + writearr += n_write; + writecnt -= n_write; + } + + unsigned int n_readout = readcnt; + while (readcnt) { + unsigned int n_read = readcnt; + if (n_read > 63) + n_read = 63; + + cmd = BIT_BYTE | BIT_READ | (unsigned char)n_read; + buf[0] = cmd; + if (ftdi_write_data(&ftdic, buf, n_read + 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + cmd = BIT_LED | BITS_OTHER | (tms_state ^= BIT_TMS); + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + readcnt -= n_read; + msg_pspew("reading %d-byte packet\n", n_read); + }; + + unsigned int n_read = n_readout; + while (n_read) { + int ret = ftdi_read_data(&ftdic, readarr, n_read); + if (ret < 0) { + msg_perr("Blaster read failed\n"); + return -1; + } + for (i=0; i<ret; i++) { + readarr[i] = reverse[readarr[i]]; + } + n_read -= ret; + readarr += ret; + } + + cmd = BIT_LED | BIT_CS | BITS_OTHER; + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + cmd = BIT_CS | BITS_OTHER; + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("Blaster write failed\n"); + return -1; + } + + return 0; +} + + +static const struct spi_programmer spi_programmer_usbblaster = { + .type = SPI_CONTROLLER_USBBLASTER, + .max_data_read = 4096, + .max_data_write = 256, + .command = usbblaster_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = default_spi_read, + .write_256 = default_spi_write_256, +}; + +#endif Index: programmer.h =================================================================== --- programmer.h (revision 1548) +++ programmer.h (working copy) @@ -87,6 +87,9 @@ #if CONFIG_LINUX_SPI == 1 PROGRAMMER_LINUX_SPI, #endif +#if CONFIG_USBBLASTER_SPI == 1 + PROGRAMMER_USBBLASTER_SPI, +#endif PROGRAMMER_INVALID /* This must always be the last entry. */ };
@@ -433,6 +436,11 @@ void print_supported_usbdevs(const struct usbdev_status *devs); #endif
+/* usbblaster_spi.c */ +#if CONFIG_USBBLASTER_SPI == 1 +int usbblaster_spi_init(void); +#endif + /* rayer_spi.c */ #if CONFIG_RAYER_SPI == 1 int rayer_spi_init(void); @@ -514,6 +522,9 @@ #if CONFIG_SERPROG == 1 SPI_CONTROLLER_SERPROG, #endif +#if CONFIG_USBBLASTER_SPI == 1 + SPI_CONTROLLER_USBBLASTER, +#endif };
#define MAX_DATA_UNSPECIFIED 0 Index: print.c =================================================================== --- print.c (revision 1548) +++ print.c (working copy) @@ -538,6 +538,12 @@ programmer_table[PROGRAMMER_LINUX_SPI].name); msg_ginfo("Device files /dev/spidev*.*\n"); #endif +#if CONFIG_USBBLASTER_SPI == 1 + msg_ginfo("\nSupported devices for the %s programmer:\n", + programmer_table[PROGRAMMER_USBBLASTER_SPI].name); + /* FIXME */ + msg_ginfo("Altera USB Blaster cable\n"); +#endif }
#if CONFIG_INTERNAL == 1 Index: flashrom.c =================================================================== --- flashrom.c (revision 1548) +++ flashrom.c (working copy) @@ -262,6 +262,16 @@ }, #endif
+#if CONFIG_USBBLASTER_SPI == 1 + { + .name = "usbblaster_spi", + .init = usbblaster_spi_init, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .delay = internal_delay, + }, +#endif + {}, /* This entry corresponds to PROGRAMMER_INVALID. */ };
On Tue, 17 Jul 2012 15:39:31 +1000 James Laird jhl@mafipulation.org wrote:
Adds support for the Altera USB Blaster programming dongle in SPI mode. It has only been tested against a cheap clone ($10, unclear origin), and so is marked as not tested. It should also support several variants which are present on Altera dev boards (PID 6002,6003...), although I believe these are hardwired to their targets.
iirc you said that those simulate spi chips. in that case it would make sense to add them imho, even if there are probably not many use cases... it is a trivial, inexpensive change that pays out even if a single user needs this once imho :)
Signed-off-by: James Laird jhl@mafipulation.org Index: Makefile =================================================================== --- Makefile (revision 1548) +++ Makefile (working copy) @@ -84,7 +84,7 @@ else override CONFIG_SERPROG = no endif -# Dediprog and FT2232 are not supported under DOS (missing USB support). +# Dediprog, FT2232 and USB Blaster are not supported under DOS (missing USB support).
the trademark is "USB-Blaster", please use that instead everywhere (including in the msg_perr invocations)
ifeq ($(CONFIG_DEDIPROG), yes) UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes else @@ -95,7 +95,12 @@ else override CONFIG_FT2232_SPI = no endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes +else +override CONFIG_USBBLASTER_SPI = no endif +endif
the macro name is ok of course
# FIXME: Should we check for Cygwin/MSVC as well? ifeq ($(TARGET_OS), MinGW) @@ -196,7 +201,7 @@ else override CONFIG_SERPROG = no endif -# Dediprog and FT2232 are not supported with libpayload (missing libusb support) +# Dediprog, FT2232 and USB Blaster are not supported with libpayload (missing libusb support) ifeq ($(CONFIG_DEDIPROG), yes) UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes else @@ -207,7 +212,12 @@ else override CONFIG_FT2232_SPI = no endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes +else +override CONFIG_USBBLASTER_SPI = no endif +endif
ifneq ($(TARGET_OS), Linux) ifeq ($(CONFIG_LINUX_SPI), yes) @@ -344,6 +354,9 @@ # Enable Linux spidev interface by default. We disable it on non-Linux targets. CONFIG_LINUX_SPI ?= yes
+# Always enable USB Blaster SPI for now.
we should get rid of this stupid duplicated all over again line (not your fault of course :)
+CONFIG_USBBLASTER_SPI ?= yes
# Disable wiki printing by default. It is only useful if you have wiki access. CONFIG_PRINT_WIKI ?= no
@@ -430,14 +443,31 @@ NEED_PCI := yes endif
+# This is a totally ugly hack. +WANT_LIBFTDI := no +HAVE_LIBFTDI := $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && echo "yes") ifeq ($(CONFIG_FT2232_SPI), yes) -FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") -# This is a totally ugly hack. -FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_FT2232_SPI=1'") -FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)") -PROGRAMMER_OBJS += ft2232_spi.o
- WANT_LIBFTDI := yes
- ifeq ($(HAVE_LIBFTDI), yes)
FEATURE_CFLAGS += -DCONFIG_FT2232_SPI=1
PROGRAMMER_OBJS += ft2232_spi.o
- endif
endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes)
- WANT_LIBFTDI := yes
- ifeq ($(HAVE_LIBFTDI), yes)
FEATURE_CFLAGS += -DCONFIG_USBBLASTER_SPI=1
PROGRAMMER_OBJS += usbblaster_spi.o
- endif
+endif
+ifeq ($(WANT_LIBFTDI), yes)
- ifeq ($(WANT_LIBFTDI), yes)
FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb")
FEATURE_LIBS += $(FTDILIBS)
- endif
+endif
i have not really looked at this hunk yet, but in general it looks ok, the double "ifeq ($(WANT_LIBFTDI), yes)" is wtf though :)
ifeq ($(CONFIG_DUMMY), yes) FEATURE_CFLAGS += -D'CONFIG_DUMMY=1' PROGRAMMER_OBJS += dummyflasher.o @@ -700,7 +730,7 @@
features: compiler @echo "FEATURES := yes" > .features.tmp -ifeq ($(CONFIG_FT2232_SPI), yes) +ifeq ($(WANT_LIBFTDI), yes) @printf "Checking for FTDI support... " @echo "$$FTDI_TEST" > .featuretest.c @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >/dev/null 2>&1 && \ Index: README =================================================================== --- README (revision 1548) +++ README (working copy) @@ -45,8 +45,8 @@ To build flashrom you need to install the following software:
- pciutils+libpci (if you want support for mainboard or PCI device flashing)
- libusb (if you want FT2232 or Dediprog support)
- libftdi (if you want FT2232 support)
- libusb (if you want FT2232, Dediprog or USB Blaster support)
- libftdi (if you want FT2232 or USB Blaster support)
Linux et al:
Index: usbblaster_spi.c
--- usbblaster_spi.c (revision 0) +++ usbblaster_spi.c (working copy) @@ -0,0 +1,258 @@ +/*
- This file is part of the flashrom project.
- Copyright (C) 2012 James Laird jhl@mafipulation.org
- 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; version 2 of the License.
- 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
- */
+/*
- Device should be connected as per "active serial" mode:
+---------+------+-----------+
| SPI | Pin | Altera |
+---------+------+-----------+
| SCLK | 1 | DCLK |
| GND | 2,10 | GND |
| VCC | 4 | VCC(TRGT) |
| MISO | 7 | ASDO |
| /CS | 8 | nCS |
| MOSI | 9 | ASDI |
hm... called "DATAOUT" in Table 2–2 in the "USB-Blaster Download Cable User Guide". some links to relevant documentation would be handy here too.
+---------+------+-----------+
- */
+#if CONFIG_USBBLASTER_SPI == 1
+#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include "flash.h" +#include "programmer.h" +#include "spi.h" +#include <ftdi.h>
+/* Please keep sorted by vendor ID, then device ID. */
+#define ALTERA_VID 0x09fb +#define ALTERA_USBBLASTER_PID 0x6001
+const struct usbdev_status devs_usbblasterspi[] = {
- {ALTERA_VID, ALTERA_USBBLASTER_PID, NT, "Altera", "USB Blaster"},
+ \n
- {},
+};
+static const struct spi_programmer spi_programmer_usbblaster;
+static struct ftdi_context ftdic;
+// command bytes +#define BIT_BYTE (1<<7) // byte mode (rather than bitbang) +#define BIT_READ (1<<6) // read request
in general we (seem to) try to avoid '//' although i am not really in favor of this.
+#define BIT_LED (1<<5) +#define BIT_CS (1<<3) +#define BIT_CLK (1<<0) +#define BIT_TMS (1<<1)
+#define BITS_OTHER 0
what's that?
+// The programmer shifts bits in the wrong order for SPI. +static unsigned char reverse[] = {
- 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
- 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
- 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
- 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
- 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
- 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
- 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
- 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
- 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
- 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
- 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
- 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
- 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
- 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
- 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
- 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
- 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
- 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
- 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
- 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
- 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
- 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
- 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
- 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
- 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
- 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
- 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
- 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
- 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
- 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
- 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
- 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
this has to die. my favorite is http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64Bits but anything without a lookup table would be better than this.
+/* Returns 0 upon success, a negative number upon errors. */ +int usbblaster_spi_init(void) +{
- if (ftdi_init(&ftdic) < 0)
return -1;
- if (ftdi_usb_open(&ftdic, ALTERA_VID, ALTERA_USBBLASTER_PID) < 0) {
msg_perr("Failed to open USB Blaster: %s\n", ftdic.error_str);
return -1;
- }
- if (ftdi_usb_reset(&ftdic) < 0) {
msg_perr("Blaster reset failed\n");
return -1;
- }
- if (ftdi_set_latency_timer(&ftdic, 2) < 0) {
msg_perr("Blaster set latency timer failed\n");
return -1;
- }
- if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 ||
why? macro?
ftdi_read_data_set_chunksize(&ftdic, 64) < 0) {
why? macro?
msg_perr("Blaster set chunk size failed\n");
return -1;
- }
- unsigned char buf[65];
why? macro? please do not use unsigned chars but uint8_t.
- memset(buf, 0, sizeof(buf));
- buf[sizeof(buf)-1] = BIT_LED | BITS_OTHER | BIT_CS;
- if (ftdi_write_data(&ftdic, buf, sizeof(buf)) < 0) {
msg_perr("Blaster reset write failed\n");
return -1;
- }
- if (ftdi_read_data(&ftdic, buf, sizeof(buf)) < 0) {
msg_perr("Blaster reset read failed\n");
return -1;
- }
- register_spi_programmer(&spi_programmer_usbblaster);
- return 0;
+}
+/* Returns 0 upon success, a negative number upon errors. */ +static int usbblaster_spi_send_command(struct flashctx *flash,
unsigned int writecnt, unsigned int readcnt,
const unsigned char *writearr,
unsigned char *readarr)
+{
- unsigned char cmd;
- unsigned char buf[64];
you know the drill ;)
- unsigned char tms_state = 0;
- int i;
- // assert /CS
- cmd = BIT_LED | BITS_OTHER;
- if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
msg_perr("Blaster write failed\n");
return -1;
- }
- while (writecnt) {
unsigned int n_write = writecnt;
if (n_write > 63)
n_write = 63;
looks slightly related to above which would mean there should be a single constant ;)
msg_pspew("writing %d-byte packet\n", n_write);
cmd = BIT_BYTE | (unsigned char)n_write;
buf[0] = cmd;
for (i=0; i<n_write; i++) {
buf[i+1] = reverse[writearr[i]];
}
if (ftdi_write_data(&ftdic, buf, n_write+1) < 0) {
msg_perr("Blaster write failed\n");
return -1;
}
cmd = BIT_LED | BITS_OTHER | (tms_state ^= BIT_TMS);
if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
msg_perr("Blaster write failed\n");
return -1;
}
writearr += n_write;
writecnt -= n_write;
- }
- unsigned int n_readout = readcnt;
if your know the upper limit of variables like this, then please use an appropriately dimensioned type of the uint*_t family.
- while (readcnt) {
unsigned int n_read = readcnt;
if (n_read > 63)
n_read = 63;
cmd = BIT_BYTE | BIT_READ | (unsigned char)n_read;
buf[0] = cmd;
if (ftdi_write_data(&ftdic, buf, n_read + 1) < 0) {
msg_perr("Blaster write failed\n");
return -1;
}
cmd = BIT_LED | BITS_OTHER | (tms_state ^= BIT_TMS);
if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
msg_perr("Blaster write failed\n");
return -1;
}
readcnt -= n_read;
msg_pspew("reading %d-byte packet\n", n_read);
- };
- unsigned int n_read = n_readout;
- while (n_read) {
int ret = ftdi_read_data(&ftdic, readarr, n_read);
if (ret < 0) {
msg_perr("Blaster read failed\n");
return -1;
}
for (i=0; i<ret; i++) {
readarr[i] = reverse[readarr[i]];
}
n_read -= ret;
readarr += ret;
- }
- cmd = BIT_LED | BIT_CS | BITS_OTHER;
- if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
msg_perr("Blaster write failed\n");
return -1;
- }
- cmd = BIT_CS | BITS_OTHER;
- if (ftdi_write_data(&ftdic, &cmd, 1) < 0) {
msg_perr("Blaster write failed\n");
return -1;
- }
thanks a lot for your effort! the only really mandatory change requirements are the one in the makefile and the reverse array. the others are partly personal opinions, but at least give them some thought when refining the patch please.
Adds support for the Altera USB-Blaster programming dongle in Active Serial (AS) mode. Tested on both original product and a clone dongle.
Signed-off-by: James Laird jhl@mafipulation.org Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com Signed-off-by: Stefan Tauner stefan.tauner@student.tuwien.ac.at ---
Rebased on Kyösti's version. Fixed Makefile and whitespace, cleaned up a few things, added a manpage... please retest on hardware.
Can someone please explain to me why send_read() does what it does?
Makefile | 49 +++++++++--- README | 4 +- flashrom.8 | 6 +- flashrom.c | 10 +++ print.c | 5 ++ programmer.h | 11 +++ usbblaster_spi.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 297 insertions(+), 13 deletions(-) create mode 100644 usbblaster_spi.c
diff --git a/Makefile b/Makefile index b087b3d..32f24ff 100644 --- a/Makefile +++ b/Makefile @@ -117,7 +117,7 @@ UNSUPPORTED_FEATURES += CONFIG_PONY_SPI=yes else override CONFIG_PONY_SPI = no endif -# Dediprog and FT2232 are not supported under DOS (missing USB support). +# Dediprog, FT2232 and USB-Blaster are not supported under DOS (missing USB support). ifeq ($(CONFIG_DEDIPROG), yes) UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes else @@ -128,6 +128,11 @@ UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes else override CONFIG_FT2232_SPI = no endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes +else +override CONFIG_USBBLASTER_SPI = no +endif endif
# FIXME: Should we check for Cygwin/MSVC as well? @@ -229,7 +234,7 @@ UNSUPPORTED_FEATURES += CONFIG_SERPROG=yes else override CONFIG_SERPROG = no endif -# Dediprog and FT2232 are not supported with libpayload (missing libusb support) +# Dediprog, FT2232 and USB-Blaster are not supported with libpayload (missing libusb support) ifeq ($(CONFIG_DEDIPROG), yes) UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes else @@ -240,6 +245,11 @@ UNSUPPORTED_FEATURES += CONFIG_FT2232_SPI=yes else override CONFIG_FT2232_SPI = no endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes) +UNSUPPORTED_FEATURES += CONFIG_USBBLASTER_SPI=yes +else +override CONFIG_USBBLASTER_SPI = no +endif endif
ifneq ($(TARGET_OS), Linux) @@ -382,6 +392,9 @@ CONFIG_SATAMV ?= yes # Enable Linux spidev interface by default. We disable it on non-Linux targets. CONFIG_LINUX_SPI ?= yes
+# Always enable USB-Blaster SPI for now. +CONFIG_USBBLASTER_SPI ?= yes + # Disable wiki printing by default. It is only useful if you have wiki access. CONFIG_PRINT_WIKI ?= no
@@ -473,13 +486,31 @@ PROGRAMMER_OBJS += atahpt.o NEED_PCI := yes endif
-ifeq ($(CONFIG_FT2232_SPI), yes) -FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") # This is a totally ugly hack. -FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_FT2232_SPI=1'") -FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FT232H := yes" .features && printf "%s" "-D'HAVE_FT232H=1'") -FEATURE_LIBS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "$(FTDILIBS)") -PROGRAMMER_OBJS += ft2232_spi.o +WANT_LIBFTDI := no +HAVE_LIBFTDI := $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && echo "yes") +ifeq ($(CONFIG_FT2232_SPI), yes) + WANT_LIBFTDI := yes + ifeq ($(HAVE_LIBFTDI), yes) + FEATURE_CFLAGS += -DCONFIG_FT2232_SPI=1 + PROGRAMMER_OBJS += ft2232_spi.o + endif +endif +ifeq ($(CONFIG_USBBLASTER_SPI), yes) + WANT_LIBFTDI := yes + ifeq ($(HAVE_LIBFTDI), yes) + FEATURE_CFLAGS += -DCONFIG_USBBLASTER_SPI=1 + PROGRAMMER_OBJS += usbblaster_spi.o + endif +endif + +ifeq ($(WANT_LIBFTDI), yes) + FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") + ifeq ($(HAVE_LIBFTDI), yes) + FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FT232H := yes" .features && printf "%s" "-D'HAVE_FT232H=1'") + FEATURE_LIBS += $(FTDILIBS) + endif + # else we will fail later endif
ifeq ($(CONFIG_DUMMY), yes) @@ -766,7 +797,7 @@ export LINUX_SPI_TEST
features: compiler @echo "FEATURES := yes" > .features.tmp -ifeq ($(CONFIG_FT2232_SPI), yes) +ifeq ($(WANT_LIBFTDI), yes) @printf "Checking for FTDI support... " @echo "$$FTDI_TEST" > .featuretest.c @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >/dev/null 2>&1 && \ diff --git a/README b/README index 8e812be..7f24cca 100644 --- a/README +++ b/README @@ -45,8 +45,8 @@ Build Instructions To build flashrom you need to install the following software:
* pciutils+libpci (if you want support for mainboard or PCI device flashing) - * libusb (if you want FT2232 or Dediprog support) - * libftdi (if you want FT2232 support) + * libusb (if you want FT2232, Dediprog or USB-Blaster support) + * libftdi (if you want FT2232 or USB-Blaster support)
Linux et al:
diff --git a/flashrom.8 b/flashrom.8 index b054c28..e07c800 100644 --- a/flashrom.8 +++ b/flashrom.8 @@ -217,6 +217,8 @@ bitbanging adapter) .sp .BR "* linux_spi" " (for SPI flash ROMs accessible via /dev/spidevX.Y on Linux)" .sp +.BR "* usbblaster_spi" " (for SPI flash ROMs attached to an Altera USB-Blaster compatible cable)" +.sp Some programmers have optional or mandatory parameters which are described in detail in the .B PROGRAMMER SPECIFIC INFO @@ -794,7 +796,7 @@ needs TCP access to the network or userspace access to a serial port. .B buspirate_spi needs userspace access to a serial port. .sp -.BR dediprog " and " ft2232_spi +.BR dediprog ", " ft2232_spi " and " usbblaster_spi need access to the USB device via libusb. .sp .B dummy @@ -804,7 +806,7 @@ needs no access permissions at all. .BR gfxnvidia ", " drkaiser ", " satasii ", " satamv " and " atahpt have to be run as superuser/root, and need additional raw access permission. .sp -.BR serprog ", " buspirate_spi ", " dediprog " and " ft2232_spi +.BR serprog ", " buspirate_spi ", " dediprog ", " usbblaster_spi " and " ft2232_spi can be run as normal user on most operating systems if appropriate device permissions are set. .sp diff --git a/flashrom.c b/flashrom.c index 2299b06..35e0579 100644 --- a/flashrom.c +++ b/flashrom.c @@ -262,6 +262,16 @@ const struct programmer_entry programmer_table[] = { }, #endif
+#if CONFIG_USBBLASTER_SPI == 1 + { + .name = "usbblaster_spi", + .init = usbblaster_spi_init, + .map_flash_region = fallback_map, + .unmap_flash_region = fallback_unmap, + .delay = internal_delay, + }, +#endif + {0}, /* This entry corresponds to PROGRAMMER_INVALID. */ };
diff --git a/print.c b/print.c index 5a27320..8df6e96 100644 --- a/print.c +++ b/print.c @@ -550,6 +550,11 @@ int print_supported(void) programmer_table[PROGRAMMER_LINUX_SPI].name); msg_ginfo("Device files /dev/spidev*.*\n"); #endif +#if CONFIG_USBBLASTER_SPI == 1 + msg_ginfo("\nSupported devices for the %s programmer:\n", + programmer_table[PROGRAMMER_USBBLASTER_SPI].name); + msg_ginfo("Altera USB-Blaster cable\n"); +#endif return 0; }
diff --git a/programmer.h b/programmer.h index dedec67..cb14fdf 100644 --- a/programmer.h +++ b/programmer.h @@ -87,6 +87,9 @@ enum programmer { #if CONFIG_LINUX_SPI == 1 PROGRAMMER_LINUX_SPI, #endif +#if CONFIG_USBBLASTER_SPI == 1 + PROGRAMMER_USBBLASTER_SPI, +#endif PROGRAMMER_INVALID /* This must always be the last entry. */ };
@@ -434,6 +437,11 @@ extern const struct usbdev_status devs_ft2232spi[]; void print_supported_usbdevs(const struct usbdev_status *devs); #endif
+/* usbblaster_spi.c */ +#if CONFIG_USBBLASTER_SPI == 1 +int usbblaster_spi_init(void); +#endif + /* rayer_spi.c */ #if CONFIG_RAYER_SPI == 1 int rayer_spi_init(void); @@ -512,6 +520,9 @@ enum spi_controller { #if CONFIG_SERPROG == 1 SPI_CONTROLLER_SERPROG, #endif +#if CONFIG_USBBLASTER_SPI == 1 + SPI_CONTROLLER_USBBLASTER, +#endif };
#define MAX_DATA_UNSPECIFIED 0 diff --git a/usbblaster_spi.c b/usbblaster_spi.c new file mode 100644 index 0000000..c99b745 --- /dev/null +++ b/usbblaster_spi.c @@ -0,0 +1,225 @@ +/* + * This file is part of the flashrom project. + * + * Copyright (C) 2012 James Laird jhl@mafipulation.org + * + * 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; version 2 of the License. + * + * 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 + */ + +/* + * Device should be connected as per "active serial" mode: + * + * +---------+------+-----------+ + * | SPI | Pin | Altera | + * +---------+------+-----------+ + * | SCLK | 1 | DCLK | + * | GND | 2,10 | GND | + * | VCC | 4 | VCC(TRGT) | + * | MISO | 7 | DATAOUT | + * | /CS | 8 | nCS | + * | MOSI | 9 | ASDI | + * +---------+------+-----------+ + * + * See also the USB-Blaster Download Cable User Guide: http://www.altera.com/literature/ug/ug_usb_blstr.pdf + */ + +#if CONFIG_USBBLASTER_SPI == 1 + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <ftdi.h> +#include "flash.h" +#include "programmer.h" +#include "spi.h" + +/* Please keep sorted by vendor ID, then device ID. */ +#define ALTERA_VID 0x09fb +#define ALTERA_USBBLASTER_PID 0x6001 + +const struct usbdev_status devs_usbblasterspi[] = { + {ALTERA_VID, ALTERA_USBBLASTER_PID, NT, "Altera", "USB-Blaster"}, + + {} +}; + +static const struct spi_programmer spi_programmer_usbblaster; + +static struct ftdi_context ftdic; + +// command bytes +#define BIT_BYTE (1<<7) // byte mode (rather than bitbang) +#define BIT_READ (1<<6) // read request +#define BIT_LED (1<<5) +#define BIT_CS (1<<3) +#define BIT_TMS (1<<1) +#define BIT_CLK (1<<0) + +#define BUF_SIZE 64 + +/* The programmer shifts bits in the wrong order for SPI, so we use this method to reverse the bits when needed. + * http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits */ +uint8_t reverse(uint8_t b) +{ + return ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16; +} + + +/* Returns 0 upon success, a negative number upon errors. */ +int usbblaster_spi_init(void) +{ + uint8_t buf[BUF_SIZE + 1]; + + if (ftdi_init(&ftdic) < 0) + return -1; + + if (ftdi_usb_open(&ftdic, ALTERA_VID, ALTERA_USBBLASTER_PID) < 0) { + msg_perr("Failed to open USB-Blaster: %s\n", ftdic.error_str); + return -1; + } + + if (ftdi_usb_reset(&ftdic) < 0) { + msg_perr("USB-Blaster reset failed\n"); + return -1; + } + + if (ftdi_set_latency_timer(&ftdic, 2) < 0) { + msg_perr("USB-Blaster set latency timer failed\n"); + return -1; + } + + if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 || + ftdi_read_data_set_chunksize(&ftdic, BUF_SIZE) < 0) { + msg_perr("USB-Blaster set chunk size failed\n"); + return -1; + } + + memset(buf, 0, sizeof(buf)); + buf[sizeof(buf)-1] = BIT_LED | BIT_CS; + if (ftdi_write_data(&ftdic, buf, sizeof(buf)) < 0) { + msg_perr("USB-Blaster reset write failed\n"); + return -1; + } + if (ftdi_read_data(&ftdic, buf, sizeof(buf)) < 0) { + msg_perr("USB-Blaster reset read failed\n"); + return -1; + } + + register_spi_programmer(&spi_programmer_usbblaster); + return 0; +} + +static int send_write(unsigned int writecnt, const unsigned char *writearr) +{ + int i; + uint8_t buf[BUF_SIZE]; + + memset(buf, 0, sizeof(buf)); + while (writecnt) { + unsigned int n_write = min(writecnt, BUF_SIZE - 1); + msg_pspew("writing %d-byte packet\n", n_write); + + buf[0] = BIT_BYTE | (uint8_t)n_write; + for (i = 0; i < n_write; i++) { + buf[i+1] = reverse(writearr[i]); + } + if (ftdi_write_data(&ftdic, buf, n_write + 1) < 0) { + msg_perr("USB-Blaster write failed\n"); + return -1; + } + + writearr += n_write; + writecnt -= n_write; + } + return 0; +} + +static int send_read(unsigned int readcnt, unsigned char *readarr) +{ + int i; + unsigned int n_read; + uint8_t buf[BUF_SIZE]; + memset(buf, 0, sizeof(buf)); + + n_read = readcnt; + while (n_read) { + unsigned int payload_size = min(n_read, BUF_SIZE - 1); + msg_pspew("reading %d-byte packet\n", payload_size); + + buf[0] = BIT_BYTE | BIT_READ | (uint8_t)payload_size; + if (ftdi_write_data(&ftdic, buf, payload_size + 1) < 0) { + msg_perr("USB-Blaster write failed\n"); + return -1; + } + n_read -= payload_size; + }; + + n_read = readcnt; + while (n_read) { + int ret = ftdi_read_data(&ftdic, readarr, n_read); + if (ret < 0) { + msg_perr("USB-Blaster read failed\n"); + return -1; + } + for (i = 0; i < ret; i++) { + readarr[i] = reverse(readarr[i]); + } + n_read -= ret; + readarr += ret; + } + return 0; +} + +/* Returns 0 upon success, a negative number upon errors. */ +static int usbblaster_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, + const unsigned char *writearr, unsigned char *readarr) +{ + uint8_t cmd; + int ret = 0; + + cmd = BIT_LED; // asserts /CS + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("USB-Blaster enable chip select failed\n"); + ret = -1; + } + + if (!ret && writecnt) + ret = send_write(writecnt, writearr); + + if (!ret && readcnt) + ret = send_read(readcnt, readarr); + + cmd = BIT_CS; + if (ftdi_write_data(&ftdic, &cmd, 1) < 0) { + msg_perr("USB-Blaster disable chip select failed\n"); + ret = -1; + } + + return ret; +} + + +static const struct spi_programmer spi_programmer_usbblaster = { + .type = SPI_CONTROLLER_USBBLASTER, + .max_data_read = 256, + .max_data_write = 256, + .command = usbblaster_spi_send_command, + .multicommand = default_spi_send_multicommand, + .read = default_spi_read, + .write_256 = default_spi_write_256, + .write_aai = default_spi_write_aai, +}; + +#endif