From: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net
Am 21.02.2013 01:46 schrieb Carl-Daniel Hailfinger:
Hi Nico,
thanks for your patch.
Am 16.11.2012 11:28 schrieb Nico Huber:
This patch tracks the changes in the libusb interface. Nothing changed in the behaviour of the driver, so far.
It will be used by a follow-up patch. It's based on "Enable spi clock setting in dediprog driver".
Signed-off-by: Nico Huber nico.huber@secunet.com
Review follows. The Makefile part checked for libusb 0.1, but it set the linker parameter for libusb 1.0. The code assumed that libusb_error_name() is always available, but that function was only introduced in libusb 1.0.9. There was a conflict between the added device parameter for multiple Dedipro SF100 devices on one PC (r1628) and the removal of get_device_by_vid_pid().
I have fixed and forward ported the code, please check that it works and looks sane.
This patch is completely untested, I only checked whether it compiles. If it works for you and looks sane, please tell me so I can commit.
Signed-off-by: Nico Huber nico.huber@secunet.com
New version. Fixed error messages and incomplete cleanup in the error case.
libusb header file location is still something I have to fix in another iteration.
Signed-off-by: Nico Huber nico.huber@secunet.com Signed-off-by: Carl-Daniel Hailfinger c-d.hailfinger.devel.2006@gmx.net --- Makefile | 58 +++++++++----- dediprog.c | 258 +++++++++++++++++++++++++++++++++---------------------------- 2 files changed, 178 insertions(+), 138 deletions(-)
diff --git a/Makefile b/Makefile index 07fefc0..96a7987 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 and FT2232 are not supported under DOS (missing libusb support). ifeq ($(CONFIG_DEDIPROG), yes) UNSUPPORTED_FEATURES += CONFIG_DEDIPROG=yes else @@ -504,8 +504,9 @@ ifeq ($(NEED_FTDI), yes) FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") 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)") -# We can't set NEED_USB here because that would transform libftdi auto-enabling +# We can't set NEED_LIBUSB1 here because that would transform libftdi auto-enabling # into a hard requirement for libusb, defeating the purpose of auto-enabling. +# Besides that, the old libftdi requires libusb 0.1, not libusb 1.0. endif
ifeq ($(CONFIG_DUMMY), yes) @@ -558,7 +559,7 @@ endif ifeq ($(CONFIG_DEDIPROG), yes) FEATURE_CFLAGS += -D'CONFIG_DEDIPROG=1' PROGRAMMER_OBJS += dediprog.o -NEED_USB := yes +NEED_LIBUSB1 := yes endif
ifeq ($(CONFIG_SATAMV), yes) @@ -613,10 +614,12 @@ endif endif endif
-ifeq ($(NEED_USB), yes) -CHECK_LIBUSB0 = yes -FEATURE_CFLAGS += -D'NEED_USB=1' -USBLIBS := $(shell pkg-config --libs libusb 2>/dev/null || printf "%s" "-lusb") +ifeq ($(NEED_LIBUSB1), yes) +CHECK_LIBUSB1 = yes +FEATURE_CFLAGS += -D'NEED_LIBUSB1=1' +FEATURE_CFLAGS += $(shell pkg-config --cflags libusb-1.0 2>/dev/null) +USBLIBS := $(shell pkg-config --libs libusb-1.0 2>/dev/null || printf "%s" "-lusb-1.0") +FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "LIBUSB1_ERROR_NAME := yes" .features && printf "%s" "-D'LIBUSB_HAVE_ERROR_NAME=1'") endif
ifeq ($(CONFIG_PRINT_WIKI), yes) @@ -711,17 +714,17 @@ int main(int argc, char **argv) endef export LIBPCI_TEST
-define LIBUSB0_TEST -#include <usb.h> +define LIBUSB1_TEST +#include <libusb.h> int main(int argc, char **argv) { (void) argc; (void) argv; - usb_init(); + libusb_init(NULL); return 0; } endef -export LIBUSB0_TEST +export LIBUSB1_TEST
hwlibs: compiler @printf "" > .libdeps @@ -744,18 +747,18 @@ ifeq ($(CHECK_LIBPCI), yes) rm -f .test.c .test.o .test$(EXEC_SUFFIX); exit 1) ) @rm -f .test.c .test.o .test$(EXEC_SUFFIX) endif -ifeq ($(CHECK_LIBUSB0), yes) - @printf "Checking for libusb-0.1/libusb-compat headers... " - @echo "$$LIBUSB0_TEST" > .test.c - @$(CC) -c $(CPPFLAGS) $(CFLAGS) .test.c -o .test.o >/dev/null && \ +ifeq ($(CHECK_LIBUSB1), yes) + @printf "Checking for libusb-1.0 headers... " + @echo "$$LIBUSB1_TEST" > .test.c + @$(CC) -c $(CPPFLAGS) $(FEATURE_CFLAGS) $(CFLAGS) .test.c -o .test.o >/dev/null && \ echo "found." || ( echo "not found."; echo; \ - echo "Please install libusb-0.1 headers or libusb-compat headers."; \ + echo "Please install libusb-1.0 headers."; \ echo "See README for more information."; echo; \ rm -f .test.c .test.o; exit 1) - @printf "Checking if libusb-0.1 is usable... " + @printf "Checking if libusb-1.0 is usable... " @$(CC) $(LDFLAGS) .test.o -o .test$(EXEC_SUFFIX) $(LIBS) $(USBLIBS) >/dev/null && \ echo "yes." || ( echo "no."; \ - echo "Please install libusb-0.1 or libusb-compat."; \ + echo "Please install libusb-1.0."; \ echo "See README for more information."; echo; \ rm -f .test.c .test.o .test$(EXEC_SUFFIX); exit 1) @rm -f .test.c .test.o .test$(EXEC_SUFFIX) @@ -777,6 +780,18 @@ ifneq ($(UNSUPPORTED_FEATURES), ) @false endif
+define LIBUSB1_ERROR_NAME_TEST +#include <libusb.h> +int main(int argc, char **argv) +{ + (void) argc; + (void) argv; + libusb_error_name(0); + return 0; +} +endef +export LIBUSB1_ERROR_NAME_TEST + define FTDI_TEST #include <ftdi.h> struct ftdi_context *ftdic = NULL; @@ -823,6 +838,13 @@ export LINUX_SPI_TEST
features: compiler @echo "FEATURES := yes" > .features.tmp +ifeq ($(CHECK_LIBUSB1), yes) + @printf "Checking for libusb_error_name support in libusb-1.0... " + @echo "$$LIBUSB1_ERROR_NAME_TEST" >> .featuretest.c + @$(CC) $(CPPFLAGS) $(FEATURE_CFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(USBLIBS) $(LIBS) >/dev/null 2>&1 && \ + ( echo "found."; echo "LIBUSB1_ERROR_NAME := yes" >> .features.tmp ) || \ + ( echo "not found." ) +endif ifeq ($(NEED_FTDI), yes) @printf "Checking for FTDI support... " @echo "$$FTDI_TEST" > .featuretest.c diff --git a/dediprog.c b/dediprog.c index ae86810..c33dc10 100644 --- a/dediprog.c +++ b/dediprog.c @@ -2,6 +2,7 @@ * This file is part of the flashrom project. * * Copyright (C) 2010 Carl-Daniel Hailfinger + * 2012 secunet Security Networks AG * * 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 @@ -21,7 +22,8 @@ #include <string.h> #include <limits.h> #include <errno.h> -#include <usb.h> +#include <stdlib.h> +#include <libusb.h> #include "flash.h" #include "chipdrivers.h" #include "programmer.h" @@ -29,7 +31,8 @@
#define FIRMWARE_VERSION(x,y,z) ((x << 16) | (y << 8) | z) #define DEFAULT_TIMEOUT 3000 -static usb_dev_handle *dediprog_handle; +static libusb_context *usb_ctx; +static libusb_device_handle *dediprog_handle; static int dediprog_firmwareversion; static int dediprog_endpoint;
@@ -47,27 +50,63 @@ static void print_hex(void *buf, size_t len) } #endif
+#ifndef LIBUSB_HAVE_ERROR_NAME +/* Quick and dirty replacement for missing libusb_error_name in older libusb 1.0. */ +const char *libusb_error_name(int error_code) +{ + /* 18 chars for text, rest for number, sign, nullbyte. */ + static char my_libusb_error[18 + 3 * sizeof(int) + 2]; + + sprintf(my_libusb_error, "libusb error code %i", error_code); + return my_libusb_error; +} +#endif + /* Might be useful for other USB devices as well. static for now. */ /* device parameter allows user to specify one device of multiple installed */ -static struct usb_device *get_device_by_vid_pid(uint16_t vid, uint16_t pid, unsigned int device) +static struct libusb_device_handle *get_device_by_vid_pid_number(uint16_t vid, uint16_t pid, unsigned int num) { - struct usb_bus *bus; - struct usb_device *dev; - - for (bus = usb_get_busses(); bus; bus = bus->next) - for (dev = bus->devices; dev; dev = dev->next) - if ((dev->descriptor.idVendor == vid) && - (dev->descriptor.idProduct == pid)) { - if (device == 0) - return dev; - device--; + struct libusb_device **list; + ssize_t i = 0; + int err = 0; + struct libusb_device_handle *handle = NULL; + struct libusb_device_descriptor desc = {}; + ssize_t count = libusb_get_device_list(usb_ctx, &list); + + if (count < 0) { + msg_perr("Getting the USB device list failed (%s)!\n", libusb_error_name(count)); + return NULL; + } + + for (i = 0; i < count; i++) { + struct libusb_device *dev = list[i]; + err = libusb_get_device_descriptor(dev, &desc); + if (err != 0) { + msg_perr("Reading the USB device descriptor failed (%s)!\n", libusb_error_name(err)); + libusb_free_device_list(list, 1); + return NULL; + } + if ((desc.idVendor == vid) && (desc.idProduct == pid)) { + msg_pdbg("Found USB device %04hx:%04hx at address %hhx-%hhx.\n", desc.idVendor, + desc.idProduct, libusb_get_bus_number(dev), libusb_get_device_address(dev)); + if (num == 0) { + err = libusb_open(dev, &handle); + if (err != 0) { + msg_perr("Opening the USB device failed (%s)!\n", + libusb_error_name(err)); + libusb_free_device_list(list, 1); + return NULL; + } + break; } + num--; + } + } + libusb_free_device_list(list, 1);
- return NULL; + return handle; }
-//int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout); - /* Set/clear LEDs on dediprog */ #define PASS_ON (0 << 0) #define PASS_OFF (1 << 0) @@ -101,11 +140,10 @@ static int dediprog_set_leds(int leds) target_leds = leds; }
- ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, target_leds, - NULL, 0x0, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0x42, 0x07, 0x09, target_leds, + NULL, 0x0, DEFAULT_TIMEOUT); if (ret != 0x0) { - msg_perr("Command Set LED 0x%x failed (%s)!\n", - leds, usb_strerror()); + msg_perr("Command Set LED 0x%x failed (%s)!\n", leds, libusb_error_name(ret)); return 1; }
@@ -144,8 +182,8 @@ static int dediprog_set_spi_voltage(int millivolt) /* Wait some time as the original driver does. */ programmer_delay(200 * 1000); } - ret = usb_control_msg(dediprog_handle, 0x42, 0x9, voltage_selector, - 0xff, NULL, 0x0, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0x42, 0x9, voltage_selector, + 0xff, NULL, 0x0, DEFAULT_TIMEOUT); if (ret != 0x0) { msg_perr("Command Set SPI Voltage 0x%x failed!\n", voltage_selector); @@ -188,8 +226,8 @@ static int dediprog_set_spi_speed(unsigned int spispeed_idx)
msg_pdbg("SPI speed is %sHz\n", spispeeds[spispeed_idx].name);
- ret = usb_control_msg(dediprog_handle, 0x42, 0x61, spispeeds[spispeed_idx].speed, 0xff, - NULL, 0x0, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0x42, 0x61, spispeeds[spispeed_idx].speed, 0xff, + NULL, 0x0, DEFAULT_TIMEOUT); if (ret != 0x0) { msg_perr("Command Set SPI Speed 0x%x failed!\n", spispeeds[spispeed_idx].speed); return 1; @@ -205,15 +243,15 @@ static int dediprog_set_spi_speed(unsigned int spispeed_idx) static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) { - int ret; + int ret, transferred; unsigned int i; /* chunksize must be 512, other sizes will NOT work at all. */ const unsigned int chunksize = 0x200; const unsigned int count = len / chunksize; - const char count_and_chunk[] = {count & 0xff, - (count >> 8) & 0xff, - chunksize & 0xff, - (chunksize >> 8) & 0xff}; + const unsigned char count_and_chunk[] = { + count & 0xff, (count >> 8) & 0xff, + chunksize & 0xff, (chunksize >> 8) & 0xff + };
if ((start % chunksize) || (len % chunksize)) { msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug " @@ -227,22 +265,20 @@ static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, /* Command Read SPI Bulk. No idea which read command is used on the * SPI side. */ - ret = usb_control_msg(dediprog_handle, 0x42, 0x20, start % 0x10000, - start / 0x10000, (char *)count_and_chunk, - sizeof(count_and_chunk), DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0x42, 0x20, start % 0x10000, start / 0x10000, + (unsigned char *)count_and_chunk, sizeof(count_and_chunk), + DEFAULT_TIMEOUT); if (ret != sizeof(count_and_chunk)) { - msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, - usb_strerror()); + msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, libusb_error_name(ret)); return 1; }
for (i = 0; i < count; i++) { - ret = usb_bulk_read(dediprog_handle, 0x80 | dediprog_endpoint, - (char *)buf + i * chunksize, chunksize, - DEFAULT_TIMEOUT); - if (ret != chunksize) { - msg_perr("SPI bulk read %i failed, expected %i, got %i " - "%s!\n", i, chunksize, ret, usb_strerror()); + ret = libusb_bulk_transfer(dediprog_handle, 0x80 | dediprog_endpoint, + buf + i * chunksize, chunksize, &transferred, DEFAULT_TIMEOUT); + if ((ret < 0) || (transferred != chunksize)) { + msg_perr("SPI bulk read %i failed, expected %i, got %i %s!\n", + i, chunksize, ret, libusb_error_name(ret)); return 1; } } @@ -306,7 +342,7 @@ static int dediprog_spi_read(struct flashctx *flash, uint8_t *buf, static int dediprog_spi_bulk_write(struct flashctx *flash, uint8_t *buf, unsigned int chunksize, unsigned int start, unsigned int len, uint8_t dedi_spi_cmd) { - int ret; + int ret, transferred; unsigned int i; /* USB transfer size must be 512, other sizes will NOT work at all. * chunksize is the real data size per USB bulk transfer. The remaining @@ -314,7 +350,7 @@ static int dediprog_spi_bulk_write(struct flashctx *flash, uint8_t *buf, unsigne */ const unsigned int count = len / chunksize; const char count_and_cmd[] = {count & 0xff, (count >> 8) & 0xff, 0x00, dedi_spi_cmd}; - char usbbuf[512]; + unsigned char usbbuf[512];
/* * We should change this check to @@ -339,23 +375,21 @@ static int dediprog_spi_bulk_write(struct flashctx *flash, uint8_t *buf, unsigne /* Command Write SPI Bulk. No idea which write command is used on the * SPI side. */ - ret = usb_control_msg(dediprog_handle, 0x42, 0x30, start % 0x10000, start / 0x10000, - (char *)count_and_cmd, sizeof(count_and_cmd), DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0x42, 0x30, start % 0x10000, start / 0x10000, + (unsigned char *)count_and_cmd, sizeof(count_and_cmd), DEFAULT_TIMEOUT); if (ret != sizeof(count_and_cmd)) { - msg_perr("Command Write SPI Bulk failed, %i %s!\n", ret, - usb_strerror()); + msg_perr("Command Write SPI Bulk failed, %i %s!\n", ret, libusb_error_name(ret)); return 1; }
for (i = 0; i < count; i++) { memset(usbbuf, 0xff, sizeof(usbbuf)); memcpy(usbbuf, buf + i * chunksize, chunksize); - ret = usb_bulk_write(dediprog_handle, dediprog_endpoint, - usbbuf, 512, - DEFAULT_TIMEOUT); - if (ret != 512) { - msg_perr("SPI bulk write failed, expected %i, got %i " - "%s!\n", 512, ret, usb_strerror()); + ret = libusb_bulk_transfer(dediprog_handle, dediprog_endpoint, + usbbuf, 512, &transferred, DEFAULT_TIMEOUT); + if ((ret < 0) || (transferred != 512)) { + msg_perr("SPI bulk write failed, expected %i, got %i %s!\n", + 512, ret, libusb_error_name(ret)); return 1; } } @@ -444,23 +478,20 @@ static int dediprog_spi_send_command(struct flashctx *flash, msg_perr("Untested readcnt=%i, aborting.\n", readcnt); return 1; } - - ret = usb_control_msg(dediprog_handle, 0x42, 0x1, 0xff, - readcnt ? 0x1 : 0x0, (char *)writearr, writecnt, - DEFAULT_TIMEOUT); + + ret = libusb_control_transfer(dediprog_handle, 0x42, 0x1, 0xff, readcnt ? 0x1 : 0x0, + (unsigned char *)writearr, writecnt, DEFAULT_TIMEOUT); if (ret != writecnt) { - msg_perr("Send SPI failed, expected %i, got %i %s!\n", - writecnt, ret, usb_strerror()); + msg_perr("Send SPI failed, expected %i, got %i %s!\n", writecnt, ret, libusb_error_name(ret)); return 1; } if (!readcnt) return 0; memset(readarr, 0, readcnt); - ret = usb_control_msg(dediprog_handle, 0xc2, 0x01, 0xbb8, 0x0000, - (char *)readarr, readcnt, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0xc2, 0x01, 0xbb8, 0x0000, + readarr, readcnt, DEFAULT_TIMEOUT); if (ret != readcnt) { - msg_perr("Receive SPI failed, expected %i, got %i %s!\n", - readcnt, ret, usb_strerror()); + msg_perr("Receive SPI failed, expected %i, got %i %s!\n", readcnt, ret, libusb_error_name(ret)); return 1; } return 0; @@ -470,22 +501,18 @@ static int dediprog_check_devicestring(void) { int ret; int fw[3]; - char buf[0x11]; + unsigned char buf[0x11];
/* Command Prepare Receive Device String. */ memset(buf, 0, sizeof(buf)); - ret = usb_control_msg(dediprog_handle, 0xc3, 0x7, 0x0, 0xef03, buf, - 0x1, DEFAULT_TIMEOUT); - /* The char casting is needed to stop gcc complaining about an always true comparison. */ - if ((ret != 0x1) || (buf[0] != (char)0xff)) { - msg_perr("Unexpected response to Command Prepare Receive Device" - " String!\n"); + ret = libusb_control_transfer(dediprog_handle, 0xc3, 0x7, 0x0, 0xef03, buf, 0x1, DEFAULT_TIMEOUT); + if ((ret != 0x1) || (buf[0] != 0xff)) { + msg_perr("Unexpected response to Command Prepare Receive Device String!\n"); return 1; } /* Command Receive Device String. */ memset(buf, 0, sizeof(buf)); - ret = usb_control_msg(dediprog_handle, 0xc2, 0x8, 0xff, 0xff, buf, - 0x10, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0xc2, 0x8, 0xff, 0xff, buf, 0x10, DEFAULT_TIMEOUT); if (ret != 0x10) { msg_perr("Incomplete/failed Command Receive Device String!\n"); return 1; @@ -496,7 +523,7 @@ static int dediprog_check_devicestring(void) msg_perr("Device not a SF100!\n"); return 1; } - if (sscanf(buf, "SF100 V:%d.%d.%d ", &fw[0], &fw[1], &fw[2]) != 3) { + if (sscanf((const char *)buf, "SF100 V:%d.%d.%d ", &fw[0], &fw[1], &fw[2]) != 3) { msg_perr("Unexpected firmware version string!\n"); return 1; } @@ -517,13 +544,12 @@ static int dediprog_check_devicestring(void) static int dediprog_command_a(void) { int ret; - char buf[0x1]; + unsigned char buf[0x1];
memset(buf, 0, sizeof(buf)); - ret = usb_control_msg(dediprog_handle, 0xc3, 0xb, 0x0, 0x0, buf, - 0x1, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0xc3, 0xb, 0x0, 0x0, buf, 0x1, DEFAULT_TIMEOUT); if (ret < 0) { - msg_perr("Command A failed (%s)!\n", usb_strerror()); + msg_perr("Command A failed (%s)!\n", libusb_error_name(ret)); return 1; } if ((ret != 0x1) || (buf[0] != 0x6f)) { @@ -541,13 +567,12 @@ static int dediprog_command_a(void) static int dediprog_command_b(void) { int ret; - char buf[0x3]; + unsigned char buf[0x3];
memset(buf, 0, sizeof(buf)); - ret = usb_control_msg(dediprog_handle, 0xc3, 0x7, 0x0, 0xef00, buf, - 0x3, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0xc3, 0x7, 0x0, 0xef00, buf, 0x3, DEFAULT_TIMEOUT); if (ret < 0) { - msg_perr("Command B failed (%s)!\n", usb_strerror()); + msg_perr("Command B failed (%s)!\n", libusb_error_name(ret)); return 1; } if ((ret != 0x3) || (buf[0] != 0xff) || (buf[1] != 0xff) || @@ -569,10 +594,9 @@ static int dediprog_command_c(void) { int ret;
- ret = usb_control_msg(dediprog_handle, 0x42, 0x4, 0x0, 0x0, NULL, - 0x0, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0x42, 0x4, 0x0, 0x0, NULL, 0x0, DEFAULT_TIMEOUT); if (ret != 0x0) { - msg_perr("Command C failed (%s)!\n", usb_strerror()); + msg_perr("Command C failed (%s)!\n", libusb_error_name(ret)); return 1; } return 0; @@ -587,17 +611,16 @@ static int dediprog_command_c(void) static int dediprog_command_f(int timeout) { int ret; - char buf[0x1]; + unsigned char buf[0x1];
memset(buf, 0, sizeof(buf)); - ret = usb_control_msg(dediprog_handle, 0xc2, 0x11, 0xff, 0xff, buf, - 0x1, timeout); + ret = libusb_control_transfer(dediprog_handle, 0xc2, 0x11, 0xff, 0xff, buf, 0x1, timeout); /* This check is most probably wrong. Command F always causes a timeout * in the logs, so we should check for timeout instead of checking for * success. */ if (ret != 0x1) { - msg_perr("Command F failed (%s)!\n", usb_strerror()); + msg_perr("Command F failed (%s)!\n", libusb_error_name(ret)); return 1; } return 0; @@ -611,9 +634,9 @@ static int dediprog_command_g(void) { int ret;
- ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x03, NULL, 0x0, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0x42, 0x07, 0x09, 0x03, NULL, 0x0, DEFAULT_TIMEOUT); if (ret != 0x0) { - msg_perr("Command G failed (%s)!\n", usb_strerror()); + msg_perr("Command G failed (%s)!\n", libusb_error_name(ret)); return 1; } return 0; @@ -628,9 +651,9 @@ static int dediprog_command_h(void) { int ret;
- ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x05, NULL, 0x0, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0x42, 0x07, 0x09, 0x05, NULL, 0x0, DEFAULT_TIMEOUT); if (ret != 0x0) { - msg_perr("Command H failed (%s)!\n", usb_strerror()); + msg_perr("Command H failed (%s)!\n", libusb_error_name(ret)); return 1; } return 0; @@ -645,9 +668,9 @@ static int dediprog_command_i(void) { int ret;
- ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x06, NULL, 0x0, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0x42, 0x07, 0x09, 0x06, NULL, 0x0, DEFAULT_TIMEOUT); if (ret != 0x0) { - msg_perr("Command I failed (%s)!\n", usb_strerror()); + msg_perr("Command I failed (%s)!\n", libusb_error_name(ret)); return 1; } return 0; @@ -665,9 +688,9 @@ static int dediprog_command_j(void) { int ret;
- ret = usb_control_msg(dediprog_handle, 0x42, 0x07, 0x09, 0x07, NULL, 0x0, DEFAULT_TIMEOUT); + ret = libusb_control_transfer(dediprog_handle, 0x42, 0x07, 0x09, 0x07, NULL, 0x0, DEFAULT_TIMEOUT); if (ret != 0x0) { - msg_perr("Command J failed (%s)!\n", usb_strerror()); + msg_perr("Command J failed (%s)!\n", libusb_error_name(ret)); return 1; } return 0; @@ -770,21 +793,18 @@ static int dediprog_shutdown(void *data) if (dediprog_set_spi_voltage(0x0)) return 1;
- if (usb_release_interface(dediprog_handle, 0)) { + if (libusb_release_interface(dediprog_handle, 0)) { msg_perr("Could not release USB interface!\n"); return 1; } - if (usb_close(dediprog_handle)) { - msg_perr("Could not close USB device!\n"); - return 1; - } + libusb_close(dediprog_handle); + libusb_exit(usb_ctx); return 0; }
/* URB numbers refer to the first log ever captured. */ int dediprog_init(void) { - struct usb_device *dev; char *voltage, *device, *spispeed; int spispeed_idx = 2; int millivolt = 3500; @@ -842,31 +862,29 @@ int dediprog_init(void) free(device);
/* Here comes the USB stuff. */ - usb_init(); - usb_find_busses(); - usb_find_devices(); - dev = get_device_by_vid_pid(0x0483, 0xdada, (unsigned int) usedevice); - if (!dev) { + libusb_init(&usb_ctx); + if (!usb_ctx) { + msg_perr("Could not initialize libusb!\n"); + return 1; + } + dediprog_handle = get_device_by_vid_pid_number(0x0483, 0xdada, (unsigned int) usedevice); + if (!dediprog_handle) { msg_perr("Could not find a Dediprog SF100 on USB!\n"); + libusb_exit(usb_ctx); return 1; } - msg_pdbg("Found USB device (%04x:%04x).\n", - dev->descriptor.idVendor, dev->descriptor.idProduct); - dediprog_handle = usb_open(dev); - ret = usb_set_configuration(dediprog_handle, 1); - if (ret < 0) { - msg_perr("Could not set USB device configuration: %i %s\n", - ret, usb_strerror()); - if (usb_close(dediprog_handle)) - msg_perr("Could not close USB device!\n"); + ret = libusb_set_configuration(dediprog_handle, 1); + if (ret != 0) { + msg_perr("Could not set USB device configuration: %i %s\n", ret, libusb_error_name(ret)); + libusb_close(dediprog_handle); + libusb_exit(usb_ctx); return 1; } - ret = usb_claim_interface(dediprog_handle, 0); + ret = libusb_claim_interface(dediprog_handle, 0); if (ret < 0) { - msg_perr("Could not claim USB device interface %i: %i %s\n", - 0, ret, usb_strerror()); - if (usb_close(dediprog_handle)) - msg_perr("Could not close USB device!\n"); + msg_perr("Could not claim USB device interface %i: %i %s\n", 0, ret, libusb_error_name(ret)); + libusb_close(dediprog_handle); + libusb_exit(usb_ctx); return 1; } dediprog_endpoint = 2;
From: Nico Huber nico.huber@secunet.com
This utilizes libusb-1.0's interface for asynchronous transfers. A read is split into 512 byte chunks as required by the dediprog hardware. Up to eight chunks are scheduled for asynchronous transfer which results in a viable speed-up. First tests have shown a three times speed increase.
Signed-off-by: Nico Huber nico.huber@secunet.com --- dediprog.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 9 deletions(-)
diff --git a/dediprog.c b/dediprog.c index c33dc10..2fdcca6 100644 --- a/dediprog.c +++ b/dediprog.c @@ -31,6 +31,7 @@
#define FIRMWARE_VERSION(x,y,z) ((x << 16) | (y << 8) | z) #define DEFAULT_TIMEOUT 3000 +#define DEDIPROG_ASYNC_TRANSFERS 8 /* at most 8 asynchronous transfers */ static libusb_context *usb_ctx; static libusb_device_handle *dediprog_handle; static int dediprog_firmwareversion; @@ -235,6 +236,38 @@ static int dediprog_set_spi_speed(unsigned int spispeed_idx) return 0; }
+struct dediprog_transfer_status { + int error; /* OK if 0, ERROR else */ + unsigned int queued_idx; + unsigned int finished_idx; +}; + +static void dediprog_bulk_read_cb(struct libusb_transfer *const transfer) +{ + struct dediprog_transfer_status *const status = (struct dediprog_transfer_status *)transfer->user_data; + if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { + status->error = 1; + msg_perr("SPI bulk read failed!\n"); + } + ++status->finished_idx; +} + +static int dediprog_bulk_read_poll(const struct dediprog_transfer_status *const status, const int finish) +{ + if (status->finished_idx >= status->queued_idx) + return 0; + + do { + struct timeval timeout = { 10, 0 }; + const int ret = libusb_handle_events_timeout_completed(usb_ctx, &timeout, NULL); + if (ret < 0) { + msg_perr("Polling read events failed: %i %s!\n", ret, libusb_error_name(ret)); + return 1; + } + } while (finish && (status->finished_idx < status->queued_idx)); + return 0; +} + /* Bulk read interface, will read multiple 512 byte chunks aligned to 512 bytes. * @start start address * @len length @@ -243,7 +276,7 @@ static int dediprog_set_spi_speed(unsigned int spispeed_idx) static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) { - int ret, transferred; + int ret, err = 1; unsigned int i; /* chunksize must be 512, other sizes will NOT work at all. */ const unsigned int chunksize = 0x200; @@ -253,6 +286,10 @@ static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, chunksize & 0xff, (chunksize >> 8) & 0xff };
+ struct dediprog_transfer_status status = { 0, 0, 0 }; + struct libusb_transfer *transfers[DEDIPROG_ASYNC_TRANSFERS] = { NULL, }; + struct libusb_transfer *transfer; + if ((start % chunksize) || (len % chunksize)) { msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug " "at flashrom@flashrom.org\n", __func__, start, len); @@ -273,17 +310,54 @@ static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, return 1; }
- for (i = 0; i < count; i++) { - ret = libusb_bulk_transfer(dediprog_handle, 0x80 | dediprog_endpoint, - buf + i * chunksize, chunksize, &transferred, DEFAULT_TIMEOUT); - if ((ret < 0) || (transferred != chunksize)) { - msg_perr("SPI bulk read %i failed, expected %i, got %i %s!\n", - i, chunksize, ret, libusb_error_name(ret)); - return 1; + /* + * Ring buffer of bulk transfers. + * Poll until at least one transfer is ready, + * schedule next transfers until buffer is full. + */ + + /* Allocate bulk transfers. */ + for (i = 0; i < min(DEDIPROG_ASYNC_TRANSFERS, count); ++i) { + transfers[i] = libusb_alloc_transfer(0); + if (!transfers[i]) { + msg_perr("Allocating libusb transfer %i failed: %s!\n", i, libusb_error_name(ret)); + goto _err_free; } }
- return 0; + /* Now transfer requested chunks using libusb's asynchronous interface. */ + while (!status.error && (status.queued_idx < count)) { + while ((status.queued_idx - status.finished_idx) < DEDIPROG_ASYNC_TRANSFERS) { + transfer = transfers[status.queued_idx % DEDIPROG_ASYNC_TRANSFERS]; + libusb_fill_bulk_transfer(transfer, dediprog_handle, 0x80 | dediprog_endpoint, + (unsigned char *)buf + status.queued_idx * chunksize, chunksize, + dediprog_bulk_read_cb, &status, DEFAULT_TIMEOUT); + transfer->flags |= LIBUSB_TRANSFER_SHORT_NOT_OK; + ret = libusb_submit_transfer(transfer); + if (ret < 0) { + msg_perr("Submitting SPI bulk read %i failed: %i %s!\n", + status.queued_idx, ret, libusb_error_name(ret)); + goto _err_free; + } + ++status.queued_idx; + } + if (dediprog_bulk_read_poll(&status, 0)) + goto _err_free; + } + /* Wait for transfers to finish. */ + if (dediprog_bulk_read_poll(&status, 1)) + goto _err_free; + /* Check if everything has been transmitted. */ + if ((status.finished_idx < count) || status.error) + goto _err_free; + + err = 0; + +_err_free: + dediprog_bulk_read_poll(&status, 1); + for (i = 0; i < DEDIPROG_ASYNC_TRANSFERS; ++i) + if (transfers[i]) libusb_free_transfer(transfers[i]); + return err; }
static int dediprog_spi_read(struct flashctx *flash, uint8_t *buf,
On Sat, 30 Mar 2013 20:31:33 +0200 Kyösti Mälkki kyosti.malkki@gmail.com wrote:
From: Nico Huber nico.huber@secunet.com
This utilizes libusb-1.0's interface for asynchronous transfers. A read is split into 512 byte chunks as required by the dediprog hardware. Up to eight chunks are scheduled for asynchronous transfer which results in a viable speed-up. First tests have shown a three times speed increase.
Signed-off-by: Nico Huber nico.huber@secunet.com
Since we default to dediprog support now I have backported that patch but I don't see any speed up at all. Nico said the speedup was seen when using VirtualBox (Linux on Linux). I have tested with Linux native and Windows XP guest on Linux but don't see any difference. I will repost my version of the patch later tonight.
These are basically combined patches from David et al. backported and improved where I discovered a potential for it. Requires the libusb1 support patch...
Stefan Tauner (3): dediprog: add support for SF600. dediprog: use command 0x0B (set voltage) only on older SF100s. dediprog: port to libusb1 and use asynchronous bulk transfers for reading.
Makefile | 2 +- dediprog.c | 379 ++++++++++++++++++++++++++++++++++++++++---------------- flashrom.8.tmpl | 5 +- pickit2_spi.c | 5 +- 4 files changed, 279 insertions(+), 112 deletions(-)
Update to libftdi-1.0 is advertised as a drop-in replacement for libftdi, running on top of libusb-1.0. This also removes indirect dependency to libusb-0.1.
NOTE: pre-compiled libftdi-1.0 packages may not be available yet NOTE: package named libftdi1 may install libftdi-0.19 (debian)
Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com --- Makefile | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/Makefile b/Makefile index 96a7987..561c67c 100644 --- a/Makefile +++ b/Makefile @@ -489,19 +489,21 @@ endif ifeq ($(CONFIG_FT2232_SPI), yes) # This is a totally ugly hack. FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_FT2232_SPI=1'") -NEED_FTDI := yes +NEED_FTDI1 := yes PROGRAMMER_OBJS += ft2232_spi.o endif
ifeq ($(CONFIG_USBBLASTER_SPI), yes) # This is a totally ugly hack. FEATURE_CFLAGS += $(shell LC_ALL=C grep -q "FTDISUPPORT := yes" .features && printf "%s" "-D'CONFIG_USBBLASTER_SPI=1'") -NEED_FTDI := yes +NEED_LIBUSB1 := yes +NEED_FTDI1 := yes PROGRAMMER_OBJS += usbblaster_spi.o endif
-ifeq ($(NEED_FTDI), yes) -FTDILIBS := $(shell pkg-config --libs libftdi 2>/dev/null || printf "%s" "-lftdi -lusb") +ifeq ($(NEED_FTDI1), yes) +FTDILIBS := $(shell pkg-config --libs libftdi1 2>/dev/null || printf "%s" "-lftdi1 -lusb-1.0") +FEATURE_CFLAGS += $(shell pkg-config --cflags libftdi1 2>/dev/null) 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)") # We can't set NEED_LIBUSB1 here because that would transform libftdi auto-enabling @@ -793,6 +795,7 @@ endef export LIBUSB1_ERROR_NAME_TEST
define FTDI_TEST +#include <stddef.h> #include <ftdi.h> struct ftdi_context *ftdic = NULL; int main(int argc, char **argv) @@ -805,6 +808,7 @@ endef export FTDI_TEST
define FTDI_232H_TEST +#include <stddef.h> #include <ftdi.h> enum ftdi_chip_type type = TYPE_232H; endef @@ -845,15 +849,15 @@ ifeq ($(CHECK_LIBUSB1), yes) ( echo "found."; echo "LIBUSB1_ERROR_NAME := yes" >> .features.tmp ) || \ ( echo "not found." ) endif -ifeq ($(NEED_FTDI), yes) +ifeq ($(NEED_FTDI1), 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 && \ + @$(CC) $(CPPFLAGS) $(CFLAGS) $(FEATURE_CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >/dev/null 2>&1 && \ ( echo "found."; echo "FTDISUPPORT := yes" >> .features.tmp ) || \ ( echo "not found."; echo "FTDISUPPORT := no" >> .features.tmp ) @printf "Checking for FT232H support in libftdi... " @echo "$$FTDI_232H_TEST" >> .featuretest.c - @$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >/dev/null 2>&1 && \ + @$(CC) $(CPPFLAGS) $(CFLAGS) $(FEATURE_CFLAGS) $(LDFLAGS) .featuretest.c -o .featuretest$(EXEC_SUFFIX) $(FTDILIBS) $(LIBS) >/dev/null 2>&1 && \ ( echo "found."; echo "FT232H := yes" >> .features.tmp ) || \ ( echo "not found."; echo "FT232H := no" >> .features.tmp ) endif
On Sat, 30 Mar 2013 20:31:34 +0200 Kyösti Mälkki kyosti.malkki@gmail.com wrote:
Update to libftdi-1.0 is advertised as a drop-in replacement for libftdi, running on top of libusb-1.0. This also removes indirect dependency to libusb-0.1.
NOTE: pre-compiled libftdi-1.0 packages may not be available yet NOTE: package named libftdi1 may install libftdi-0.19 (debian)
Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com
An alternative version of this went in with r1904 that should work with both libraries.
There is minor speedup for using this.
Signed-off-by: Kyösti Mälkki kyosti.malkki@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@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@mafipulation.org + * Copyright (C) 2013 Kyösti Mälkki kyosti.malkki@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,