[flashrom] [PATCH 4/4] usbblaster: Use asynchronous bulk transfers
Kyösti Mälkki
kyosti.malkki at gmail.com
Sat Mar 30 19:31:35 CET 2013
There is minor speedup for using this.
Signed-off-by: Kyösti Mälkki <kyosti.malkki at gmail.com>
---
usbblaster.h | 63 +++++++++++++
usbblaster_spi.c | 282 ++++++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 278 insertions(+), 67 deletions(-)
create mode 100644 usbblaster.h
diff --git a/usbblaster.h b/usbblaster.h
new file mode 100644
index 0000000..d79384b
--- /dev/null
+++ b/usbblaster.h
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the flashrom project.
+ *
+ * Copyright (C) 2013 Kyösti Mälkki <kyosti.malkki at gmail.com>
+ *
+ * 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
+ */
+
+/* Please keep sorted by vendor ID, then device ID. */
+#define ALTERA_VID 0x09fb
+#define ALTERA_USBBLASTER_PID 0x6001
+
+// 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 PAYLOAD_TIMEOUT 0
+#define URB_COUNT 12
+#define MAX_PAYLOAD 64
+
+enum spi_direction {
+ READ_TDO, WRITE_TDI
+};
+
+struct blaster_block {
+ struct libusb_device_handle *usb_dev;
+ struct libusb_context *context;
+ uint8_t endpoint_in;
+ uint8_t endpoint_out;
+
+ enum spi_direction dir;
+ uint8_t *buf;
+ size_t len;
+ uint32_t wr_queued;
+ uint32_t wr_done;
+ uint32_t rd_queued;
+ uint32_t rd_done;
+ uint32_t complete;
+};
+
+struct blaster_control {
+ uint8_t buf[MAX_PAYLOAD];
+ size_t len;
+
+ struct blaster_block *block;
+ struct libusb_transfer *transfer;
+};
+
diff --git a/usbblaster_spi.c b/usbblaster_spi.c
index 86fd573..5b5e53a 100644
--- a/usbblaster_spi.c
+++ b/usbblaster_spi.c
@@ -2,6 +2,7 @@
* This file is part of the flashrom project.
*
* Copyright (C) 2012 James Laird <jhl at mafipulation.org>
+ * Copyright (C) 2013 Kyösti Mälkki <kyosti.malkki at gmail.com>
*
* 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
@@ -39,15 +40,15 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <unistd.h>
#include <ctype.h>
#include <ftdi.h>
+#include <libusb.h>
#include "flash.h"
#include "programmer.h"
#include "spi.h"
+#include "usbblaster.h"
-/* Please keep sorted by vendor ID, then device ID. */
-#define ALTERA_VID 0x09fb
-#define ALTERA_USBBLASTER_PID 0x6001
const struct dev_entry devs_usbblasterspi[] = {
{ALTERA_VID, ALTERA_USBBLASTER_PID, OK, "Altera", "USB-Blaster"},
@@ -59,28 +60,14 @@ 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;
-}
+static struct blaster_block block_template;
+static struct blaster_control tcs[URB_COUNT];
/* Returns 0 upon success, a negative number upon errors. */
int usbblaster_spi_init(void)
{
- uint8_t buf[BUF_SIZE + 1];
+ uint8_t buf[MAX_PAYLOAD + 1];
if (ftdi_init(&ftdic) < 0)
return -1;
@@ -101,7 +88,7 @@ int usbblaster_spi_init(void)
}
if (ftdi_write_data_set_chunksize(&ftdic, 4096) < 0 ||
- ftdi_read_data_set_chunksize(&ftdic, BUF_SIZE) < 0) {
+ ftdi_read_data_set_chunksize(&ftdic, MAX_PAYLOAD) < 0) {
msg_perr("USB-Blaster set chunk size failed\n");
return -1;
}
@@ -117,69 +104,230 @@ int usbblaster_spi_init(void)
return -1;
}
+ block_template.usb_dev = ftdic.usb_dev;
+ block_template.context = ftdic.usb_ctx;
+ /* Note the reversed view on endpoint direction. */
+ block_template.endpoint_in = ftdic.out_ep;
+ block_template.endpoint_out = ftdic.in_ep;
+
register_spi_programmer(&spi_programmer_usbblaster);
return 0;
}
-static int send_write(unsigned int writecnt, const unsigned char *writearr)
+static void init_block(struct blaster_block *tb, enum spi_direction dir, uint8_t *buf, size_t len)
+{
+ memcpy(tb, &block_template, sizeof(struct blaster_block));
+ tb->buf = buf;
+ tb->len = len;
+ tb->dir = dir;
+ /* On writes fast-forward read pointer to end. */
+ if (tb->dir == WRITE_TDI)
+ tb->rd_done = tb->len;
+}
+
+static int alloc_transfer(struct blaster_block *tb)
{
int i;
- uint8_t buf[BUF_SIZE];
+ memset(tcs, 0, sizeof(tcs));
+ for (i = 0; i < URB_COUNT; i++) {
+ tcs[i].block = tb;
+ tcs[i].transfer = libusb_alloc_transfer(0);
+ if (!tcs[i].transfer)
+ return -1;
+ }
+ return 0;
+}
+
+static void free_transfer(struct blaster_block *tb)
+{
+ int i;
+ for (i = 0; i < URB_COUNT; i++) {
+ libusb_free_transfer(tcs[i].transfer);
+ }
+}
+
+
+/*
+ *
+ *
+ */
+
+static int blaster_write(struct blaster_control *tc);
+static int blaster_read(struct blaster_control *tc, int forced);
+
+/* 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 */
+static uint8_t reverse(uint8_t b)
+{
+ return ((b * 0x0802LU & 0x22110LU) | (b * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
+}
- 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;
+static void blaster_write_cb(struct libusb_transfer *transfer)
+{
+ struct blaster_control *tc = (struct blaster_control *) transfer->user_data;
+ struct blaster_block *tb = tc->block;
+
+ transfer->user_data = NULL;
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
+ return;
+
+ tb->wr_done += transfer->length;
+ if ((tb->wr_done >= tb->len) && (tb->rd_done >= tb->len))
+ tb->complete = 1;
+
+ blaster_write(tc);
+}
+
+static int blaster_write(struct blaster_control *tc)
+{
+ struct blaster_block *tb = tc->block;
+ unsigned int n_write;
+ int i, ret;
+
+ n_write = tb->len - tb->wr_queued;
+ if (!n_write)
+ return 0;
+ if (n_write > MAX_PAYLOAD - 1)
+ n_write = MAX_PAYLOAD - 1;
+
+ if (tb->dir==WRITE_TDI) {
+ tc->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;
+ tc->buf[i + 1] = reverse(tb->buf[tb->wr_queued + i]);
}
-
- writearr += n_write;
- writecnt -= n_write;
+ tc->len = n_write + 1;
+ } else {
+ memset(tc->buf, 0, MAX_PAYLOAD);
+ tc->buf[0] = BIT_BYTE | BIT_READ | (uint8_t) n_write;
+ tc->len = n_write + 1;
}
- return 0;
+
+ memset(tc->transfer, 0, sizeof(struct libusb_transfer));
+ libusb_fill_bulk_transfer(tc->transfer, tb->usb_dev, tb->endpoint_out,
+ tc->buf, tc->len, blaster_write_cb, tc, PAYLOAD_TIMEOUT);
+
+ do {
+ ret = libusb_submit_transfer(tc->transfer);
+ } while (ret < 0);
+
+ tb->wr_queued += n_write;
+ return ret;
}
-static int send_read(unsigned int readcnt, unsigned char *readarr)
+
+static void blaster_read_cb(struct libusb_transfer *transfer)
{
+ struct blaster_control *tc = (struct blaster_control *) transfer->user_data;
+ struct blaster_block *tb = tc->block;
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);
+ transfer->user_data = NULL;
+ if (transfer->status != LIBUSB_TRANSFER_COMPLETED)
+ return;
- 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]);
+ /* Endpoint IN payload always begins with two status bytes. */
+ if (transfer->actual_length > 2) {
+ for (i = 0; i < (transfer->actual_length - 2); i++) {
+ tb->buf[tb->rd_done + i] = reverse(transfer->buffer[i + 2]);
}
- n_read -= ret;
- readarr += ret;
+ tb->rd_done += i;
}
- return 0;
+
+ if ((tb->rd_done >= tb->len) && (tb->wr_done >= tb->len))
+ tb->complete = 1;
+
+ blaster_read(tc, (tb->rd_done < tb->len));
+}
+
+static int blaster_read(struct blaster_control *tc, int forced)
+{
+ struct blaster_block *tb = tc->block;
+ int ret;
+
+ if (!forced && (tb->rd_queued >= tb->len))
+ return 0;
+
+ memset(tc->buf, 0, sizeof(tc->buf));
+ tc->len = MAX_PAYLOAD;
+
+ memset(tc->transfer, 0, sizeof(struct libusb_transfer));
+ libusb_fill_bulk_transfer(tc->transfer, tb->usb_dev, tb->endpoint_in,
+ tc->buf, tc->len, blaster_read_cb, tc, PAYLOAD_TIMEOUT);
+
+ do {
+ ret = libusb_submit_transfer(tc->transfer);
+ } while (ret < 0);
+
+ /* Endpoint IN payload always begins with two status bytes. */
+ tb->rd_queued += MAX_PAYLOAD - 2;
+ return ret;
+}
+
+static int do_transfer(struct blaster_block *tb)
+{
+ struct timeval timeout;
+ int i, j, ret = -1;
+
+ if (tb->dir==READ_TDO) {
+ /* To read data, must write data. */
+ for (i = 0; i < URB_COUNT / 2 - 2; i++)
+ blaster_write(&tcs[i]);
+ for (; i < URB_COUNT; i++)
+ blaster_read(&tcs[i], 0);
+ } else {
+ /* No need to read to write. */
+ for (i = 0; i < URB_COUNT; i++)
+ blaster_write(&tcs[i]);
+ }
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 5000;
+ while (!tb->complete) {
+ ret = libusb_handle_events_timeout(tb->context, &timeout);
+// if (ret<0)
+// break;
+ }
+
+ /* Cleanup URBs. */
+ for (i = 0; i < URB_COUNT; i++) {
+ libusb_cancel_transfer(tcs[i].transfer);
+ }
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 5000;
+ do {
+ libusb_handle_events_timeout(tb->context, &timeout);
+ j = 0;
+ for (i = 0; i < URB_COUNT; i++) {
+ if (tcs[i].transfer->user_data)
+ j++;
+ }
+ } while (j);
+
+ return ret;
+}
+
+static int send_write(unsigned int writecnt, const unsigned char *writearr)
+{
+ struct blaster_block block;
+ int ret;
+ init_block(&block, WRITE_TDI, (unsigned char*) writearr, writecnt);
+ alloc_transfer(&block);
+ ret = do_transfer(&block);
+ free_transfer(&block);
+ return ret;
+}
+
+static int send_read(unsigned int readcnt, unsigned char *readarr)
+{
+ struct blaster_block block;
+ int ret;
+ init_block(&block, READ_TDO, readarr, readcnt);
+ alloc_transfer(&block);
+ ret = do_transfer(&block);
+ free_transfer(&block);
+ return ret;
}
/* Returns 0 upon success, a negative number upon errors. */
@@ -213,8 +361,8 @@ static int usbblaster_spi_send_command(struct flashctx *flash, unsigned int writ
static const struct spi_programmer spi_programmer_usbblaster = {
.type = SPI_CONTROLLER_USBBLASTER,
- .max_data_read = 256,
- .max_data_write = 256,
+ .max_data_read = 8192,
+ .max_data_write = 8192,
.command = usbblaster_spi_send_command,
.multicommand = default_spi_send_multicommand,
.read = default_spi_read,
--
1.8.1.1
More information about the flashrom
mailing list