Browse Source

Merge branch 'cg_merges_20121203' into bfgminer

Luke Dashjr 13 years ago
parent
commit
5286e06249
21 changed files with 1777 additions and 248 deletions
  1. 13 0
      API-README
  2. 28 1
      FPGA-README
  3. 3 3
      Makefile.am
  4. 17 0
      NEWS
  5. 1 1
      README
  6. 75 19
      api.c
  7. 9 10
      configure.ac
  8. 32 10
      driver-modminer.c
  9. 1 1
      driver-opencl.c
  10. 4 1
      driver-ztex.c
  11. 1 1
      dynclock.c
  12. 1 1
      findnonce.c
  13. 6 4
      libztex.c
  14. 157 153
      miner.c
  15. 10 2
      miner.h
  16. 15 12
      scrypt.c
  17. 1192 0
      usbutils.c
  18. 120 0
      usbutils.h
  19. 55 27
      util.c
  20. 3 0
      util.h
  21. 34 2
      windows-build.txt

+ 13 - 0
API-README

@@ -332,6 +332,9 @@ The list of requests - a (*) means it requires privileged access - and replies a
                                                        0 to 9999)
                                                        0 to 9999)
                               coinbase-sig (string)
                               coinbase-sig (string)
 
 
+ substats      USBSTATS       Stats of all LIBUSB mining devices except ztex
+                              e.g. Name=MMQ,ID=0,Stat=SendWork,Count=99,...|
+
 When you enable, disable or restart a GPU or PGA, you will also get Thread messages
 When you enable, disable or restart a GPU or PGA, you will also get Thread messages
 in the BFGMiner status window
 in the BFGMiner status window
 
 
@@ -384,6 +387,16 @@ miner.php - an example web page to access the API
 Feature Changelog for external applications using the API:
 Feature Changelog for external applications using the API:
 
 
 
 
+API V1.21
+
+Added API commands:
+ 'usbstats'
+
+Modified API commands:
+ 'summary' - add 'Best Share'
+
+----------
+
 API V1.20b (BFGMiner v2.9.1)
 API V1.20b (BFGMiner v2.9.1)
 
 
 Support for the X6500 FPGA was added
 Support for the X6500 FPGA was added

+ 28 - 1
FPGA-README

@@ -6,7 +6,34 @@ ModMinerQuad (MMQ)
 ------------------
 ------------------
 
 
 The mining bitstream does not survive a power cycle, so BFGMiner will upload
 The mining bitstream does not survive a power cycle, so BFGMiner will upload
-it, if it needs to, before it starts mining
+it, if it needs to, before it starts mining (approx 3min)
+
+The red LED also flashes while it is uploading the bitstream
+
+-
+
+If the MMQ doesn't respond to cgminer at all, or the red LED isn't flashing
+then you will need to reset the MMQ
+
+The red LED should always be flashing when it is mining or ready to mine
+
+To reset the MMQ, you are best to press the left "RESET" button on the
+backplane, then unplug and replug the USB cable
+
+If your MMQ doesn't have a button on the "RESET" pad, you need to join
+the two left pads of the "RESET" pad with conductive wire to reset it.
+Cutting a small (metal) paper-clip in half works well for this
+
+Then unplug the USB cable, wait for 5 seconds, then plug it back in
+
+After you press reset, the red LED near the USB port should blink continuously
+
+If it still wont work, power off, wait for 5 seconds, then power on the MMQ
+This of course means it will upload the bitstream again when you start cgminer
+
+-
+
+Device 0 is on the power end of the board
 
 
 -
 -
 
 

+ 3 - 3
Makefile.am

@@ -8,7 +8,7 @@ EXTRA_DIST	= example.conf m4/gnulib-cache.m4 linux-usb-bfgminer \
 
 
 SUBDIRS		= lib ccan
 SUBDIRS		= lib ccan
 
 
-INCLUDES	= $(PTHREAD_FLAGS) -fno-strict-aliasing $(USB_CFLAGS)
+INCLUDES	= $(PTHREAD_FLAGS) -fno-strict-aliasing
 
 
 bin_PROGRAMS	= bfgminer
 bin_PROGRAMS	= bfgminer
 
 
@@ -17,9 +17,9 @@ bin_SCRIPTS	= *.cl
 bfgminer_LDFLAGS	= $(PTHREAD_FLAGS)
 bfgminer_LDFLAGS	= $(PTHREAD_FLAGS)
 bfgminer_LDADD	= $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
 bfgminer_LDADD	= $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
 		  @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \
 		  @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \
-		  @UDEV_LIBS@ @USB_LIBS@ \
+		  @UDEV_LIBS@ @LIBUSB_LIBS@ \
 		  @MATH_LIBS@ lib/libgnu.a ccan/libccan.a
 		  @MATH_LIBS@ lib/libgnu.a ccan/libccan.a
-bfgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @LIBCURL_CFLAGS@
+bfgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @LIBUSB_CFLAGS@ @LIBCURL_CFLAGS@
 
 
 bfgminer_CPPFLAGS += $(NCURSES_CPPFLAGS)
 bfgminer_CPPFLAGS += $(NCURSES_CPPFLAGS)
 
 

+ 17 - 0
NEWS

@@ -1,5 +1,22 @@
 BFGMiner Version 2.10.0 - Future
 BFGMiner Version 2.10.0 - Future
 
 
+- Make gen_stratum_work more robust by using a dynamically allocated array for
+the header in case bogus data is sent by the pool to avoid overflowing a static
+array.
+- scrypt_diff now returns a uint64_t
+- Support monitoring and reporting much higher diffs for scrypt mining,
+truncating irrelevant zeroes from displayed hash.
+- Pass ostate values around in scrypt to be able to extract full hashes if
+needed later on.
+- Revert "Handle crash exceptions by trying to restart cgminer unless the
+--no-restart option is used."
+- Count longpoll decodes as queued work since the count otherwise remains
+static.
+- Provide helper function realloc_strcat to extend arbitrary length arrays
+based on string length.
+- Bugfix: Assign header-based rolltime before decoding work, so GBT expires
+overrides it properly
+- Bugfix: FPGA-README: Correct idVendor in example MMQ udev rule
 - fixes target calc for mips openwrt
 - fixes target calc for mips openwrt
 - openwrt needs roundl
 - openwrt needs roundl
 - Get rid of unused last_work in opencl thread data.
 - Get rid of unused last_work in opencl thread data.

+ 1 - 1
README

@@ -141,7 +141,7 @@ Options for both config file and command line:
 --no-gbt            Disable getblocktemplate support
 --no-gbt            Disable getblocktemplate support
 --no-longpoll       Disable X-Long-Polling support
 --no-longpoll       Disable X-Long-Polling support
 --no-pool-disable   Do not automatically disable pools that continually reject shares
 --no-pool-disable   Do not automatically disable pools that continually reject shares
---no-restart        Do not attempt to restart devices that hang or BFGMiner if it crashes
+--no-restart        Do not attempt to restart devices that hang
 --no-stratum        Disable Stratum detection
 --no-stratum        Disable Stratum detection
 --no-submit-stale   Don't submit shares if they are detected as stale
 --no-submit-stale   Don't submit shares if they are detected as stale
 --pass|-p <arg>     Password for bitcoin JSON-RPC server
 --pass|-p <arg>     Password for bitcoin JSON-RPC server

+ 75 - 19
api.c

@@ -131,7 +131,7 @@ static const char SEPARATOR = '|';
 #define SEPSTR "|"
 #define SEPSTR "|"
 static const char GPUSEP = ',';
 static const char GPUSEP = ',';
 
 
-static const char *APIVERSION = "1.20";
+static const char *APIVERSION = "1.21";
 static const char *DEAD = "Dead";
 static const char *DEAD = "Dead";
 static const char *SICK = "Sick";
 static const char *SICK = "Sick";
 static const char *NOSTART = "NoStart";
 static const char *NOSTART = "NoStart";
@@ -231,6 +231,7 @@ static const char *OSINFO =
 #define _MINECOIN	"COIN"
 #define _MINECOIN	"COIN"
 #define _DEBUGSET	"DEBUG"
 #define _DEBUGSET	"DEBUG"
 #define _SETCONFIG	"SETCONFIG"
 #define _SETCONFIG	"SETCONFIG"
+#define _USBSTATS	"USBSTATS"
 
 
 static const char ISJSON = '{';
 static const char ISJSON = '{';
 #define JSON0		"{"
 #define JSON0		"{"
@@ -270,6 +271,7 @@ static const char ISJSON = '{';
 #define JSON_MINECOIN	JSON1 _MINECOIN JSON2
 #define JSON_MINECOIN	JSON1 _MINECOIN JSON2
 #define JSON_DEBUGSET	JSON1 _DEBUGSET JSON2
 #define JSON_DEBUGSET	JSON1 _DEBUGSET JSON2
 #define JSON_SETCONFIG	JSON1 _SETCONFIG JSON2
 #define JSON_SETCONFIG	JSON1 _SETCONFIG JSON2
+#define JSON_USBSTATS	JSON1 _USBSTATS JSON2
 #define JSON_END	JSON4 JSON5
 #define JSON_END	JSON4 JSON5
 
 
 static const char *JSON_COMMAND = "command";
 static const char *JSON_COMMAND = "command";
@@ -374,6 +376,8 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_INVNUM 84
 #define MSG_INVNUM 84
 #define MSG_CONPAR 85
 #define MSG_CONPAR 85
 #define MSG_CONVAL 86
 #define MSG_CONVAL 86
+#define MSG_USBSTA 87
+#define MSG_NOUSTA 88
 
 
 enum code_severity {
 enum code_severity {
 	SEVERITY_ERR,
 	SEVERITY_ERR,
@@ -538,6 +542,8 @@ struct CODES {
  { SEVERITY_ERR,   MSG_INVNUM,	PARAM_BOTH,	"Invalid number (%d) for '%s' range is 0-9999" },
  { SEVERITY_ERR,   MSG_INVNUM,	PARAM_BOTH,	"Invalid number (%d) for '%s' range is 0-9999" },
  { SEVERITY_ERR,   MSG_CONPAR,	PARAM_NONE,	"Missing config parameters 'name,N'" },
  { SEVERITY_ERR,   MSG_CONPAR,	PARAM_NONE,	"Missing config parameters 'name,N'" },
  { SEVERITY_ERR,   MSG_CONVAL,	PARAM_STR,	"Missing config value N for '%s,N'" },
  { SEVERITY_ERR,   MSG_CONVAL,	PARAM_STR,	"Missing config value N for '%s,N'" },
+ { SEVERITY_SUCC,  MSG_USBSTA,	PARAM_NONE,	"USB Statistics" },
+ { SEVERITY_INFO,  MSG_NOUSTA,	PARAM_NONE,	"No USB Statistics" },
  { SEVERITY_FAIL, 0, 0, NULL }
  { SEVERITY_FAIL, 0, 0, NULL }
 };
 };
 
 
@@ -1786,6 +1792,9 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
 		algo = (char *)NULLSTR;
 		algo = (char *)NULLSTR;
 #endif
 #endif
 
 
+	// stop hashmeter() changing some while copying
+	mutex_lock(&hash_lock);
+
 	utility = total_accepted / ( total_secs ? total_secs : 1 ) * 60;
 	utility = total_accepted / ( total_secs ? total_secs : 1 ) * 60;
 	mhs = total_mhashes_done / total_secs;
 	mhs = total_mhashes_done / total_secs;
 	work_utility = total_diff1 / ( total_secs ? total_secs : 1 ) * 60;
 	work_utility = total_diff1 / ( total_secs ? total_secs : 1 ) * 60;
@@ -1795,29 +1804,32 @@ static void summary(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, boo
 		: "%s" _SUMMARY ",",
 		: "%s" _SUMMARY ",",
 		message(MSG_SUMM, 0, NULL, isjson));
 		message(MSG_SUMM, 0, NULL, isjson));
 
 
-	root = api_add_elapsed(root, "Elapsed", &(total_secs), false);
+	root = api_add_elapsed(root, "Elapsed", &(total_secs), true);
 #ifdef WANT_CPUMINE
 #ifdef WANT_CPUMINE
 	if (opt_n_threads)
 	if (opt_n_threads)
 	root = api_add_string(root, "Algorithm", algo, false);
 	root = api_add_string(root, "Algorithm", algo, false);
 #endif
 #endif
 	root = api_add_mhs(root, "MHS av", &(mhs), false);
 	root = api_add_mhs(root, "MHS av", &(mhs), false);
-	root = api_add_uint(root, "Found Blocks", &(found_blocks), false);
-	root = api_add_int(root, "Getworks", &(total_getworks), false);
-	root = api_add_int(root, "Accepted", &(total_accepted), false);
-	root = api_add_int(root, "Rejected", &(total_rejected), false);
-	root = api_add_int(root, "Hardware Errors", &(hw_errors), false);
+	root = api_add_uint(root, "Found Blocks", &(found_blocks), true);
+	root = api_add_int(root, "Getworks", &(total_getworks), true);
+	root = api_add_int(root, "Accepted", &(total_accepted), true);
+	root = api_add_int(root, "Rejected", &(total_rejected), true);
+	root = api_add_int(root, "Hardware Errors", &(hw_errors), true);
 	root = api_add_utility(root, "Utility", &(utility), false);
 	root = api_add_utility(root, "Utility", &(utility), false);
-	root = api_add_int(root, "Discarded", &(total_discarded), false);
-	root = api_add_int(root, "Stale", &(total_stale), false);
-	root = api_add_uint(root, "Get Failures", &(total_go), false);
-	root = api_add_uint(root, "Local Work", &(local_work), false);
-	root = api_add_uint(root, "Remote Failures", &(total_ro), false);
-	root = api_add_uint(root, "Network Blocks", &(new_blocks), false);
-	root = api_add_mhtotal(root, "Total MH", &(total_mhashes_done), false);
+	root = api_add_int(root, "Discarded", &(total_discarded), true);
+	root = api_add_int(root, "Stale", &(total_stale), true);
+	root = api_add_uint(root, "Get Failures", &(total_go), true);
+	root = api_add_uint(root, "Local Work", &(local_work), true);
+	root = api_add_uint(root, "Remote Failures", &(total_ro), true);
+	root = api_add_uint(root, "Network Blocks", &(new_blocks), true);
+	root = api_add_mhtotal(root, "Total MH", &(total_mhashes_done), true);
 	root = api_add_utility(root, "Work Utility", &(work_utility), false);
 	root = api_add_utility(root, "Work Utility", &(work_utility), false);
-	root = api_add_diff(root, "Difficulty Accepted", &(total_diff_accepted), false);
-	root = api_add_diff(root, "Difficulty Rejected", &(total_diff_rejected), false);
-	root = api_add_diff(root, "Difficulty Stale", &(total_diff_stale), false);
+	root = api_add_diff(root, "Difficulty Accepted", &(total_diff_accepted), true);
+	root = api_add_diff(root, "Difficulty Rejected", &(total_diff_rejected), true);
+	root = api_add_diff(root, "Difficulty Stale", &(total_diff_stale), true);
+	root = api_add_uint64(root, "Best Share", &(best_diff), true);
+
+	mutex_unlock(&hash_lock);
 
 
 	root = print_data(root, buf, isjson);
 	root = print_data(root, buf, isjson);
 	if (isjson)
 	if (isjson)
@@ -2849,6 +2861,49 @@ static void setconfig(__maybe_unused SOCKETTYPE c, char *param, bool isjson, __m
 	strcpy(io_buffer, message(MSG_SETCONFIG, value, param, isjson));
 	strcpy(io_buffer, message(MSG_SETCONFIG, value, param, isjson));
 }
 }
 
 
+static void usbstats(__maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
+{
+	struct api_data *root = NULL;
+
+#ifdef USE_USBUTILS
+	char buf[TMPBUFSIZ];
+	int count = 0;
+
+	root = api_usb_stats(&count);
+#endif
+
+	if (!root) {
+		strcpy(io_buffer, message(MSG_NOUSTA, 0, NULL, isjson));
+		return;
+	}
+
+#ifdef USE_USBUTILS
+
+	strcpy(io_buffer, message(MSG_USBSTA, 0, NULL, isjson));
+
+	if (isjson) {
+		strcat(io_buffer, COMMA);
+		strcat(io_buffer, JSON_USBSTATS);
+	}
+
+	root = print_data(root, buf, isjson);
+	strcat(io_buffer, buf);
+
+	while (42) {
+		root = api_usb_stats(&count);
+		if (!root)
+			break;
+
+		strcat(io_buffer, COMMA);
+		root = print_data(root, buf, isjson);
+		strcat(io_buffer, buf);
+	}
+
+	if (isjson)
+		strcat(io_buffer, JSON_CLOSE);
+#endif
+}
+
 static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
 static void checkcommand(__maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
 
 
 struct CMDS {
 struct CMDS {
@@ -2905,6 +2960,7 @@ struct CMDS {
 	{ "coin",		minecoin,	false },
 	{ "coin",		minecoin,	false },
 	{ "debug",		debugstate,	true },
 	{ "debug",		debugstate,	true },
 	{ "setconfig",		setconfig,	true },
 	{ "setconfig",		setconfig,	true },
+	{ "usbstats",		usbstats,	false },
 	{ NULL,			NULL,		false }
 	{ NULL,			NULL,		false }
 };
 };
 
 
@@ -3252,7 +3308,7 @@ popipo:
 
 
 static void *quit_thread(__maybe_unused void *userdata)
 static void *quit_thread(__maybe_unused void *userdata)
 {
 {
-	rename_thr("bfg-rpc-quit");
+	RenameThread("rpc_quit");
 
 
 	// allow thread creator to finish whatever it's doing
 	// allow thread creator to finish whatever it's doing
 	mutex_lock(&quit_restart_lock);
 	mutex_lock(&quit_restart_lock);
@@ -3268,7 +3324,7 @@ static void *quit_thread(__maybe_unused void *userdata)
 
 
 static void *restart_thread(__maybe_unused void *userdata)
 static void *restart_thread(__maybe_unused void *userdata)
 {
 {
-	rename_thr("bfg-rpc-restart");
+	RenameThread("rpc_restart");
 
 
 	// allow thread creator to finish whatever it's doing
 	// allow thread creator to finish whatever it's doing
 	mutex_lock(&quit_restart_lock);
 	mutex_lock(&quit_restart_lock);

+ 9 - 10
configure.ac

@@ -65,8 +65,6 @@ AC_FUNC_ALLOCA
 have_cygwin=false
 have_cygwin=false
 have_win32=false
 have_win32=false
 PTHREAD_FLAGS="-lpthread"
 PTHREAD_FLAGS="-lpthread"
-USB_LIBS=""
-USB_CFLAGS=""
 DLOPEN_FLAGS="-ldl"
 DLOPEN_FLAGS="-ldl"
 WS2_LIBS=""
 WS2_LIBS=""
 MATH_LIBS="-lm"
 MATH_LIBS="-lm"
@@ -185,7 +183,7 @@ PKG_PROG_PKG_CONFIG()
 
 
 libusb=no
 libusb=no
 libusb_include_path=""
 libusb_include_path=""
-PKG_CHECK_MODULES([USB], [libusb-1.0],[
+PKG_CHECK_MODULES([LIBUSB], [libusb-1.0],[
 	libusb=yes
 	libusb=yes
 ],[
 ],[
 	for usb_lib in usb-1.0 usb; do
 	for usb_lib in usb-1.0 usb; do
@@ -211,9 +209,9 @@ PKG_CHECK_MODULES([USB], [libusb-1.0],[
 	fi
 	fi
 ])
 ])
 if test "x$libusb" = xyes; then
 if test "x$libusb" = xyes; then
-	AC_DEFINE([HAVE_LIBUSB], [1], [Defined to 1 if libusb is wanted])
+	AC_DEFINE([HAVE_LIBUSB], [1], [Define if you have libusb-1.0])
 	save_CFLAGS="$CFLAGS"
 	save_CFLAGS="$CFLAGS"
-	CFLAGS="$USB_CFLAGS $CFLAGS"
+	CFLAGS="$LIBUSB_CFLAGS $CFLAGS"
 	AC_CHECK_DECLS([libusb_error_name],[],[],[#include <libusb.h>])
 	AC_CHECK_DECLS([libusb_error_name],[],[],[#include <libusb.h>])
 	CFLAGS="$save_CFLAGS"
 	CFLAGS="$save_CFLAGS"
 fi
 fi
@@ -398,6 +396,9 @@ if test "x$bitforce$modminer" != xnono; then
 fi
 fi
 AM_CONDITIONAL([HAVE_LIBUDEV], [test x$libudev != xno])
 AM_CONDITIONAL([HAVE_LIBUDEV], [test x$libudev != xno])
 
 
+AC_SUBST(LIBUSB_LIBS)
+AC_SUBST(LIBUSB_CFLAGS)
+
 PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.18.2], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.18.2])])
 PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.18.2], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.18.2])])
 AC_SUBST(LIBCURL_LIBS)
 AC_SUBST(LIBCURL_LIBS)
 
 
@@ -456,8 +457,6 @@ AC_SUBST(PDCURSES_LIBS)
 AC_SUBST(WS2_LIBS)
 AC_SUBST(WS2_LIBS)
 AC_SUBST(MATH_LIBS)
 AC_SUBST(MATH_LIBS)
 AC_SUBST(UDEV_LIBS)
 AC_SUBST(UDEV_LIBS)
-AC_SUBST(USB_LIBS)
-AC_SUBST(USB_CFLAGS)
 
 
 AC_CONFIG_FILES([
 AC_CONFIG_FILES([
 	Makefile
 	Makefile
@@ -552,9 +551,9 @@ fi
 echo
 echo
 echo "Compilation............: make (or gmake)"
 echo "Compilation............: make (or gmake)"
 echo "  CPPFLAGS.............: $CPPFLAGS $NCURSES_CPPFLAGS"
 echo "  CPPFLAGS.............: $CPPFLAGS $NCURSES_CPPFLAGS"
-echo "  CFLAGS...............: $CFLAGS"
-echo "  LDFLAGS..............: $LDFLAGS $PTHREAD_FLAGS $USB_CFLAGS"
-echo "  LDADD................: $DLOPEN_FLAGS $LIBCURL_LIBS $JANSSON_LIBS $PTHREAD_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $UDEV_LIBS $USB_LIBS"
+echo "  CFLAGS...............: $CFLAGS $LIBUSB_CFLAGS"
+echo "  LDFLAGS..............: $LDFLAGS $PTHREAD_FLAGS"
+echo "  LDADD................: $DLOPEN_FLAGS $LIBCURL_LIBS $JANSSON_LIBS $PTHREAD_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $UDEV_LIBS $LIBUSB_LIBS"
 echo
 echo
 echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')"
 echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')"
 echo "  prefix...............: $prefix"
 echo "  prefix...............: $prefix"

+ 32 - 10
driver-modminer.c

@@ -16,15 +16,34 @@
 #include "dynclock.h"
 #include "dynclock.h"
 #include "logging.h"
 #include "logging.h"
 #include "miner.h"
 #include "miner.h"
+#include "usbutils.h"
 #include "fpgautils.h"
 #include "fpgautils.h"
 #include "util.h"
 #include "util.h"
 
 
 #define BITSTREAM_FILENAME "fpgaminer_top_fixed7_197MHz.bit"
 #define BITSTREAM_FILENAME "fpgaminer_top_fixed7_197MHz.bit"
 #define BISTREAM_USER_ID "\2\4$B"
 #define BISTREAM_USER_ID "\2\4$B"
+
 #define MODMINER_MINIMUM_CLOCK    2
 #define MODMINER_MINIMUM_CLOCK    2
 #define MODMINER_DEFAULT_CLOCK  200
 #define MODMINER_DEFAULT_CLOCK  200
 #define MODMINER_MAXIMUM_CLOCK  210
 #define MODMINER_MAXIMUM_CLOCK  210
 
 
+// Commands
+#define MODMINER_PING "\x00"
+#define MODMINER_GET_VERSION "\x01"
+#define MODMINER_FPGA_COUNT "\x02"
+// Commands + require FPGAid
+#define MODMINER_GET_IDCODE '\x03'
+#define MODMINER_GET_USERCODE '\x04'
+#define MODMINER_PROGRAM '\x05'
+#define MODMINER_SET_CLOCK '\x06'
+#define MODMINER_READ_CLOCK '\x07'
+#define MODMINER_SEND_WORK '\x08'
+#define MODMINER_CHECK_WORK '\x09'
+// One byte temperature reply
+#define MODMINER_TEMP1 '\x0a'
+
+#define FPGAID_ALL 4
+
 struct device_api modminer_api;
 struct device_api modminer_api;
 
 
 struct modminer_fpga_state {
 struct modminer_fpga_state {
@@ -68,6 +87,9 @@ _bailout(int fd, struct cgpu_info*modminer, int prio, const char *fmt, ...)
 }
 }
 #define bailout(...)  return _bailout(fd, NULL, __VA_ARGS__);
 #define bailout(...)  return _bailout(fd, NULL, __VA_ARGS__);
 
 
+// 45 noops sent when detecting, in case the device was left in "start job" reading
+static const char NOOP[] = MODMINER_PING "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
+
 static bool
 static bool
 modminer_detect_one(const char *devpath)
 modminer_detect_one(const char *devpath)
 {
 {
@@ -80,11 +102,11 @@ modminer_detect_one(const char *devpath)
 
 
 	// Sending a "ping" first, to workaround bug in new firmware betas (see issue #62)
 	// Sending a "ping" first, to workaround bug in new firmware betas (see issue #62)
 	// Sending 45 noops, just in case the device was left in "start job" reading
 	// Sending 45 noops, just in case the device was left in "start job" reading
-	(void)(write(fd, "\0\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 46) ?:0);
+	(void)(write(fd, NOOP, sizeof(NOOP)) ?:0);
 	while (serial_read(fd, buf, sizeof(buf)) > 0)
 	while (serial_read(fd, buf, sizeof(buf)) > 0)
 		;
 		;
 
 
-	if (1 != write(fd, "\x01", 1))  // Get version
+	if (1 != write(fd, MODMINER_GET_VERSION, 1))
 		bailout(LOG_DEBUG, "ModMiner detect: write failed on %s (get version)", devpath);
 		bailout(LOG_DEBUG, "ModMiner detect: write failed on %s (get version)", devpath);
 	len = serial_read(fd, buf, sizeof(buf)-1);
 	len = serial_read(fd, buf, sizeof(buf)-1);
 	if (len < 1)
 	if (len < 1)
@@ -93,7 +115,7 @@ modminer_detect_one(const char *devpath)
 	char*devname = strdup(buf);
 	char*devname = strdup(buf);
 	applog(LOG_DEBUG, "ModMiner identified as: %s", devname);
 	applog(LOG_DEBUG, "ModMiner identified as: %s", devname);
 
 
-	if (1 != write(fd, "\x02", 1))  // Get FPGA count
+	if (1 != write(fd, MODMINER_FPGA_COUNT, 1))
 		bailout(LOG_DEBUG, "ModMiner detect: write failed on %s (get FPGA count)", devpath);
 		bailout(LOG_DEBUG, "ModMiner detect: write failed on %s (get FPGA count)", devpath);
 	len = read(fd, buf, 1);
 	len = read(fd, buf, 1);
 	if (len < 1)
 	if (len < 1)
@@ -194,7 +216,7 @@ modminer_fpga_upload_bitstream(struct cgpu_info*modminer)
 	fd_set fds;
 	fd_set fds;
 	char buf[0x100];
 	char buf[0x100];
 	unsigned long len, flen;
 	unsigned long len, flen;
-	char fpgaid = 4;  // "all FPGAs"
+	char fpgaid = FPGAID_ALL;
 	FILE *f = open_xilinx_bitstream(modminer, BITSTREAM_FILENAME, &len);
 	FILE *f = open_xilinx_bitstream(modminer, BITSTREAM_FILENAME, &len);
 	if (!f)
 	if (!f)
 		return false;
 		return false;
@@ -203,7 +225,7 @@ modminer_fpga_upload_bitstream(struct cgpu_info*modminer)
 	int fd = modminer->device_fd;
 	int fd = modminer->device_fd;
 
 
 	applog(LOG_WARNING, "%s %u: Programming %s... DO NOT EXIT UNTIL COMPLETE", modminer->api->name, modminer->device_id, modminer->device_path);
 	applog(LOG_WARNING, "%s %u: Programming %s... DO NOT EXIT UNTIL COMPLETE", modminer->api->name, modminer->device_id, modminer->device_path);
-	buf[0] = '\x05';  // Program Bitstream
+	buf[0] = MODMINER_PROGRAM;
 	buf[1] = fpgaid;
 	buf[1] = fpgaid;
 	buf[2] = (len >>  0) & 0xff;
 	buf[2] = (len >>  0) & 0xff;
 	buf[3] = (len >>  8) & 0xff;
 	buf[3] = (len >>  8) & 0xff;
@@ -266,7 +288,7 @@ modminer_fpga_prepare(struct thr_info *thr)
 	struct modminer_fpga_state *state;
 	struct modminer_fpga_state *state;
 	state = thr->cgpu_data = calloc(1, sizeof(struct modminer_fpga_state));
 	state = thr->cgpu_data = calloc(1, sizeof(struct modminer_fpga_state));
 	dclk_prepare(&state->dclk);
 	dclk_prepare(&state->dclk);
-	state->next_work_cmd[0] = '\x08';  // Send Job
+	state->next_work_cmd[0] = MODMINER_SEND_WORK;
 	state->next_work_cmd[1] = thr->device_thread;  // FPGA id
 	state->next_work_cmd[1] = thr->device_thread;  // FPGA id
 
 
 	return true;
 	return true;
@@ -284,7 +306,7 @@ modminer_change_clock(struct thr_info*thr, bool needlock, signed char delta)
 
 
 	clk = (state->dclk.freqM * 2) + delta;
 	clk = (state->dclk.freqM * 2) + delta;
 
 
-	cmd[0] = '\x06';  // set frequency
+	cmd[0] = MODMINER_SET_CLOCK;
 	cmd[1] = fpgaid;
 	cmd[1] = fpgaid;
 	cmd[2] = clk;
 	cmd[2] = clk;
 	cmd[3] = cmd[4] = cmd[5] = '\0';
 	cmd[3] = cmd[4] = cmd[5] = '\0';
@@ -335,7 +357,7 @@ modminer_reduce_clock(struct thr_info*thr, bool needlock)
 static bool _modminer_get_nonce(struct cgpu_info*modminer, char fpgaid, uint32_t*nonce)
 static bool _modminer_get_nonce(struct cgpu_info*modminer, char fpgaid, uint32_t*nonce)
 {
 {
 	int fd = modminer->device_fd;
 	int fd = modminer->device_fd;
-	char cmd[2] = {'\x09', fpgaid};
+	char cmd[2] = {MODMINER_CHECK_WORK, fpgaid};
 	
 	
 	if (write(fd, cmd, 2) != 2) {
 	if (write(fd, cmd, 2) != 2) {
 		applog(LOG_ERR, "%s %u: Error writing (get nonce %u)", modminer->api->name, modminer->device_id, fpgaid);
 		applog(LOG_ERR, "%s %u: Error writing (get nonce %u)", modminer->api->name, modminer->device_id, fpgaid);
@@ -368,7 +390,7 @@ modminer_fpga_init(struct thr_info *thr)
 		return false;
 		return false;
 	}
 	}
 
 
-	cmd[0] = '\x04';  // Read USER code (bitstream id)
+	cmd[0] = MODMINER_GET_USERCODE;
 	cmd[1] = fpgaid;
 	cmd[1] = fpgaid;
 	if (write(fd, cmd, 2) != 2)
 	if (write(fd, cmd, 2) != 2)
 		bailout2(LOG_ERR, "%s %u.%u: Error writing (read USER code)", modminer->api->name, modminer->device_id, fpgaid);
 		bailout2(LOG_ERR, "%s %u.%u: Error writing (read USER code)", modminer->api->name, modminer->device_id, fpgaid);
@@ -473,7 +495,7 @@ static void modminer_get_temperature(struct cgpu_info *modminer, struct thr_info
 
 
 	int fd = modminer->device_fd;
 	int fd = modminer->device_fd;
 	int fpgaid = thr->device_thread;
 	int fpgaid = thr->device_thread;
-	char cmd[2] = {'\x0a', fpgaid};
+	char cmd[2] = {MODMINER_TEMP1, fpgaid};
 	char temperature;
 	char temperature;
 
 
 	if (2 == write(fd, cmd, 2) && read(fd, &temperature, 1) == 1)
 	if (2 == write(fd, cmd, 2) && read(fd, &temperature, 1) == 1)

+ 1 - 1
driver-opencl.c

@@ -1329,7 +1329,7 @@ void *reinit_gpu(void *userdata)
 	int gpu;
 	int gpu;
 
 
 	pthread_detach(pthread_self());
 	pthread_detach(pthread_self());
-	rename_thr("bfg-reinit_gpu");
+	RenameThread("reinit_gpu");
 
 
 select_cgpu:
 select_cgpu:
 	cgpu = tq_pop(mythr->q, NULL);
 	cgpu = tq_pop(mythr->q, NULL);

+ 4 - 1
driver-ztex.c

@@ -365,8 +365,11 @@ static bool ztex_prepare(struct thr_info *thr)
 	get_datestamp(cgpu->init, &now);
 	get_datestamp(cgpu->init, &now);
 	
 	
 	ztex_selectFpga(ztex);
 	ztex_selectFpga(ztex);
-	if (libztex_configureFpga(ztex) != 0)
+	if (libztex_configureFpga(ztex) != 0) {
+		libztex_resetFpga(ztex);
+		ztex_releaseFpga(ztex);
 		return false;
 		return false;
+	}
 	ztex_releaseFpga(ztex);
 	ztex_releaseFpga(ztex);
 	ztex->dclk.freqM = ztex->dclk.freqMaxM+1;;
 	ztex->dclk.freqM = ztex->dclk.freqMaxM+1;;
 	//ztex_updateFreq(thr);
 	//ztex_updateFreq(thr);

+ 1 - 1
dynclock.c

@@ -20,7 +20,7 @@ void dclk_prepare(struct dclk_data *data)
 
 
 void dclk_msg_freqchange(const char *repr, int oldFreq, int newFreq, const char *tail)
 void dclk_msg_freqchange(const char *repr, int oldFreq, int newFreq, const char *tail)
 {
 {
-	applog(LOG_NOTICE, "%s: Frequency %s from %u to %u Mhz%s",
+	applog(LOG_NOTICE, "%s: Frequency %s from %u to %u MHz%s",
 	       repr,
 	       repr,
 	       (oldFreq > newFreq ? "dropped" : "raised "),
 	       (oldFreq > newFreq ? "dropped" : "raised "),
 	       oldFreq, newFreq,
 	       oldFreq, newFreq,

+ 1 - 1
findnonce.c

@@ -147,7 +147,7 @@ static void *postcalc_hash(void *userdata)
 	unsigned int entry = 0;
 	unsigned int entry = 0;
 
 
 	pthread_detach(pthread_self());
 	pthread_detach(pthread_self());
-	rename_thr("bfg-postcalchsh");
+	RenameThread("postcalchsh");
 
 
 	/* To prevent corrupt values in FOUND from trying to read beyond the
 	/* To prevent corrupt values in FOUND from trying to read beyond the
 	 * end of the res[] array */
 	 * end of the res[] array */

+ 6 - 4
libztex.c

@@ -307,11 +307,13 @@ static int libztex_configureFpgaLS(struct libztex_device *ztex, const char* firm
 
 
 		fclose(fp);
 		fclose(fp);
 	}
 	}
+
 	libztex_getFpgaState(ztex, &state);
 	libztex_getFpgaState(ztex, &state);
 	if (!state.fpgaConfigured) {
 	if (!state.fpgaConfigured) {
-		applog(LOG_ERR, "%s: FPGA configuration failed: DONE pin does not go high", ztex->repr);
-		return 3;
+		applog(LOG_ERR, "%s: LS FPGA configuration failed: DONE pin does not go high", ztex->repr);
+		return -3;
 	}
 	}
+
 	nmsleep(200);
 	nmsleep(200);
 	applog(LOG_INFO, "%s: FPGA configuration done", ztex->repr);
 	applog(LOG_INFO, "%s: FPGA configuration done", ztex->repr);
 	return 0;
 	return 0;
@@ -384,7 +386,7 @@ int libztex_setFreq(struct libztex_device *ztex, uint16_t freq) {
 	}
 	}
 	ztex->dclk.freqM = freq;
 	ztex->dclk.freqM = freq;
 	if (oldfreq > ztex->dclk.freqMaxM)
 	if (oldfreq > ztex->dclk.freqMaxM)
-		applog(LOG_WARNING, "%s: Frequency set to %u Mhz (range: %u-%u)",
+		applog(LOG_WARNING, "%s: Frequency set to %u MHz (range: %u-%u)",
 		       ztex->repr,
 		       ztex->repr,
 		       (unsigned)(ztex->freqM1 * (ztex->dclk.freqM + 1)),
 		       (unsigned)(ztex->freqM1 * (ztex->dclk.freqM + 1)),
 		       (unsigned)ztex->freqM1,
 		       (unsigned)ztex->freqM1,
@@ -474,7 +476,7 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt
 	}
 	}
 
 
 	/* num chars = (all bytes except bLength and bDescriptorType) / 2 */
 	/* num chars = (all bytes except bLength and bDescriptorType) / 2 */
-	for (i = 0; i <= (cnt - 2) / 2 && i < sizeof(newdev->snString)-1; i++)
+	for (i = 0; i <= (cnt - 2) / 2 && i < (int)sizeof(newdev->snString)-1; i++)
 		newdev->snString[i] = buf[2 + i*2];
 		newdev->snString[i] = buf[2 + i*2];
 
 
 	newdev->snString[i] = 0;
 	newdev->snString[i] = 0;

+ 157 - 153
miner.c

@@ -183,6 +183,9 @@ bool opt_disable_pool = true;
 char *opt_icarus_options = NULL;
 char *opt_icarus_options = NULL;
 char *opt_icarus_timing = NULL;
 char *opt_icarus_timing = NULL;
 bool opt_worktime;
 bool opt_worktime;
+#ifdef HAVE_LIBUSB
+int opt_usbdump = -1;
+#endif
 
 
 char *opt_kernel_path;
 char *opt_kernel_path;
 char *cgminer_path;
 char *cgminer_path;
@@ -204,7 +207,11 @@ int gpur_thr_id;
 static int api_thr_id;
 static int api_thr_id;
 static int total_threads;
 static int total_threads;
 
 
-static pthread_mutex_t hash_lock;
+#ifdef HAVE_LIBUSB
+pthread_mutex_t cgusb_lock;
+#endif
+
+pthread_mutex_t hash_lock;
 static pthread_mutex_t qd_lock;
 static pthread_mutex_t qd_lock;
 static pthread_mutex_t *stgd_lock;
 static pthread_mutex_t *stgd_lock;
 pthread_mutex_t console_lock;
 pthread_mutex_t console_lock;
@@ -263,7 +270,7 @@ static char datestamp[40];
 static char blocktime[32];
 static char blocktime[32];
 struct timeval block_timeval;
 struct timeval block_timeval;
 static char best_share[8] = "0";
 static char best_share[8] = "0";
-static uint64_t best_diff = 0;
+uint64_t best_diff = 0;
 
 
 struct block {
 struct block {
 	char hash[40];
 	char hash[40];
@@ -305,7 +312,7 @@ static int include_count;
 
 
 bool ping = true;
 bool ping = true;
 
 
-struct sigaction termhandler, inthandler, segvhandler, bushandler, illhandler;
+struct sigaction termhandler, inthandler;
 
 
 struct thread_q *getq;
 struct thread_q *getq;
 
 
@@ -1229,7 +1236,7 @@ static struct opt_table opt_config_table[] = {
 			"Do not automatically disable pools that continually reject shares"),
 			"Do not automatically disable pools that continually reject shares"),
 	OPT_WITHOUT_ARG("--no-restart",
 	OPT_WITHOUT_ARG("--no-restart",
 			opt_set_invbool, &opt_restart,
 			opt_set_invbool, &opt_restart,
-			"Do not attempt to restart devices that hang or BFGMiner if it crashes"
+			"Do not attempt to restart devices that hang"
 	),
 	),
 	OPT_WITHOUT_ARG("--no-stratum",
 	OPT_WITHOUT_ARG("--no-stratum",
 			opt_set_invbool, &want_stratum,
 			opt_set_invbool, &want_stratum,
@@ -1357,6 +1364,11 @@ static struct opt_table opt_config_table[] = {
 	OPT_WITH_ARG("--user|-u",
 	OPT_WITH_ARG("--user|-u",
 		     set_user, NULL, NULL,
 		     set_user, NULL, NULL,
 		     "Username for bitcoin JSON-RPC server"),
 		     "Username for bitcoin JSON-RPC server"),
+#ifdef HAVE_LIBUSB
+	OPT_WITH_ARG("--usb-dump",
+		     set_int_0_to_10, opt_show_intval, &opt_usbdump,
+		     opt_hidden),
+#endif
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
 	OPT_WITH_ARG("--vectors|-v",
 	OPT_WITH_ARG("--vectors|-v",
 		     set_vector, NULL, NULL,
 		     set_vector, NULL, NULL,
@@ -1631,6 +1643,51 @@ static void calc_midstate(struct work *work)
 	swap32tole(work->midstate, work->midstate, 8);
 	swap32tole(work->midstate, work->midstate, 8);
 }
 }
 
 
+static struct work *make_work(void)
+{
+	struct work *work = calloc(1, sizeof(struct work));
+
+	if (unlikely(!work))
+		quit(1, "Failed to calloc work in make_work");
+	mutex_lock(&control_lock);
+	work->id = total_work++;
+	mutex_unlock(&control_lock);
+	return work;
+}
+
+/* This is the central place all work that is about to be retired should be
+ * cleaned to remove any dynamically allocated arrays within the struct */
+void clean_work(struct work *work)
+{
+	free(work->job_id);
+	free(work->nonce2);
+	free(work->ntime);
+	work->job_id = NULL;
+	work->nonce2 = NULL;
+	work->ntime = NULL;
+
+	if (work->tmpl) {
+		struct pool *pool = work->pool;
+		mutex_lock(&pool->pool_lock);
+		bool free_tmpl = !--*work->tmpl_refcount;
+		mutex_unlock(&pool->pool_lock);
+		if (free_tmpl) {
+			blktmpl_free(work->tmpl);
+			free(work->tmpl_refcount);
+		}
+		work->tmpl = NULL;
+		work->tmpl_refcount = NULL;
+	}
+}
+
+/* All dynamically allocated work structs should be freed here to not leak any
+ * ram from arrays allocated within the work struct */
+void free_work(struct work *work)
+{
+	clean_work(work);
+	free(work);
+}
+
 static bool work_decode(struct pool *pool, struct work *work, json_t *val)
 static bool work_decode(struct pool *pool, struct work *work, json_t *val)
 {
 {
 	json_t *res_val = json_object_get(val, "result");
 	json_t *res_val = json_object_get(val, "result");
@@ -2524,14 +2581,14 @@ static uint64_t share_diff(const struct work *work)
 	return ret;
 	return ret;
 }
 }
 
 
-static uint32_t scrypt_diff(const struct work *work)
+static uint64_t scrypt_diff(const struct work *work)
 {
 {
-	const uint32_t scrypt_diffone = 0x0000fffful;
-	uint32_t d32 = work->outputhash, ret;
+	const uint64_t scrypt_diffone = 0x0000ffff00000000ul;
+	uint64_t d64 = work->outputhash, ret;
 
 
-	if (unlikely(!d32))
-		d32 = 1;
-	ret = scrypt_diffone / d32;
+	if (unlikely(!d64))
+		d64 = 1;
+	ret = scrypt_diffone / d64;
 	if (ret > best_diff) {
 	if (ret > best_diff) {
 		best_diff = ret;
 		best_diff = ret;
 		suffix_string(best_diff, best_share, 0);
 		suffix_string(best_diff, best_share, 0);
@@ -2562,30 +2619,32 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
 		json_decref(req);
 		json_decref(req);
 		sd = bin2hex(data, 80);
 		sd = bin2hex(data, 80);
 	} else {
 	} else {
-		s  = malloc(345);
 		sd = s;
 		sd = s;
 
 
 	/* build hex string */
 	/* build hex string */
 	hexstr = bin2hex(work->data, sizeof(work->data));
 	hexstr = bin2hex(work->data, sizeof(work->data));
 
 
 	/* build JSON-RPC request */
 	/* build JSON-RPC request */
-		sprintf(s, "{\"method\": \"getwork\", \"params\": [ \"%s\" ], \"id\":1}", hexstr);
+		s = strdup("{\"method\": \"getwork\", \"params\": [ \"");
+		s = realloc_strcat(s, hexstr);
+		s = realloc_strcat(s, "\" ], \"id\":1}");
 
 
 	}
 	}
 
 
 	applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, sd);
 	applog(LOG_DEBUG, "DBG: sending %s submit RPC call: %s", pool->rpc_url, sd);
 	if (!work->tmpl)
 	if (!work->tmpl)
-	strcat(s, "\n");
+	s = realloc_strcat(s, "\n");
 
 
 	gettimeofday(&tv_submit, NULL);
 	gettimeofday(&tv_submit, NULL);
 	/* issue JSON-RPC request */
 	/* issue JSON-RPC request */
 	val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, s, false, false, &rolltime, pool, true);
 	val = json_rpc_call(curl, pool->rpc_url, pool->rpc_userpass, s, false, false, &rolltime, pool, true);
 
 
-	free(s);
 	if (sd != s)
 	if (sd != s)
 	free(sd);
 	free(sd);
 
 
 	gettimeofday(&tv_submit_reply, NULL);
 	gettimeofday(&tv_submit_reply, NULL);
+	free(s);
+
 	if (unlikely(!val)) {
 	if (unlikely(!val)) {
 		applog(LOG_INFO, "submit_upstream_work json_rpc_call failed");
 		applog(LOG_INFO, "submit_upstream_work json_rpc_call failed");
 		if (!pool_tset(pool, &pool->submit_fail)) {
 		if (!pool_tset(pool, &pool->submit_fail)) {
@@ -2608,12 +2667,14 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
 		hash32 = (uint32_t *)(work->hash);
 		hash32 = (uint32_t *)(work->hash);
 		if (opt_scrypt) {
 		if (opt_scrypt) {
 			uint32_t sharediff;
 			uint32_t sharediff;
+			uint64_t outhash;
 
 
 			scrypt_outputhash(work);
 			scrypt_outputhash(work);
 			sharediff = scrypt_diff(work);
 			sharediff = scrypt_diff(work);
 			suffix_string(sharediff, diffdisp, 0);
 			suffix_string(sharediff, diffdisp, 0);
 
 
-			sprintf(hashshow, "%08lx Diff %s/%d", (unsigned long)work->outputhash, diffdisp, intdiff);
+			outhash = work->outputhash >> 16;
+			sprintf(hashshow, "%08lx Diff %s/%d", (unsigned long)outhash, diffdisp, intdiff);
 		} else {
 		} else {
 			uint64_t sharediff = share_diff(work);
 			uint64_t sharediff = share_diff(work);
 
 
@@ -2941,51 +3002,6 @@ tryagain:
 	return rc;
 	return rc;
 }
 }
 
 
-static struct work *make_work(void)
-{
-	struct work *work = calloc(1, sizeof(struct work));
-
-	if (unlikely(!work))
-		quit(1, "Failed to calloc work in make_work");
-	mutex_lock(&control_lock);
-	work->id = total_work++;
-	mutex_unlock(&control_lock);
-	return work;
-}
-
-/* This is the central place all work that is about to be retired should be
- * cleaned to remove any dynamically allocated arrays within the struct */
-void clean_work(struct work *work)
-{
-	free(work->job_id);
-	free(work->nonce2);
-	free(work->ntime);
-	work->job_id = NULL;
-	work->nonce2 = NULL;
-	work->ntime = NULL;
-
-	if (work->tmpl) {
-		struct pool *pool = work->pool;
-		mutex_lock(&pool->pool_lock);
-		bool free_tmpl = !--*work->tmpl_refcount;
-		mutex_unlock(&pool->pool_lock);
-		if (free_tmpl) {
-			blktmpl_free(work->tmpl);
-			free(work->tmpl_refcount);
-		}
-		work->tmpl = NULL;
-		work->tmpl_refcount = NULL;
-	}
-}
-
-/* All dynamically allocated work structs should be freed here to not leak any
- * ram from arrays allocated within the work struct */
-void free_work(struct work *work)
-{
-	clean_work(work);
-	free(work);
-}
-
 static void workio_cmd_free(struct workio_cmd *wc)
 static void workio_cmd_free(struct workio_cmd *wc)
 {
 {
 	if (!wc)
 	if (!wc)
@@ -3099,8 +3115,13 @@ char **initial_args;
 
 
 static void clean_up(void);
 static void clean_up(void);
 
 
-static inline void __app_restart(void)
+void app_restart(void)
 {
 {
+	applog(LOG_WARNING, "Attempting to restart %s", packagename);
+
+	__kill_work();
+	clean_up();
+
 #if defined(unix)
 #if defined(unix)
 	if (forkpid > 0) {
 	if (forkpid > 0) {
 		kill(forkpid, SIGTERM);
 		kill(forkpid, SIGTERM);
@@ -3109,55 +3130,17 @@ static inline void __app_restart(void)
 #endif
 #endif
 
 
 	execv(initial_args[0], initial_args);
 	execv(initial_args[0], initial_args);
-}
-
-void app_restart(void)
-{
-	applog(LOG_WARNING, "Attempting to restart %s", packagename);
-
-	__kill_work();
-	clean_up();
-
-	__app_restart();
-
-	/* We shouldn't reach here */
 	applog(LOG_WARNING, "Failed to restart application");
 	applog(LOG_WARNING, "Failed to restart application");
 }
 }
 
 
-/* Returns all signal handlers to their defaults */
-static inline void __sighandler(void)
+static void sighandler(int __maybe_unused sig)
 {
 {
 	/* Restore signal handlers so we can still quit if kill_work fails */
 	/* Restore signal handlers so we can still quit if kill_work fails */
 	sigaction(SIGTERM, &termhandler, NULL);
 	sigaction(SIGTERM, &termhandler, NULL);
 	sigaction(SIGINT, &inthandler, NULL);
 	sigaction(SIGINT, &inthandler, NULL);
-	if (opt_restart) {
-		sigaction(SIGSEGV, &segvhandler, NULL);
-		sigaction(SIGILL, &illhandler, NULL);
-#ifndef WIN32
-		sigaction(SIGBUS, &bushandler, NULL);
-#endif
-	}
-}
-
-static void sighandler(int __maybe_unused sig)
-{
-	__sighandler();
 	kill_work();
 	kill_work();
 }
 }
 
 
-/* Handles segfaults and other crashes by attempting to restart cgminer. Try to
- * do as little as possible since we are probably corrupted. */
-static void seghandler(int sig)
-{
-	__sighandler();
-	fprintf(stderr, "\nCrashed with signal %d! Will attempt to restart\n", sig);
-	__app_restart();
-	/* We shouldn't reach here */
-	fprintf(stderr, "Failed to restart, exiting now\n");
-
-	exit(1);
-}
-
 static void start_longpoll(void);
 static void start_longpoll(void);
 static void stop_longpoll(void);
 static void stop_longpoll(void);
 
 
@@ -3427,7 +3410,8 @@ static void *get_work_thread(void *userdata)
 	struct pool *pool;
 	struct pool *pool;
 
 
 	pthread_detach(pthread_self());
 	pthread_detach(pthread_self());
-	rename_thr("bfg-get_work");
+
+	RenameThread("get_work");
 
 
 	applog(LOG_DEBUG, "Creating extra get work thread");
 	applog(LOG_DEBUG, "Creating extra get work thread");
 
 
@@ -3645,7 +3629,8 @@ static void *submit_work_thread(void *userdata)
 	time_t staleexpire;
 	time_t staleexpire;
 
 
 	pthread_detach(pthread_self());
 	pthread_detach(pthread_self());
-	rename_thr("bfg-submit_work");
+
+	RenameThread("submit_work");
 
 
 	applog(LOG_DEBUG, "Creating extra submit work thread");
 	applog(LOG_DEBUG, "Creating extra submit work thread");
 
 
@@ -4327,7 +4312,7 @@ static void *stage_thread(void *userdata)
 	struct thr_info *mythr = userdata;
 	struct thr_info *mythr = userdata;
 	bool ok = true;
 	bool ok = true;
 
 
-	rename_thr("bfg-stage");
+	RenameThread("stage");
 
 
 	while (ok) {
 	while (ok) {
 		struct work *work = NULL;
 		struct work *work = NULL;
@@ -5063,7 +5048,7 @@ retry:
 
 
 static void *input_thread(void __maybe_unused *userdata)
 static void *input_thread(void __maybe_unused *userdata)
 {
 {
-	rename_thr("bfg-input");
+	RenameThread("input");
 
 
 	if (!curses_active)
 	if (!curses_active)
 		return NULL;
 		return NULL;
@@ -5125,7 +5110,7 @@ static void *workio_thread(void *userdata)
 	struct thr_info *mythr = userdata;
 	struct thr_info *mythr = userdata;
 	bool ok = true;
 	bool ok = true;
 
 
-	rename_thr("bfg-workio");
+	RenameThread("work_io");
 
 
 	while (ok) {
 	while (ok) {
 		struct workio_cmd *wc;
 		struct workio_cmd *wc;
@@ -5179,9 +5164,10 @@ static void *api_thread(void *userdata)
 	struct thr_info *mythr = userdata;
 	struct thr_info *mythr = userdata;
 
 
 	pthread_detach(pthread_self());
 	pthread_detach(pthread_self());
-	rename_thr("bfg-rpc");
 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 
 
+	RenameThread("rpc");
+
 	api(api_thr_id);
 	api(api_thr_id);
 
 
 	PTH(mythr) = 0L;
 	PTH(mythr) = 0L;
@@ -5465,6 +5451,26 @@ static void clear_stratum_shares(struct pool *pool)
 	}
 	}
 }
 }
 
 
+/* We only need to maintain a secondary pool connection when we need the
+ * capacity to get work from the backup pools while still on the primary */
+static bool cnx_needed(struct pool *pool)
+{
+	struct pool *cp;
+
+	if (pool_strategy == POOL_BALANCE)
+		return true;
+	if (pool_strategy == POOL_LOADBALANCE)
+		return true;
+	cp = current_pool();
+	if (cp == pool)
+		return true;
+	if (!cp->has_stratum && (!opt_fail_only || !cp->hdr_path))
+		return true;
+	return false;
+}
+
+static void wait_lpcurrent(struct pool *pool);
+
 /* One stratum thread per pool that has stratum waits on the socket checking
 /* One stratum thread per pool that has stratum waits on the socket checking
  * for new messages and for the integrity of the socket connection. We reset
  * for new messages and for the integrity of the socket connection. We reset
  * the connection based on the integrity of the receive side only as the send
  * the connection based on the integrity of the receive side only as the send
@@ -5475,6 +5481,8 @@ static void *stratum_thread(void *userdata)
 
 
 	pthread_detach(pthread_self());
 	pthread_detach(pthread_self());
 
 
+	RenameThread("stratum");
+
 	while (42) {
 	while (42) {
 		struct timeval timeout;
 		struct timeval timeout;
 		fd_set rd;
 		fd_set rd;
@@ -5483,6 +5491,22 @@ static void *stratum_thread(void *userdata)
 		if (unlikely(!pool->has_stratum))
 		if (unlikely(!pool->has_stratum))
 			break;
 			break;
 
 
+		/* Check to see whether we need to maintain this connection
+		 * indefinitely or just bring it up when we switch to this
+		 * pool */
+		if (!cnx_needed(pool)) {
+			suspend_stratum(pool);
+			wait_lpcurrent(pool);
+			if (!initiate_stratum(pool) || !auth_stratum(pool)) {
+				pool_died(pool);
+				while (!initiate_stratum(pool) || !auth_stratum(pool)) {
+					if (pool->removed)
+						goto out;
+					sleep(30);
+				}
+			}
+		}
+
 		FD_ZERO(&rd);
 		FD_ZERO(&rd);
 		FD_SET(pool->sock, &rd);
 		FD_SET(pool->sock, &rd);
 		timeout.tv_sec = 120;
 		timeout.tv_sec = 120;
@@ -5983,7 +6007,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	unsigned char *coinbase, merkle_root[32], merkle_sha[64], *merkle_hash;
 	unsigned char *coinbase, merkle_root[32], merkle_sha[64], *merkle_hash;
 	int len, cb1_len, n1_len, cb2_len, i;
 	int len, cb1_len, n1_len, cb2_len, i;
 	uint32_t *data32, *swap32;
 	uint32_t *data32, *swap32;
-	char header[260];
+	char *header;
 
 
 	mutex_lock(&pool->pool_lock);
 	mutex_lock(&pool->pool_lock);
 
 
@@ -6017,13 +6041,13 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 		swap32[i] = swab32(data32[i]);
 		swap32[i] = swab32(data32[i]);
 	merkle_hash = (unsigned char *)bin2hex((const unsigned char *)merkle_root, 32);
 	merkle_hash = (unsigned char *)bin2hex((const unsigned char *)merkle_root, 32);
 
 
-	sprintf(header, "%s", pool->swork.bbversion);
-	strcat(header, pool->swork.prev_hash);
-	strcat(header, (char *)merkle_hash);
-	strcat(header, pool->swork.ntime);
-	strcat(header, pool->swork.nbit);
-	strcat(header, "00000000"); /* nonce */
-	strcat(header, "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000");
+	header = strdup(pool->swork.bbversion);
+	header = realloc_strcat(header, pool->swork.prev_hash);
+	header = realloc_strcat(header, (char *)merkle_hash);
+	header = realloc_strcat(header, pool->swork.ntime);
+	header = realloc_strcat(header, pool->swork.nbit);
+	header = realloc_strcat(header, "00000000"); /* nonce */
+	header = realloc_strcat(header, "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000");
 
 
 	/* Store the stratum work diff to check it still matches the pool's
 	/* Store the stratum work diff to check it still matches the pool's
 	 * stratum diff when submitting shares */
 	 * stratum diff when submitting shares */
@@ -6044,6 +6068,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
 	/* Convert hex data to binary data for work */
 	/* Convert hex data to binary data for work */
 	if (unlikely(!hex2bin(work->data, header, 128)))
 	if (unlikely(!hex2bin(work->data, header, 128)))
 		quit(1, "Failed to convert header to data in gen_stratum_work");
 		quit(1, "Failed to convert header to data in gen_stratum_work");
+	free(header);
 	calc_midstate(work);
 	calc_midstate(work);
 
 
 	set_work_target(work, work->sdiff);
 	set_work_target(work, work->sdiff);
@@ -6196,7 +6221,6 @@ enum test_nonce2_result hashtest2(struct work *work, bool checktarget)
 	unsigned char hash1[32];
 	unsigned char hash1[32];
 	unsigned char hash2[32];
 	unsigned char hash2[32];
 	uint32_t *hash2_32 = (uint32_t *)hash2;
 	uint32_t *hash2_32 = (uint32_t *)hash2;
-	struct pool *pool = work->pool;
 
 
 	swap32yes(swap32, data32, 80 / 4);
 	swap32yes(swap32, data32, 80 / 4);
 
 
@@ -6213,21 +6237,6 @@ enum test_nonce2_result hashtest2(struct work *work, bool checktarget)
 
 
 	memcpy((void*)work->hash, hash2, 32);
 	memcpy((void*)work->hash, hash2, 32);
 
 
-	if (work->stratum) {
-		double diff;
-
-		mutex_lock(&pool->pool_lock);
-		diff = pool->swork.diff;
-		mutex_unlock(&pool->pool_lock);
-
-		/* Retarget share only if pool diff has dropped since we
-		 * generated this work */
-		if (unlikely(work->sdiff > diff)) {
-			applog(LOG_DEBUG, "Share needs retargetting to match pool");
-			set_work_target(work, diff);
-		}
-	}
-
 	if (!fulltest(work->hash, work->target))
 	if (!fulltest(work->hash, work->target))
 		return TNR_HIGH;
 		return TNR_HIGH;
 
 
@@ -6326,12 +6335,6 @@ void *miner_thread(void *userdata)
 	struct cgminer_stats *pool_stats;
 	struct cgminer_stats *pool_stats;
 	struct timeval getwork_start;
 	struct timeval getwork_start;
 
 
-	{
-		char thrname[16];
-		sprintf(thrname, "bfg-miner-%s%d", api->name, cgpu->device_id);
-		rename_thr(thrname);
-	}
-
 	/* Try to cycle approximately 5 times before each log update */
 	/* Try to cycle approximately 5 times before each log update */
 	const long cycle = opt_log_interval / 5 ? : 1;
 	const long cycle = opt_log_interval / 5 ? : 1;
 	struct timeval tv_start, tv_end, tv_workstart, tv_lastupdate;
 	struct timeval tv_start, tv_end, tv_workstart, tv_lastupdate;
@@ -6345,6 +6348,10 @@ void *miner_thread(void *userdata)
 
 
 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 
 
+	char threadname[20];
+	snprintf(threadname, 20, "miner_%s%d.%d", api->name, cgpu->device_id, mythr->device_thread);
+	RenameThread(threadname);
+
 	gettimeofday(&getwork_start, NULL);
 	gettimeofday(&getwork_start, NULL);
 
 
 	if (api->thread_init && !api->thread_init(mythr)) {
 	if (api->thread_init && !api->thread_init(mythr)) {
@@ -6525,6 +6532,8 @@ static void convert_to_work(json_t *val, int rolltime, struct pool *pool, struct
 		free_work(work);
 		free_work(work);
 		return;
 		return;
 	}
 	}
+	total_getworks++;
+	pool->getwork_requested++;
 	work->pool = pool;
 	work->pool = pool;
 	memcpy(&(work->tv_getwork), tv_lp, sizeof(struct timeval));
 	memcpy(&(work->tv_getwork), tv_lp, sizeof(struct timeval));
 	memcpy(&(work->tv_getwork_reply), tv_lp_reply, sizeof(struct timeval));
 	memcpy(&(work->tv_getwork_reply), tv_lp_reply, sizeof(struct timeval));
@@ -6584,7 +6593,7 @@ static struct pool *select_longpoll_pool(struct pool *cp)
  */
  */
 static void wait_lpcurrent(struct pool *pool)
 static void wait_lpcurrent(struct pool *pool)
 {
 {
-	if (pool->enabled == POOL_REJECTING || pool_strategy == POOL_LOADBALANCE || pool_strategy == POOL_BALANCE)
+	if (cnx_needed(pool))
 		return;
 		return;
 
 
 	while (pool != current_pool() && pool_strategy != POOL_LOADBALANCE && pool_strategy != POOL_BALANCE) {
 	while (pool != current_pool() && pool_strategy != POOL_LOADBALANCE && pool_strategy != POOL_BALANCE) {
@@ -6613,7 +6622,7 @@ static void *longpoll_thread(void *userdata)
 	char *lp_url;
 	char *lp_url;
 	int rolltime;
 	int rolltime;
 
 
-	rename_thr("bfg-longpoll");
+	RenameThread("longpoll");
 
 
 	curl = curl_easy_init();
 	curl = curl_easy_init();
 	if (unlikely(!curl)) {
 	if (unlikely(!curl)) {
@@ -6797,7 +6806,7 @@ static void *watchpool_thread(void __maybe_unused *userdata)
 {
 {
 	int intervals = 0;
 	int intervals = 0;
 
 
-	rename_thr("bfg-watchpool");
+	RenameThread("watchpool");
 
 
 	while (42) {
 	while (42) {
 		struct timeval now;
 		struct timeval now;
@@ -6871,7 +6880,7 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 	const unsigned int interval = WATCHDOG_INTERVAL;
 	const unsigned int interval = WATCHDOG_INTERVAL;
 	struct timeval zero_tv;
 	struct timeval zero_tv;
 
 
-	rename_thr("bfg-watchdog");
+	RenameThread("watchdog");
 
 
 	memset(&zero_tv, 0, sizeof(struct timeval));
 	memset(&zero_tv, 0, sizeof(struct timeval));
 	gettimeofday(&rotate_tv, NULL);
 	gettimeofday(&rotate_tv, NULL);
@@ -7513,8 +7522,15 @@ int main(int argc, char *argv[])
 	for  (i = 0; i < argc; i++)
 	for  (i = 0; i < argc; i++)
 		initial_args[i] = strdup(argv[i]);
 		initial_args[i] = strdup(argv[i]);
 	initial_args[argc] = NULL;
 	initial_args[argc] = NULL;
+
 #ifdef HAVE_LIBUSB
 #ifdef HAVE_LIBUSB
-        libusb_init(NULL);
+	int err = libusb_init(NULL);
+	if (err) {
+		fprintf(stderr, "libusb_init() failed err %d", err);
+		fflush(stderr);
+		quit(1, "libusb_init() failed");
+	}
+	mutex_init(&cgusb_lock);
 #endif
 #endif
 
 
 	mutex_init(&hash_lock);
 	mutex_init(&hash_lock);
@@ -7607,18 +7623,6 @@ int main(int argc, char *argv[])
 	if (!config_loaded)
 	if (!config_loaded)
 		load_default_config();
 		load_default_config();
 
 
-	if (opt_restart) {
-		struct sigaction shandler;
-
-		shandler.sa_handler = &seghandler;
-		shandler.sa_flags = 0;
-		sigemptyset(&shandler.sa_mask);
-		sigaction(SIGSEGV, &shandler, &segvhandler);
-		sigaction(SIGILL, &shandler, &illhandler);
-#ifndef WIN32
-		sigaction(SIGBUS, &shandler, &bushandler);
-#endif
-	}
 	if (opt_benchmark) {
 	if (opt_benchmark) {
 		struct pool *pool;
 		struct pool *pool;
 
 

+ 10 - 2
miner.h

@@ -551,7 +551,6 @@ extern void thr_info_cancel(struct thr_info *thr);
 extern void thr_info_freeze(struct thr_info *thr);
 extern void thr_info_freeze(struct thr_info *thr);
 extern void nmsleep(unsigned int msecs);
 extern void nmsleep(unsigned int msecs);
 extern double us_tdiff(struct timeval *end, struct timeval *start);
 extern double us_tdiff(struct timeval *end, struct timeval *start);
-extern void rename_thr(const char* name);
 extern double tdiff(struct timeval *end, struct timeval *start);
 extern double tdiff(struct timeval *end, struct timeval *start);
 
 
 struct string_elist {
 struct string_elist {
@@ -711,6 +710,9 @@ extern bool opt_restart;
 extern char *opt_icarus_options;
 extern char *opt_icarus_options;
 extern char *opt_icarus_timing;
 extern char *opt_icarus_timing;
 extern bool opt_worktime;
 extern bool opt_worktime;
+#ifdef HAVE_LIBUSB
+extern int opt_usbdump;
+#endif
 #ifdef USE_BITFORCE
 #ifdef USE_BITFORCE
 extern bool opt_bfl_noncerange;
 extern bool opt_bfl_noncerange;
 #endif
 #endif
@@ -740,6 +742,11 @@ extern int opt_queue;
 extern int opt_scantime;
 extern int opt_scantime;
 extern int opt_expiry;
 extern int opt_expiry;
 
 
+#ifdef HAVE_LIBUSB
+extern pthread_mutex_t cgusb_lock;
+#endif
+
+extern pthread_mutex_t hash_lock;
 extern pthread_mutex_t console_lock;
 extern pthread_mutex_t console_lock;
 extern pthread_mutex_t ch_lock;
 extern pthread_mutex_t ch_lock;
 
 
@@ -825,6 +832,7 @@ extern int opt_fail_pause;
 extern int opt_log_interval;
 extern int opt_log_interval;
 extern unsigned long long global_hashrate;
 extern unsigned long long global_hashrate;
 extern char *current_fullhash;
 extern char *current_fullhash;
+extern uint64_t best_diff;
 extern struct timeval block_timeval;
 extern struct timeval block_timeval;
 
 
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
@@ -1008,7 +1016,7 @@ struct work {
 	unsigned char	target[32];
 	unsigned char	target[32];
 	unsigned char	hash[32];
 	unsigned char	hash[32];
 
 
-	uint32_t	outputhash;
+	uint64_t	outputhash;
 
 
 	int		rolls;
 	int		rolls;
 
 

+ 15 - 12
scrypt.c

@@ -250,11 +250,10 @@ PBKDF2_SHA256_80_128(const uint32_t * passwd, uint32_t * buf)
 }
 }
 
 
 
 
-static inline uint32_t
-PBKDF2_SHA256_80_128_32(const uint32_t * passwd, const uint32_t * salt)
+static inline void
+PBKDF2_SHA256_80_128_32(const uint32_t * passwd, const uint32_t * salt, uint32_t *ostate)
 {
 {
 	uint32_t tstate[8];
 	uint32_t tstate[8];
-	uint32_t ostate[8];
 	uint32_t ihash[8];
 	uint32_t ihash[8];
 	uint32_t i;
 	uint32_t i;
 
 
@@ -292,8 +291,6 @@ PBKDF2_SHA256_80_128_32(const uint32_t * passwd, const uint32_t * salt)
 
 
 	/* Feed the inner hash to the outer SHA256 operation. */
 	/* Feed the inner hash to the outer SHA256 operation. */
 	SHA256_Transform(ostate, pad, 0);
 	SHA256_Transform(ostate, pad, 0);
-	/* Finish the outer SHA256 operation. */
-	return be32toh(ostate[7]);
 }
 }
 
 
 
 
@@ -359,7 +356,7 @@ salsa20_8(uint32_t B[16], const uint32_t Bx[16])
 /* cpu and memory intensive function to transform a 80 byte buffer into a 32 byte output
 /* cpu and memory intensive function to transform a 80 byte buffer into a 32 byte output
    scratchpad size needs to be at least 63 + (128 * r * p) + (256 * r + 64) + (128 * r * N) bytes
    scratchpad size needs to be at least 63 + (128 * r * p) + (256 * r + 64) + (128 * r * N) bytes
  */
  */
-static uint32_t scrypt_1024_1_1_256_sp(const uint32_t* input, char* scratchpad)
+static void scrypt_1024_1_1_256_sp(const uint32_t* input, char* scratchpad, uint32_t *ostate)
 {
 {
 	uint32_t * V;
 	uint32_t * V;
 	uint32_t X[32];
 	uint32_t X[32];
@@ -402,32 +399,35 @@ static uint32_t scrypt_1024_1_1_256_sp(const uint32_t* input, char* scratchpad)
 		salsa20_8(&X[16], &X[0]);
 		salsa20_8(&X[16], &X[0]);
 	}
 	}
 
 
-	return PBKDF2_SHA256_80_128_32(input, X);
+	PBKDF2_SHA256_80_128_32(input, X, ostate);
 }
 }
 
 
 void scrypt_outputhash(struct work *work)
 void scrypt_outputhash(struct work *work)
 {
 {
-	uint32_t data[20];
+	uint32_t data[20], ohash[8], rhash[8];
 	char *scratchbuf;
 	char *scratchbuf;
 	uint32_t *nonce = (uint32_t *)(work->data + 76);
 	uint32_t *nonce = (uint32_t *)(work->data + 76);
 
 
 	be32enc_vect(data, (const uint32_t *)work->data, 19);
 	be32enc_vect(data, (const uint32_t *)work->data, 19);
 	data[19] = htobe32(*nonce);
 	data[19] = htobe32(*nonce);
 	scratchbuf = alloca(131584);
 	scratchbuf = alloca(131584);
-	work->outputhash = scrypt_1024_1_1_256_sp(data, scratchbuf);
+	scrypt_1024_1_1_256_sp(data, scratchbuf, ohash);
+	swap256(rhash, ohash);
+	work->outputhash = be64toh(*((uint64_t *)rhash));
 }
 }
 
 
 /* Used externally as confirmation of correct OCL code */
 /* Used externally as confirmation of correct OCL code */
 bool scrypt_test(unsigned char *pdata, const unsigned char *ptarget, uint32_t nonce)
 bool scrypt_test(unsigned char *pdata, const unsigned char *ptarget, uint32_t nonce)
 {
 {
 	uint32_t tmp_hash7, Htarg = ((const uint32_t *)ptarget)[7];
 	uint32_t tmp_hash7, Htarg = ((const uint32_t *)ptarget)[7];
+	uint32_t data[20], ohash[8];
 	char *scratchbuf;
 	char *scratchbuf;
-	uint32_t data[20];
 
 
 	be32enc_vect(data, (const uint32_t *)pdata, 19);
 	be32enc_vect(data, (const uint32_t *)pdata, 19);
 	data[19] = htobe32(nonce);
 	data[19] = htobe32(nonce);
 	scratchbuf = alloca(131584);
 	scratchbuf = alloca(131584);
-	tmp_hash7 = scrypt_1024_1_1_256_sp(data, scratchbuf);
+	scrypt_1024_1_1_256_sp(data, scratchbuf, ohash);
+	tmp_hash7 = be32toh(ohash[7]);
 
 
 	return (tmp_hash7 <= Htarg);
 	return (tmp_hash7 <= Htarg);
 }
 }
@@ -453,9 +453,12 @@ bool scanhash_scrypt(struct thr_info *thr, const unsigned char __maybe_unused *p
 	}
 	}
 
 
 	while(1) {
 	while(1) {
+		uint32_t ostate[8];
+
 		*nonce = ++n;
 		*nonce = ++n;
 		data[19] = n;
 		data[19] = n;
-		tmp_hash7 = scrypt_1024_1_1_256_sp(data, scratchbuf);
+		scrypt_1024_1_1_256_sp(data, scratchbuf, ostate);
+		tmp_hash7 = be32toh(ostate[7]);
 
 
 		if (unlikely(tmp_hash7 <= Htarg)) {
 		if (unlikely(tmp_hash7 <= Htarg)) {
 			((uint32_t *)pdata)[19] = htobe32(n);
 			((uint32_t *)pdata)[19] = htobe32(n);

+ 1192 - 0
usbutils.c

@@ -0,0 +1,1192 @@
+/*
+ * Copyright 2012 Andrew Smith
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "logging.h"
+#include "miner.h"
+#include "usbutils.h"
+
+#ifdef USE_ICARUS
+#define DRV_ICARUS 1
+#endif
+
+#ifdef USE_BITFORCE
+#define DRV_BITFORCE 2
+#endif
+
+#ifdef USE_MODMINER
+#define DRV_MODMINER 3
+#endif
+
+#define DRV_LAST -1
+
+#define USB_CONFIG 1
+
+#define EPI(x) (LIBUSB_ENDPOINT_IN | (unsigned char)(x))
+#define EPO(x) (LIBUSB_ENDPOINT_OUT | (unsigned char)(x))
+
+#ifdef WIN32
+#define MODMINER_TIMEOUT_MS 200
+#else
+#define MODMINER_TIMEOUT_MS 100
+#endif
+
+#ifdef USE_MODMINER
+static struct usb_endpoints mmq_eps[] = {
+	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(3), 0 },
+	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(3), 0 }
+};
+#endif
+
+// TODO: Add support for (at least) Interrupt endpoints
+static struct usb_find_devices find_dev[] = {
+/*
+#ifdef USE_ICARUS
+	{ DRV_ICARUS, 	"ICA",	0x067b,	0x0230,	true,	EPI(3),	EPO(2), 1 },
+	{ DRV_ICARUS, 	"LOT",	0x0403,	0x6001,	false,	EPI(0),	EPO(0), 1 },
+	{ DRV_ICARUS, 	"CM1",	0x067b,	0x0230,	false,	EPI(0),	EPO(0), 1 },
+#endif
+#ifdef USE_BITFORCE
+	{ DRV_BITFORCE,	"BFL",	0x0403,	0x6014,	true,	EPI(1),	EPO(2), 1 },
+#endif
+*/
+#ifdef USE_MODMINER
+	{
+		.drv = DRV_MODMINER,
+		.name = "MMQ",
+		.idVendor = 0x1fc9,
+		.idProduct = 0x0003,
+		.config = 1,
+		.interface = 1,
+		.timeout = MODMINER_TIMEOUT_MS,
+		.epcount = ARRAY_SIZE(mmq_eps),
+		.eps = mmq_eps },
+#endif
+	{ DRV_LAST, NULL, 0, 0, 0, 0, 0, 0, NULL }
+};
+
+#ifdef USE_BITFORCE
+extern struct device_api bitforce_api;
+#endif
+
+#ifdef USE_ICARUS
+extern struct device_api icarus_api;
+#endif
+
+#ifdef USE_MODMINER
+extern struct device_api modminer_api;
+#endif
+
+/*
+ * Our own internal list of used USB devices
+ * So two drivers or a single driver searching
+ * can't touch the same device during detection
+ */
+struct usb_list {
+	uint8_t bus_number;
+	uint8_t device_address;
+	uint8_t filler[2];
+	struct usb_list *prev;
+	struct usb_list *next;
+};
+
+#define STRBUFLEN 256
+static const char *BLANK = "";
+
+static pthread_mutex_t *list_lock = NULL;
+static struct usb_list *usb_head = NULL;
+
+struct cg_usb_stats_item {
+	uint64_t count;
+	double total_delay;
+	double min_delay;
+	double max_delay;
+	struct timeval first;
+	struct timeval last;
+};
+
+#define CMD_CMD 0
+#define CMD_TIMEOUT 1
+#define CMD_ERROR 2
+
+struct cg_usb_stats_details {
+	int seq;
+	struct cg_usb_stats_item item[CMD_ERROR+1];
+};
+
+struct cg_usb_stats {
+	char *name;
+	int device_id;
+	struct cg_usb_stats_details *details;
+};
+
+#define SEQ0 0
+#define SEQ1 1
+
+static struct cg_usb_stats *usb_stats = NULL;
+static int next_stat = 0;
+
+static const char **usb_commands;
+
+static const char *C_PING_S = "Ping";
+static const char *C_CLEAR_S = "Clear";
+static const char *C_REQUESTVERSION_S = "RequestVersion";
+static const char *C_GETVERSION_S = "GetVersion";
+static const char *C_REQUESTFPGACOUNT_S = "RequestFPGACount";
+static const char *C_GETFPGACOUNT_S = "GetFPGACount";
+static const char *C_STARTPROGRAM_S = "StartProgram";
+static const char *C_STARTPROGRAMSTATUS_S = "StartProgramStatus";
+static const char *C_PROGRAM_S = "Program";
+static const char *C_PROGRAMSTATUS_S = "ProgramStatus";
+static const char *C_PROGRAMSTATUS2_S = "ProgramStatus2";
+static const char *C_FINALPROGRAMSTATUS_S = "FinalProgramStatus";
+static const char *C_SETCLOCK_S = "SetClock";
+static const char *C_REPLYSETCLOCK_S = "ReplySetClock";
+static const char *C_REQUESTUSERCODE_S = "RequestUserCode";
+static const char *C_GETUSERCODE_S = "GetUserCode";
+static const char *C_REQUESTTEMPERATURE_S = "RequestTemperature";
+static const char *C_GETTEMPERATURE_S = "GetTemperature";
+static const char *C_SENDWORK_S = "SendWork";
+static const char *C_SENDWORKSTATUS_S = "SendWorkStatus";
+static const char *C_REQUESTWORKSTATUS_S = "RequestWorkStatus";
+static const char *C_GETWORKSTATUS_S = "GetWorkStatus";
+
+#ifdef EOL
+#undef EOL
+#endif
+#define EOL "\n"
+
+static const char *DESDEV = "Device";
+static const char *DESCON = "Config";
+static const char *DESSTR = "String";
+static const char *DESINT = "Interface";
+static const char *DESEP = "Endpoint";
+static const char *DESHID = "HID";
+static const char *DESRPT = "Report";
+static const char *DESPHY = "Physical";
+static const char *DESHUB = "Hub";
+
+static const char *EPIN = "In: ";
+static const char *EPOUT = "Out: ";
+static const char *EPX = "?: ";
+
+static const char *CONTROL = "Control";
+static const char *ISOCHRONOUS_X = "Isochronous+?";
+static const char *ISOCHRONOUS_N_X = "Isochronous+None+?";
+static const char *ISOCHRONOUS_N_D = "Isochronous+None+Data";
+static const char *ISOCHRONOUS_N_F = "Isochronous+None+Feedback";
+static const char *ISOCHRONOUS_N_I = "Isochronous+None+Implicit";
+static const char *ISOCHRONOUS_A_X = "Isochronous+Async+?";
+static const char *ISOCHRONOUS_A_D = "Isochronous+Async+Data";
+static const char *ISOCHRONOUS_A_F = "Isochronous+Async+Feedback";
+static const char *ISOCHRONOUS_A_I = "Isochronous+Async+Implicit";
+static const char *ISOCHRONOUS_D_X = "Isochronous+Adaptive+?";
+static const char *ISOCHRONOUS_D_D = "Isochronous+Adaptive+Data";
+static const char *ISOCHRONOUS_D_F = "Isochronous+Adaptive+Feedback";
+static const char *ISOCHRONOUS_D_I = "Isochronous+Adaptive+Implicit";
+static const char *ISOCHRONOUS_S_X = "Isochronous+Sync+?";
+static const char *ISOCHRONOUS_S_D = "Isochronous+Sync+Data";
+static const char *ISOCHRONOUS_S_F = "Isochronous+Sync+Feedback";
+static const char *ISOCHRONOUS_S_I = "Isochronous+Sync+Implicit";
+static const char *BULK = "Bulk";
+static const char *INTERRUPT = "Interrupt";
+static const char *UNKNOWN = "Unknown";
+
+static const char *destype(uint8_t bDescriptorType)
+{
+	switch (bDescriptorType) {
+		case LIBUSB_DT_DEVICE:
+			return DESDEV;
+		case LIBUSB_DT_CONFIG:
+			return DESCON;
+		case LIBUSB_DT_STRING:
+			return DESSTR;
+		case LIBUSB_DT_INTERFACE:
+			return DESINT;
+		case LIBUSB_DT_ENDPOINT:
+			return DESEP;
+		case LIBUSB_DT_HID:
+			return DESHID;
+		case LIBUSB_DT_REPORT:
+			return DESRPT;
+		case LIBUSB_DT_PHYSICAL:
+			return DESPHY;
+		case LIBUSB_DT_HUB:
+			return DESHUB;
+	}
+	return UNKNOWN;
+}
+
+static const char *epdir(uint8_t bEndpointAddress)
+{
+	switch (bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) {
+		case LIBUSB_ENDPOINT_IN:
+			return EPIN;
+		case LIBUSB_ENDPOINT_OUT:
+			return EPOUT;
+	}
+	return EPX;
+}
+
+static const char *epatt(uint8_t bmAttributes)
+{
+	switch(bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) {
+		case LIBUSB_TRANSFER_TYPE_CONTROL:
+			return CONTROL;
+		case LIBUSB_TRANSFER_TYPE_BULK:
+			return BULK;
+		case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+			return INTERRUPT;
+		case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+			switch(bmAttributes & LIBUSB_ISO_SYNC_TYPE_MASK) {
+				case LIBUSB_ISO_SYNC_TYPE_NONE:
+					switch(bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) {
+						case LIBUSB_ISO_USAGE_TYPE_DATA:
+							return ISOCHRONOUS_N_D;
+						case LIBUSB_ISO_USAGE_TYPE_FEEDBACK:
+							return ISOCHRONOUS_N_F;
+						case LIBUSB_ISO_USAGE_TYPE_IMPLICIT:
+							return ISOCHRONOUS_N_I;
+					}
+					return ISOCHRONOUS_N_X;
+				case LIBUSB_ISO_SYNC_TYPE_ASYNC:
+					switch(bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) {
+						case LIBUSB_ISO_USAGE_TYPE_DATA:
+							return ISOCHRONOUS_A_D;
+						case LIBUSB_ISO_USAGE_TYPE_FEEDBACK:
+							return ISOCHRONOUS_A_F;
+						case LIBUSB_ISO_USAGE_TYPE_IMPLICIT:
+							return ISOCHRONOUS_A_I;
+					}
+					return ISOCHRONOUS_A_X;
+				case LIBUSB_ISO_SYNC_TYPE_ADAPTIVE:
+					switch(bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) {
+						case LIBUSB_ISO_USAGE_TYPE_DATA:
+							return ISOCHRONOUS_D_D;
+						case LIBUSB_ISO_USAGE_TYPE_FEEDBACK:
+							return ISOCHRONOUS_D_F;
+						case LIBUSB_ISO_USAGE_TYPE_IMPLICIT:
+							return ISOCHRONOUS_D_I;
+					}
+					return ISOCHRONOUS_D_X;
+				case LIBUSB_ISO_SYNC_TYPE_SYNC:
+					switch(bmAttributes & LIBUSB_ISO_USAGE_TYPE_MASK) {
+						case LIBUSB_ISO_USAGE_TYPE_DATA:
+							return ISOCHRONOUS_S_D;
+						case LIBUSB_ISO_USAGE_TYPE_FEEDBACK:
+							return ISOCHRONOUS_S_F;
+						case LIBUSB_ISO_USAGE_TYPE_IMPLICIT:
+							return ISOCHRONOUS_S_I;
+					}
+					return ISOCHRONOUS_S_X;
+			}
+			return ISOCHRONOUS_X;
+	}
+
+	return UNKNOWN;
+}
+
+static void append(char **buf, char *append, size_t *off, size_t *len)
+{
+	int new = strlen(append);
+	if ((new + *off) >= *len)
+	{
+		*len *= 2;
+		*buf = realloc(*buf, *len);
+	}
+
+	strcpy(*buf + *off, append);
+	*off += new;
+}
+
+static bool setgetdes(ssize_t count, libusb_device *dev, struct libusb_device_handle *handle, struct libusb_config_descriptor **config, int cd, char **buf, size_t *off, size_t *len)
+{
+	char tmp[512];
+	int err;
+
+	err = libusb_set_configuration(handle, cd);
+	if (err) {
+		sprintf(tmp, EOL "  ** dev %d: Failed to set config descriptor to %d, err %d",
+				(int)count, cd, err);
+		append(buf, tmp, off, len);
+		return false;
+	}
+
+	err = libusb_get_active_config_descriptor(dev, config);
+	if (err) {
+		sprintf(tmp, EOL "  ** dev %d: Failed to get active config descriptor set to %d, err %d",
+				(int)count, cd, err);
+		append(buf, tmp, off, len);
+		return false;
+	}
+
+	sprintf(tmp, EOL "  ** dev %d: Set & Got active config descriptor to %d, err %d",
+			(int)count, cd, err);
+	append(buf, tmp, off, len);
+	return true;
+}
+
+static void usb_full(ssize_t count, libusb_device *dev, char **buf, size_t *off, size_t *len)
+{
+	struct libusb_device_descriptor desc;
+	struct libusb_device_handle *handle;
+	struct libusb_config_descriptor *config;
+	const struct libusb_interface_descriptor *idesc;
+	const struct libusb_endpoint_descriptor *epdesc;
+	unsigned char man[STRBUFLEN+1];
+	unsigned char prod[STRBUFLEN+1];
+	unsigned char ser[STRBUFLEN+1];
+	char tmp[512];
+	int err, i, j, k;
+
+	err = libusb_get_device_descriptor(dev, &desc);
+	if (err) {
+		sprintf(tmp, EOL ".USB dev %d: Failed to get descriptor, err %d",
+					(int)count, err);
+		append(buf, tmp, off, len);
+		return;
+	}
+
+	sprintf(tmp, EOL ".USB dev %d: Device Descriptor:" EOL "\tLength: %d" EOL
+			"\tDescriptor Type: %s" EOL "\tUSB: %04x" EOL "\tDeviceClass: %d" EOL
+			"\tDeviceSubClass: %d" EOL "\tDeviceProtocol: %d" EOL "\tMaxPacketSize0: %d" EOL
+			"\tidVendor: %04x" EOL "\tidProduct: %04x" EOL "\tDeviceRelease: %x" EOL
+			"\tNumConfigurations: %d",
+				(int)count, (int)(desc.bLength), destype(desc.bDescriptorType),
+				desc.bcdUSB, (int)(desc.bDeviceClass), (int)(desc.bDeviceSubClass),
+				(int)(desc.bDeviceProtocol), (int)(desc.bMaxPacketSize0),
+				desc.idVendor, desc.idProduct, desc.bcdDevice,
+				(int)(desc.bNumConfigurations));
+	append(buf, tmp, off, len);
+
+	err = libusb_open(dev, &handle);
+	if (err) {
+		sprintf(tmp, EOL "  ** dev %d: Failed to open, err %d", (int)count, err);
+		append(buf, tmp, off, len);
+		return;
+	}
+
+	if (libusb_kernel_driver_active(handle, 0) == 1) {
+		sprintf(tmp, EOL "   * dev %d: kernel attached", (int)count);
+		append(buf, tmp, off, len);
+	}
+
+	err = libusb_get_active_config_descriptor(dev, &config);
+	if (err) {
+		if (!setgetdes(count, dev, handle, &config, 1, buf, off, len)
+		&&  !setgetdes(count, dev, handle, &config, 0, buf, off, len)) {
+			libusb_close(handle);
+			sprintf(tmp, EOL "  ** dev %d: Failed to set config descriptor to %d or %d",
+					(int)count, 1, 0);
+			append(buf, tmp, off, len);
+			return;
+		}
+	}
+
+	sprintf(tmp, EOL "     dev %d: Active Config:" EOL "\tDescriptorType: %s" EOL
+			"\tNumInterfaces: %d" EOL "\tConfigurationValue: %d" EOL
+			"\tAttributes: %d" EOL "\tMaxPower: %d",
+				(int)count, destype(config->bDescriptorType),
+				(int)(config->bNumInterfaces), (int)(config->iConfiguration),
+				(int)(config->bmAttributes), (int)(config->MaxPower));
+	append(buf, tmp, off, len);
+
+	for (i = 0; i < (int)(config->bNumInterfaces); i++) {
+		for (j = 0; j < config->interface[i].num_altsetting; j++) {
+			idesc = &(config->interface[i].altsetting[j]);
+
+			sprintf(tmp, EOL "     _dev %d: Interface Descriptor %d:" EOL
+					"\tDescriptorType: %s" EOL "\tInterfaceNumber: %d" EOL
+					"\tNumEndpoints: %d" EOL "\tInterfaceClass: %d" EOL
+					"\tInterfaceSubClass: %d" EOL "\tInterfaceProtocol: %d",
+						(int)count, j, destype(idesc->bDescriptorType),
+						(int)(idesc->bInterfaceNumber),
+						(int)(idesc->bNumEndpoints),
+						(int)(idesc->bInterfaceClass),
+						(int)(idesc->bInterfaceSubClass),
+						(int)(idesc->bInterfaceProtocol));
+			append(buf, tmp, off, len);
+
+			for (k = 0; k < (int)(idesc->bNumEndpoints); k++) {
+				epdesc = &(idesc->endpoint[k]);
+
+				sprintf(tmp, EOL "     __dev %d: Interface %d Endpoint %d:" EOL
+						"\tDescriptorType: %s" EOL
+						"\tEndpointAddress: %s0x%x" EOL
+						"\tAttributes: %s" EOL "\tMaxPacketSize: %d" EOL
+						"\tInterval: %d" EOL "\tRefresh: %d",
+							(int)count, (int)(idesc->bInterfaceNumber), k,
+							destype(epdesc->bDescriptorType),
+							epdir(epdesc->bEndpointAddress),
+							(int)(epdesc->bEndpointAddress),
+							epatt(epdesc->bmAttributes),
+							epdesc->wMaxPacketSize,
+							(int)(epdesc->bInterval),
+							(int)(epdesc->bRefresh));
+				append(buf, tmp, off, len);
+			}
+		}
+	}
+
+	libusb_free_config_descriptor(config);
+	config = NULL;
+
+	err = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, man, STRBUFLEN);
+	if (err < 0)
+		sprintf((char *)man, "** err(%d)", err);
+
+	err = libusb_get_string_descriptor_ascii(handle, desc.iProduct, prod, STRBUFLEN);
+	if (err < 0)
+		sprintf((char *)prod, "** err(%d)", err);
+
+	err = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, ser, STRBUFLEN);
+	if (err < 0)
+		sprintf((char *)ser, "** err(%d)", err);
+
+	sprintf(tmp, EOL "     dev %d: More Info:" EOL "\tManufacturer: '%s'" EOL
+			"\tProduct: '%s'" EOL "\tSerial '%s'",
+				(int)count, man, prod, ser);
+	append(buf, tmp, off, len);
+
+	libusb_close(handle);
+}
+
+// Function to dump all USB devices
+static void usb_all()
+{
+	libusb_device **list;
+	ssize_t count, i;
+	char *buf;
+	size_t len, off;
+
+	count = libusb_get_device_list(NULL, &list);
+	if (count < 0) {
+		applog(LOG_ERR, "USB all: failed, err %d", (int)count);
+		return;
+	}
+
+	if (count == 0)
+		applog(LOG_WARNING, "USB all: found no devices");
+	else
+	{
+		len = 10000;
+		buf = malloc(len+1);
+
+		sprintf(buf, "USB all: found %d devices", (int)count);
+
+		off = strlen(buf);
+
+		for (i = 0; i < count; i++)
+			usb_full(i, list[i], &buf, &off, &len);
+
+		applog(LOG_WARNING, "%s", buf);
+
+		free(buf);
+	}
+
+	libusb_free_device_list(list, 1);
+}
+
+static void cgusb_check_init()
+{
+	mutex_lock(&cgusb_lock);
+
+	if (list_lock == NULL) {
+		list_lock = calloc(1, sizeof(*list_lock));
+		mutex_init(list_lock);
+
+		if (opt_usbdump >= 0) {
+			libusb_set_debug(NULL, opt_usbdump);
+			usb_all();
+		}
+
+		usb_commands = malloc(sizeof(*usb_commands) * C_MAX);
+
+		// use constants so the stat generation is very quick
+		// and the association between number and name can't
+		// be missalined easily
+		usb_commands[C_PING] = C_PING_S;
+		usb_commands[C_CLEAR] = C_CLEAR_S;
+		usb_commands[C_REQUESTVERSION] = C_REQUESTVERSION_S;
+		usb_commands[C_GETVERSION] = C_GETVERSION_S;
+		usb_commands[C_REQUESTFPGACOUNT] = C_REQUESTFPGACOUNT_S;
+		usb_commands[C_GETFPGACOUNT] = C_GETFPGACOUNT_S;
+		usb_commands[C_STARTPROGRAM] = C_STARTPROGRAM_S;
+		usb_commands[C_STARTPROGRAMSTATUS] = C_STARTPROGRAMSTATUS_S;
+		usb_commands[C_PROGRAM] = C_PROGRAM_S;
+		usb_commands[C_PROGRAMSTATUS] = C_PROGRAMSTATUS_S;
+		usb_commands[C_PROGRAMSTATUS2] = C_PROGRAMSTATUS2_S;
+		usb_commands[C_FINALPROGRAMSTATUS] = C_FINALPROGRAMSTATUS_S;
+		usb_commands[C_SETCLOCK] = C_SETCLOCK_S;
+		usb_commands[C_REPLYSETCLOCK] = C_REPLYSETCLOCK_S;
+		usb_commands[C_REQUESTUSERCODE] = C_REQUESTUSERCODE_S;
+		usb_commands[C_GETUSERCODE] = C_GETUSERCODE_S;
+		usb_commands[C_REQUESTTEMPERATURE] = C_REQUESTTEMPERATURE_S;
+		usb_commands[C_GETTEMPERATURE] = C_GETTEMPERATURE_S;
+		usb_commands[C_SENDWORK] = C_SENDWORK_S;
+		usb_commands[C_SENDWORKSTATUS] = C_SENDWORKSTATUS_S;
+		usb_commands[C_REQUESTWORKSTATUS] = C_REQUESTWORKSTATUS_S;
+		usb_commands[C_GETWORKSTATUS] = C_GETWORKSTATUS_S;
+	}
+
+	mutex_unlock(&cgusb_lock);
+}
+
+static bool in_use(libusb_device *dev, bool lock)
+{
+	struct usb_list *usb_tmp;
+	bool used = false;
+	uint8_t bus_number;
+	uint8_t device_address;
+
+	bus_number = libusb_get_bus_number(dev);
+	device_address = libusb_get_device_address(dev);
+
+	if (lock)
+		mutex_lock(list_lock);
+
+	if ((usb_tmp = usb_head))
+		do {
+			if (bus_number == usb_tmp->bus_number
+			&&  device_address == usb_tmp->device_address) {
+				used = true;
+				break;
+			}
+
+			usb_tmp = usb_tmp->next;
+
+		} while (usb_tmp != usb_head);
+
+	if (lock)
+		mutex_unlock(list_lock);
+
+	return used;
+}
+
+static void add_used(libusb_device *dev, bool lock)
+{
+	struct usb_list *usb_tmp;
+	char buf[128];
+	uint8_t bus_number;
+	uint8_t device_address;
+
+	bus_number = libusb_get_bus_number(dev);
+	device_address = libusb_get_device_address(dev);
+
+	if (lock)
+		mutex_lock(list_lock);
+
+	if (in_use(dev, false)) {
+		if (lock)
+			mutex_unlock(list_lock);
+
+		sprintf(buf, "add_used() duplicate bus_number %d device_address %d",
+				bus_number, device_address);
+		quit(1, buf);
+	}
+
+	usb_tmp = malloc(sizeof(*usb_tmp));
+
+	usb_tmp->bus_number = bus_number;
+	usb_tmp->device_address = device_address;
+
+	if (usb_head) {
+		// add to end
+		usb_tmp->prev = usb_head->prev;
+		usb_tmp->next = usb_head;
+		usb_head->prev = usb_tmp;
+		usb_tmp->prev->next = usb_tmp;
+	} else {
+		usb_tmp->prev = usb_tmp;
+		usb_tmp->next = usb_tmp;
+		usb_head = usb_tmp;
+	}
+
+	if (lock)
+		mutex_unlock(list_lock);
+}
+
+static void release(uint8_t bus_number, uint8_t device_address, bool lock)
+{
+	struct usb_list *usb_tmp;
+	bool found = false;
+	char buf[128];
+
+	if (lock)
+		mutex_lock(list_lock);
+
+	usb_tmp = usb_head;
+	if (usb_tmp)
+		do {
+			if (bus_number == usb_tmp->bus_number
+			&&  device_address == usb_tmp->device_address) {
+				found = true;
+				break;
+			}
+
+			usb_tmp = usb_tmp->next;
+
+		} while (usb_tmp != usb_head);
+
+	if (!found) {
+		if (lock)
+			mutex_unlock(list_lock);
+
+		sprintf(buf, "release() unknown: bus_number %d device_address %d",
+				bus_number, device_address);
+		quit(1, buf);
+	}
+
+	if (usb_tmp->next == usb_tmp) {
+		usb_head = NULL;
+	} else {
+		usb_tmp->next->prev = usb_tmp->prev;
+		usb_tmp->prev->next = usb_tmp->next;
+	}
+
+	if (lock)
+		mutex_unlock(list_lock);
+
+	free(usb_tmp);
+}
+
+static void release_dev(libusb_device *dev, bool lock)
+{
+	uint8_t bus_number;
+	uint8_t device_address;
+
+	bus_number = libusb_get_bus_number(dev);
+	device_address = libusb_get_device_address(dev);
+
+	release(bus_number, device_address, lock);
+}
+
+#if 0
+static void release_cgusb(struct cg_usb_device *cgusb, bool lock)
+{
+	release(cgusb->bus_number, cgusb->device_address, lock);
+}
+#endif
+
+static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb)
+{
+	if (cgusb->serial_string && cgusb->serial_string != BLANK)
+		free(cgusb->serial_string);
+
+	if (cgusb->manuf_string && cgusb->manuf_string != BLANK)
+		free(cgusb->manuf_string);
+
+	if (cgusb->prod_string && cgusb->prod_string != BLANK)
+		free(cgusb->prod_string);
+
+	free(cgusb->descriptor);
+
+	free(cgusb);
+
+	return NULL;
+}
+
+void usb_uninit(struct cgpu_info *cgpu)
+{
+	libusb_release_interface(cgpu->usbdev->handle, cgpu->usbdev->found->interface);
+	libusb_close(cgpu->usbdev->handle);
+	cgpu->usbdev = free_cgusb(cgpu->usbdev);
+}
+
+bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found)
+{
+	struct cg_usb_device *cgusb = NULL;
+	struct libusb_config_descriptor *config = NULL;
+	const struct libusb_interface_descriptor *idesc;
+	const struct libusb_endpoint_descriptor *epdesc;
+	unsigned char strbuf[STRBUFLEN+1];
+	int err, i, j, k;
+
+	cgusb = calloc(1, sizeof(*cgusb));
+	cgusb->found = found;
+	cgusb->descriptor = calloc(1, sizeof(*(cgusb->descriptor)));
+
+	err = libusb_get_device_descriptor(dev, cgusb->descriptor);
+	if (err) {
+		applog(LOG_ERR, "USB init failed to get descriptor, err %d", err);
+		goto dame;
+	}
+
+	err = libusb_open(dev, &(cgusb->handle));
+	if (err) {
+		switch (err) {
+			case LIBUSB_ERROR_ACCESS:
+				applog(LOG_ERR, "USB init open device failed, err %d, you dont have priviledge to access the device", err);
+				break;
+#ifdef WIN32
+			// Windows specific message
+			case LIBUSB_ERROR_NOT_SUPPORTED:
+				applog(LOG_ERR, "USB init, open device failed, err %d, you need to install a Windows USB driver for the device", err);
+				break;
+#endif
+			default:
+				applog(LOG_ERR, "USB init, open device failed, err %d", err);
+		}
+
+		goto dame;
+	}
+
+	if (libusb_kernel_driver_active(cgusb->handle, 0) == 1) {
+		applog(LOG_WARNING, "USB init, kernel attached ...");
+		if (libusb_detach_kernel_driver(cgusb->handle, 0) == 0)
+			applog(LOG_WARNING, "USB init, kernel detached successfully");
+		else
+			applog(LOG_WARNING, "USB init, kernel detach failed :(");
+	}
+
+	err = libusb_set_configuration(cgusb->handle, found->config);
+	if (err) {
+		applog(LOG_DEBUG, "USB init, failed to set config to %d, err %d",
+			found->config, err);
+		goto cldame;
+	}
+
+	err = libusb_get_active_config_descriptor(dev, &config);
+	if (err) {
+		applog(LOG_DEBUG, "USB init, failed to get config descriptor %d, err %d",
+			found->config, err);
+		goto cldame;
+	}
+
+	if ((int)(config->bNumInterfaces) < found->interface)
+		goto cldame;
+
+	for (i = 0; i < found->epcount; i++)
+		found->eps[i].found = false;
+
+	for (i = 0; i < config->interface[found->interface].num_altsetting; i++) {
+		idesc = &(config->interface[found->interface].altsetting[i]);
+		for (j = 0; j < (int)(idesc->bNumEndpoints); j++) {
+			epdesc = &(idesc->endpoint[j]);
+			for (k = 0; k < found->epcount; k++) {
+				if (!found->eps[k].found) {
+					if (epdesc->bmAttributes == found->eps[k].att
+					&&  epdesc->wMaxPacketSize >= found->eps[k].size
+					&&  epdesc->bEndpointAddress == found->eps[k].ep) {
+						found->eps[k].found = true;
+						break;
+					}
+				}
+			}
+		}
+	}
+
+	for (i = 0; i < found->epcount; i++)
+		if (found->eps[i].found == false)
+			goto cldame;
+
+	err = libusb_claim_interface(cgusb->handle, found->interface);
+	if (err) {
+		applog(LOG_DEBUG, "USB init, claim interface %d failed, err %d",
+			found->interface, err);
+		goto cldame;
+	}
+
+	cgusb->bus_number = libusb_get_bus_number(dev);
+	cgusb->device_address = libusb_get_device_address(dev);
+	cgusb->usbver = cgusb->descriptor->bcdUSB;
+
+// TODO: allow this with the right version of the libusb include and running library
+//	cgusb->speed = libusb_get_device_speed(dev);
+
+	err = libusb_get_string_descriptor_ascii(cgusb->handle,
+				cgusb->descriptor->iProduct, strbuf, STRBUFLEN);
+	if (err > 0)
+		cgusb->prod_string = strdup((char *)strbuf);
+	else
+		cgusb->prod_string = (char *)BLANK;
+
+	err = libusb_get_string_descriptor_ascii(cgusb->handle,
+				cgusb->descriptor->iManufacturer, strbuf, STRBUFLEN);
+	if (err > 0)
+		cgusb->manuf_string = strdup((char *)strbuf);
+	else
+		cgusb->manuf_string = (char *)BLANK;
+
+	err = libusb_get_string_descriptor_ascii(cgusb->handle,
+				cgusb->descriptor->iSerialNumber, strbuf, STRBUFLEN);
+	if (err > 0)
+		cgusb->serial_string = strdup((char *)strbuf);
+	else
+		cgusb->serial_string = (char *)BLANK;
+
+// TODO: ?
+//	cgusb->fwVersion <- for temp1/temp2 decision? or serial? (driver-modminer.c)
+//	cgusb->interfaceVersion
+
+	applog(LOG_DEBUG, "USB init device bus_number=%d device_address=%d usbver=%04x prod='%s' manuf='%s' serial='%s'", (int)(cgusb->bus_number), (int)(cgusb->device_address), cgusb->usbver, cgusb->prod_string, cgusb->manuf_string, cgusb->serial_string);
+
+	cgpu->usbdev = cgusb;
+
+	libusb_free_config_descriptor(config);
+
+	return true;
+
+cldame:
+
+	libusb_close(cgusb->handle);
+
+dame:
+
+	if (config)
+		libusb_free_config_descriptor(config);
+
+	cgusb = free_cgusb(cgusb);
+
+	return false;
+}
+
+static bool usb_check_device(struct device_api *api, struct libusb_device *dev, struct usb_find_devices *look)
+{
+	struct libusb_device_descriptor desc;
+	int err;
+
+	err = libusb_get_device_descriptor(dev, &desc);
+	if (err) {
+		applog(LOG_DEBUG, "USB check device: Failed to get descriptor, err %d", err);
+		return false;
+	}
+
+	if (desc.idVendor != look->idVendor || desc.idProduct != look->idProduct) {
+		applog(LOG_DEBUG, "%s looking for %04x:%04x but found %04x:%04x instead",
+			api->name, look->idVendor, look->idProduct, desc.idVendor, desc.idProduct);
+
+		return false;
+	}
+
+	applog(LOG_DEBUG, "%s looking for and found %04x:%04x",
+		api->name, look->idVendor, look->idProduct);
+
+	return true;
+}
+
+static struct usb_find_devices *usb_check_each(int drv, struct device_api *api, struct libusb_device *dev)
+{
+	struct usb_find_devices *found;
+	int i;
+
+	for (i = 0; find_dev[i].drv != DRV_LAST; i++)
+		if (find_dev[i].drv == drv) {
+			if (usb_check_device(api, dev, &(find_dev[i]))) {
+				found = malloc(sizeof(*found));
+				memcpy(found, &(find_dev[i]), sizeof(*found));
+				return found;
+			}
+		}
+
+	return NULL;
+}
+
+static struct usb_find_devices *usb_check(__maybe_unused struct device_api *api, __maybe_unused struct libusb_device *dev)
+{
+#ifdef USE_BITFORCE
+	if (api == &bitforce_api)
+		return usb_check_each(DRV_BITFORCE, api, dev);
+#endif
+
+#ifdef USE_ICARUS
+	if (api == &icarus_api)
+		return usb_check_each(DRV_ICARUS, api, dev);
+#endif
+
+#ifdef USE_MODMINER
+	if (api == &modminer_api)
+		return usb_check_each(DRV_MODMINER, api, dev);
+#endif
+
+	return NULL;
+}
+
+void usb_detect(struct device_api *api, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *))
+{
+	libusb_device **list;
+	ssize_t count, i;
+	struct usb_find_devices *found;
+
+	cgusb_check_init();
+
+	count = libusb_get_device_list(NULL, &list);
+	if (count < 0) {
+		applog(LOG_DEBUG, "USB scan devices: failed, err %d", count);
+		return;
+	}
+
+	if (count == 0)
+		applog(LOG_DEBUG, "USB scan devices: found no devices");
+
+	for (i = 0; i < count; i++) {
+		mutex_lock(list_lock);
+
+		if (in_use(list[i], false))
+			mutex_unlock(list_lock);
+		else {
+			add_used(list[i], false);
+
+			mutex_unlock(list_lock);
+
+			found = usb_check(api, list[i]);
+			if (!found)
+				release_dev(list[i], true);
+			else
+				if (!device_detect(list[i], found))
+					release_dev(list[i], true);
+		}
+	}
+
+	libusb_free_device_list(list, 1);
+}
+
+// Set this to 0 to remove stats processing
+#define DO_USB_STATS 1
+
+#if DO_USB_STATS
+#define USB_STATS(sgpu, sta, fin, err, cmd, seq) stats(cgpu, sta, fin, err, cmd, seq)
+#define STATS_TIMEVAL(tv) gettimeofday(tv, NULL)
+#else
+#define USB_STATS(sgpu, sta, fin, err, cmd, seq)
+#define STATS_TIMEVAL(tv)
+#endif
+
+// The stat data can be spurious due to not locking it before copying it -
+// however that would require the stat() function to also lock and release
+// a mutex every time a usb read or write is called which would slow
+// things down more
+struct api_data *api_usb_stats(__maybe_unused int *count)
+{
+#if DO_USB_STATS
+	struct cg_usb_stats_details *details;
+	struct cg_usb_stats *sta;
+	struct api_data *root = NULL;
+	int device;
+	int cmdseq;
+
+	cgusb_check_init();
+
+	if (next_stat == 0)
+		return NULL;
+
+	while (*count < next_stat * C_MAX * 2) {
+		device = *count / (C_MAX * 2);
+		cmdseq = *count % (C_MAX * 2);
+
+		(*count)++;
+
+		sta = &(usb_stats[device]);
+		details = &(sta->details[cmdseq]);
+
+		// Only show stats that have results
+		if (details->item[CMD_CMD].count == 0 &&
+		    details->item[CMD_TIMEOUT].count == 0 &&
+		    details->item[CMD_ERROR].count == 0)
+			continue;
+
+		root = api_add_string(root, "Name", sta->name, false);
+		root = api_add_int(root, "ID", &(sta->device_id), false);
+		root = api_add_const(root, "Stat", usb_commands[cmdseq/2], false);
+		root = api_add_int(root, "Seq", &(details->seq), true);
+		root = api_add_uint64(root, "Count",
+					&(details->item[CMD_CMD].count), true);
+		root = api_add_double(root, "Total Delay",
+					&(details->item[CMD_CMD].total_delay), true);
+		root = api_add_double(root, "Min Delay",
+					&(details->item[CMD_CMD].min_delay), true);
+		root = api_add_double(root, "Max Delay",
+					&(details->item[CMD_CMD].max_delay), true);
+		root = api_add_uint64(root, "Timeout Count",
+					&(details->item[CMD_TIMEOUT].count), true);
+		root = api_add_double(root, "Timeout Total Delay",
+					&(details->item[CMD_TIMEOUT].total_delay), true);
+		root = api_add_double(root, "Timeout Min Delay",
+					&(details->item[CMD_TIMEOUT].min_delay), true);
+		root = api_add_double(root, "Timeout Max Delay",
+					&(details->item[CMD_TIMEOUT].max_delay), true);
+		root = api_add_uint64(root, "Error Count",
+					&(details->item[CMD_ERROR].count), true);
+		root = api_add_double(root, "Error Total Delay",
+					&(details->item[CMD_ERROR].total_delay), true);
+		root = api_add_double(root, "Error Min Delay",
+					&(details->item[CMD_ERROR].min_delay), true);
+		root = api_add_double(root, "Error Max Delay",
+					&(details->item[CMD_ERROR].max_delay), true);
+		root = api_add_timeval(root, "First Command",
+					&(details->item[CMD_CMD].first), true);
+		root = api_add_timeval(root, "Last Command",
+					&(details->item[CMD_CMD].last), true);
+		root = api_add_timeval(root, "First Timeout",
+					&(details->item[CMD_TIMEOUT].first), true);
+		root = api_add_timeval(root, "Last Timeout",
+					&(details->item[CMD_TIMEOUT].last), true);
+		root = api_add_timeval(root, "First Error",
+					&(details->item[CMD_ERROR].first), true);
+		root = api_add_timeval(root, "Last Error",
+					&(details->item[CMD_ERROR].last), true);
+
+		return root;
+	}
+#endif
+	return NULL;
+}
+
+#if DO_USB_STATS
+static void newstats(struct cgpu_info *cgpu)
+{
+	int i;
+
+	cgpu->usbstat = ++next_stat;
+
+	usb_stats = realloc(usb_stats, sizeof(*usb_stats) * next_stat);
+	usb_stats[next_stat-1].name = cgpu->api->name;
+	usb_stats[next_stat-1].device_id = -1;
+	usb_stats[next_stat-1].details = calloc(1, sizeof(struct cg_usb_stats_details) * C_MAX * 2);
+	for (i = 1; i < C_MAX * 2; i += 2)
+		usb_stats[next_stat-1].details[i].seq = 1;
+}
+#endif
+
+void update_usb_stats(__maybe_unused struct cgpu_info *cgpu)
+{
+#if DO_USB_STATS
+	// we don't know the device_id until after add_cgpu()
+	usb_stats[cgpu->usbstat - 1].device_id = cgpu->device_id;
+#endif
+}
+
+#if DO_USB_STATS
+static void stats(struct cgpu_info *cgpu, struct timeval *tv_start, struct timeval *tv_finish, int err, enum usb_cmds cmd, int seq)
+{
+	struct cg_usb_stats_details *details;
+	double diff;
+	int item;
+
+	if (cgpu->usbstat < 1)
+		newstats(cgpu);
+
+	details = &(usb_stats[cgpu->usbstat - 1].details[cmd * 2 + seq]);
+
+	diff = tdiff(tv_finish, tv_start);
+
+	switch (err) {
+		case LIBUSB_SUCCESS:
+			item = CMD_CMD;
+			break;
+		case LIBUSB_ERROR_TIMEOUT:
+			item = CMD_TIMEOUT;
+			break;
+		default:
+			item = CMD_ERROR;
+			break;
+	}
+
+	if (details->item[item].count == 0) {
+		details->item[item].min_delay = diff;
+		memcpy(&(details->item[item].first), tv_start, sizeof(*tv_start));
+	} else if (diff < details->item[item].min_delay)
+		details->item[item].min_delay = diff;
+
+	if (diff > details->item[item].max_delay)
+		details->item[item].max_delay = diff;
+
+	details->item[item].total_delay += diff;
+	memcpy(&(details->item[item].last), tv_start, sizeof(tv_start));
+	details->item[item].count++;
+}
+#endif
+
+int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, int eol, enum usb_cmds cmd)
+{
+	struct cg_usb_device *usbdev = cgpu->usbdev;
+#if DO_USB_STATS
+	struct timeval tv_start, tv_finish;
+#endif
+	int err, got, tot;
+	bool first = true;
+
+	if (eol == -1) {
+		got = 0;
+		STATS_TIMEVAL(&tv_start);
+		err = libusb_bulk_transfer(usbdev->handle,
+				usbdev->found->eps[ep].ep,
+				(unsigned char *)buf,
+				bufsiz, &got,
+				timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout);
+		STATS_TIMEVAL(&tv_finish);
+		USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, SEQ0);
+
+		*processed = got;
+
+		return err;
+	}
+
+	tot = 0;
+	while (bufsiz) {
+		got = 0;
+		STATS_TIMEVAL(&tv_start);
+		err = libusb_bulk_transfer(usbdev->handle,
+				usbdev->found->eps[ep].ep,
+				(unsigned char *)buf,
+				1, &got,
+				timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout);
+		STATS_TIMEVAL(&tv_finish);
+		USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, first ? SEQ0 : SEQ1);
+
+		tot += got;
+
+		if (err)
+			break;
+
+		if (eol == buf[0])
+			break;
+
+		buf += got;
+		bufsiz -= got;
+
+		first = false;
+	}
+
+	*processed = tot;
+
+	return err;
+}
+
+int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds cmd)
+{
+	struct cg_usb_device *usbdev = cgpu->usbdev;
+#if DO_USB_STATS
+	struct timeval tv_start, tv_finish;
+#endif
+	int err, sent;
+
+	sent = 0;
+	STATS_TIMEVAL(&tv_start);
+	err = libusb_bulk_transfer(usbdev->handle,
+			usbdev->found->eps[ep].ep,
+			(unsigned char *)buf,
+			bufsiz, &sent,
+			timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout);
+	STATS_TIMEVAL(&tv_finish);
+	USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, SEQ0);
+
+	*processed = sent;
+
+	return err;
+}
+
+void usb_cleanup()
+{
+	// TODO:
+}

+ 120 - 0
usbutils.h

@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012 Andrew Smith
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#ifndef USBUTILS_H
+#define USBUTILS_H
+
+#include <libusb.h>
+
+// Use the device defined timeout
+#define DEVTIMEOUT 0
+
+// For endpoints defined in usb_find_devices.eps,
+// the first two must be the default IN and OUT
+#define DEFAULT_EP_IN 0
+#define DEFAULT_EP_OUT 1
+
+struct usb_endpoints {
+	uint8_t att;
+	uint16_t size;
+	unsigned char ep;
+	bool found;
+};
+
+struct usb_find_devices {
+	int drv;
+	const char *name;
+	uint16_t idVendor;
+	uint16_t idProduct;
+	int config;
+	int interface;
+	unsigned int timeout;
+	int epcount;
+	struct usb_endpoints *eps;
+};
+
+struct cg_usb_device {
+	struct usb_find_devices *found;
+	libusb_device_handle *handle;
+	pthread_mutex_t *mutex;
+	struct libusb_device_descriptor *descriptor;
+	uint8_t bus_number;
+	uint8_t device_address;
+	uint16_t usbver;
+	int speed;
+	char *prod_string;
+	char *manuf_string;
+	char *serial_string;
+	unsigned char fwVersion;	// ??
+	unsigned char interfaceVersion;	// ??
+};
+
+enum usb_cmds {
+	C_PING = 0,
+	C_CLEAR,
+	C_REQUESTVERSION,
+	C_GETVERSION,
+	C_REQUESTFPGACOUNT,
+	C_GETFPGACOUNT,
+	C_STARTPROGRAM,
+	C_STARTPROGRAMSTATUS,
+	C_PROGRAM,
+	C_PROGRAMSTATUS,
+	C_PROGRAMSTATUS2,
+	C_FINALPROGRAMSTATUS,
+	C_SETCLOCK,
+	C_REPLYSETCLOCK,
+	C_REQUESTUSERCODE,
+	C_GETUSERCODE,
+	C_REQUESTTEMPERATURE,
+	C_GETTEMPERATURE,
+	C_SENDWORK,
+	C_SENDWORKSTATUS,
+	C_REQUESTWORKSTATUS,
+	C_GETWORKSTATUS,
+	C_MAX
+};
+
+struct device_api;
+struct cgpu_info;
+
+void usb_uninit(struct cgpu_info *cgpu);
+bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found);
+void usb_detect(struct device_api *api, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *));
+struct api_data *api_usb_stats(int *count);
+void update_usb_stats(struct cgpu_info *cgpu);
+int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, int eol, enum usb_cmds);
+int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds);
+void usb_cleanup();
+
+#define usb_read(cgpu, buf, bufsiz, read, cmd) \
+	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, -1, cmd)
+
+#define usb_read_ep(cgpu, ep, buf, bufsiz, read, cmd) \
+	_usb_read(cgpu, ep, buf, bufsiz, read, DEVTIMEOUT, -1, cmd)
+
+#define usb_read_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
+	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, -1, cmd)
+
+#define usb_read_ep_timeout(cgpu, ep, buf, bufsiz, read, timeout, cmd) \
+	_usb_read(cgpu, ep, buf, bufsiz, read, timeout, -1, cmd)
+
+#define usb_write(cgpu, buf, bufsiz, wrote, cmd) \
+	_usb_write(cgpu, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
+
+#define usb_write_ep(cgpu, ep, buf, bufsiz, wrote, cmd) \
+	_usb_write(cgpu, ep, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
+
+#define usb_write_timeout(cgpu, buf, bufsiz, wrote, timeout, cmd) \
+	_usb_write(cgpu, DEFAULT_EP_OUT, buf, bufsiz, wrote, timeout, cmd)
+
+#define usb_write_ep_timeout(cgpu, ep, buf, bufsiz, wrote, timeout, cmd) \
+	_usb_write(cgpu, ep, buf, bufsiz, wrote, timeout, cmd)
+
+#endif

+ 55 - 27
util.c

@@ -789,20 +789,6 @@ double us_tdiff(struct timeval *end, struct timeval *start)
 	return end->tv_sec * 1000000 + end->tv_usec - start->tv_sec * 1000000 - start->tv_usec;
 	return end->tv_sec * 1000000 + end->tv_usec - start->tv_sec * 1000000 - start->tv_usec;
 }
 }
 
 
-void rename_thr(const char* name) {
-#if defined(PR_SET_NAME)
-	// Only the first 15 characters are used (16 - NUL terminator)
-	prctl(PR_SET_NAME, name, 0, 0, 0);
-#elif defined(__APPLE__)
-	pthread_setname_np(name);
-#elif defined(__FreeBSD__) || defined(__OpenBSD__)
-	pthread_set_name_np(pthread_self(), name);
-#else
-	// Prevent warnings for unused parameters...
-	(void)name;
-#endif
-}
-
 /* Returns the seconds difference between end and start times as a double */
 /* Returns the seconds difference between end and start times as a double */
 double tdiff(struct timeval *end, struct timeval *start)
 double tdiff(struct timeval *end, struct timeval *start)
 {
 {
@@ -1420,45 +1406,87 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
+void suspend_stratum(struct pool *pool)
+{
+	applog(LOG_INFO, "Closing socket for stratum pool %d", pool->pool_no);
+	mutex_lock(&pool->stratum_lock);
+	pool->stratum_active = false;
+	mutex_unlock(&pool->stratum_lock);
+	CLOSESOCKET(pool->sock);
+}
 
 
 void dev_error(struct cgpu_info *dev, enum dev_reason reason)
 void dev_error(struct cgpu_info *dev, enum dev_reason reason)
 {
 {
 	dev->device_last_not_well = time(NULL);
 	dev->device_last_not_well = time(NULL);
 	dev->device_not_well_reason = reason;
 	dev->device_not_well_reason = reason;
 
 
-
-	switch (reason)
-	{
+	switch (reason) {
 		case REASON_THREAD_FAIL_INIT:
 		case REASON_THREAD_FAIL_INIT:
 			dev->thread_fail_init_count++;
 			dev->thread_fail_init_count++;
-		break;
+			break;
 		case REASON_THREAD_ZERO_HASH:
 		case REASON_THREAD_ZERO_HASH:
 			dev->thread_zero_hash_count++;
 			dev->thread_zero_hash_count++;
-		break;
+			break;
 		case REASON_THREAD_FAIL_QUEUE:
 		case REASON_THREAD_FAIL_QUEUE:
 			dev->thread_fail_queue_count++;
 			dev->thread_fail_queue_count++;
-		break;
+			break;
 		case REASON_DEV_SICK_IDLE_60:
 		case REASON_DEV_SICK_IDLE_60:
 			dev->dev_sick_idle_60_count++;
 			dev->dev_sick_idle_60_count++;
-		break;
+			break;
 		case REASON_DEV_DEAD_IDLE_600:
 		case REASON_DEV_DEAD_IDLE_600:
 			dev->dev_dead_idle_600_count++;
 			dev->dev_dead_idle_600_count++;
-		break;
+			break;
 		case REASON_DEV_NOSTART:
 		case REASON_DEV_NOSTART:
 			dev->dev_nostart_count++;
 			dev->dev_nostart_count++;
-		break;
+			break;
 		case REASON_DEV_OVER_HEAT:
 		case REASON_DEV_OVER_HEAT:
 			dev->dev_over_heat_count++;
 			dev->dev_over_heat_count++;
-		break;
+			break;
 		case REASON_DEV_THERMAL_CUTOFF:
 		case REASON_DEV_THERMAL_CUTOFF:
 			dev->dev_thermal_cutoff_count++;
 			dev->dev_thermal_cutoff_count++;
-		break;
+			break;
 		case REASON_DEV_COMMS_ERROR:
 		case REASON_DEV_COMMS_ERROR:
 			dev->dev_comms_error_count++;
 			dev->dev_comms_error_count++;
-		break;
+			break;
 		case REASON_DEV_THROTTLE:
 		case REASON_DEV_THROTTLE:
 			dev->dev_throttle_count++;
 			dev->dev_throttle_count++;
-		break;
+			break;
 	}
 	}
+}
+
+/* Realloc an existing string to fit an extra string s, appending s to it. */
+void *realloc_strcat(char *ptr, char *s)
+{
+	size_t old = strlen(ptr), len = strlen(s);
+	char *ret;
+
+	if (!len)
+		return ptr;
+
+	len += old + 1;
+	if (len % 4)
+		len += 4 - (len % 4);
+
+	ret = malloc(len);
+	if (unlikely(!ret))
+		quit(1, "Failed to malloc in realloc_strcat");
+
+	sprintf(ret, "%s%s", ptr, s);
+	free(ptr);
+	return ret;
+}
 
 
+void RenameThread(const char* name)
+{
+#if defined(PR_SET_NAME)
+	// Only the first 15 characters are used (16 - NUL terminator)
+	prctl(PR_SET_NAME, name, 0, 0, 0);
+#elif defined(__APPLE__)
+	pthread_setname_np(name);
+#elif (defined(__FreeBSD__) || defined(__OpenBSD__))
+	pthread_set_name_np(pthread_self(), name);
+#else
+	// Prevent warnings for unused parameters...
+	(void)name;
+#endif
 }
 }

+ 3 - 0
util.h

@@ -51,6 +51,9 @@ bool parse_method(struct pool *pool, char *s);
 bool extract_sockaddr(struct pool *pool, char *url);
 bool extract_sockaddr(struct pool *pool, char *url);
 bool auth_stratum(struct pool *pool);
 bool auth_stratum(struct pool *pool);
 bool initiate_stratum(struct pool *pool);
 bool initiate_stratum(struct pool *pool);
+void suspend_stratum(struct pool *pool);
 void dev_error(struct cgpu_info *dev, enum dev_reason reason);
 void dev_error(struct cgpu_info *dev, enum dev_reason reason);
+void *realloc_strcat(char *ptr, char *s);
+void RenameThread(const char* name);
 
 
 #endif /* __UTIL_H__ */
 #endif /* __UTIL_H__ */

+ 34 - 2
windows-build.txt

@@ -18,7 +18,7 @@ If you think that this documentation was helpful and you wish to donate, you can
 do so at the following address. 12KaKtrK52iQjPdtsJq7fJ7smC32tXWbWr
 do so at the following address. 12KaKtrK52iQjPdtsJq7fJ7smC32tXWbWr
 
 
 **************************************************************************************
 **************************************************************************************
-* A tip that might help you along the way                                             *
+* A tip that might help you along the way                                            *
 **************************************************************************************
 **************************************************************************************
 Enable "QuickEdit Mode" in your Command Prompt Window or MinGW Command Prompt
 Enable "QuickEdit Mode" in your Command Prompt Window or MinGW Command Prompt
 Window (No need to go into the context menu to choose edit-mark/copy/paste):
 Window (No need to go into the context menu to choose edit-mark/copy/paste):
@@ -137,6 +137,7 @@ to the next.
       autoreconf -fvi
       autoreconf -fvi
       CFLAGS="-O2 -msse2" ./configure (additional config options, see below)
       CFLAGS="-O2 -msse2" ./configure (additional config options, see below)
       make
       make
+      strip bfgminer.exe  <== only do this if you are not compiling for debugging
 
 
 **************************************************************************************
 **************************************************************************************
 * Copy files to a build directory/folder                                             *
 * Copy files to a build directory/folder                                             *
@@ -177,10 +178,41 @@ Now you can get the latest source directly from github.
 * Optional - Install libusb if you need auto USB device detection                    *
 * Optional - Install libusb if you need auto USB device detection                    *
 * Required for Ztex and X6500                                                        *
 * Required for Ztex and X6500                                                        *
 **************************************************************************************
 **************************************************************************************
+Go to this url ==> http://git.libusb.org/?p=libusb.git;a=snapshot;h=master;sf=zip
+save the file to your local storage. Open the file and copy the libusb* folder to
+\MinGW\msys\1.0\home\(your user directory/folder).
+Or if you do not want to download the file directly and would like to use git then
+Type the following from the MSYS shell in your home folder.
+git clone git://git.libusb.org/libusb.git
+
+Run the MinGW MSYS shell
+(Start Icon/keyboard key ==> All Programs ==> MinGW ==> MinGW Shell).
+Change the working directory to your libusb project folder.
+Example: cd libusb-something [Enter Key] if you are unsure then type "ls -la"
+Another way is to type "cd libusb" and then press the tab key; It will auto fill.
+Type the lines below one at a time. Look for problems after each one before going on
+to the next.
+
+./autogen.sh --disable-debug-log
+./configure --prefix=/MinGW
+make
+make install
+
+You may now exit the MSYS shell.
+Ctrl-D or typing "logout" and pressing the enter key should get you out of the
+window.
+
+You will have to copy "libusb-1.0.dll" to your working BFGMiner binary directory.
+You will find "libusb-1.0.dll" in the \MinGW\bin directory/folder.
+
+Use this method if libusb does not work for you on Ztex. Once someone lets us know
+Libusb works instead of libusbx then we will remove the section below this line.
+Run the MSYS shell and change into the libusb folder as above.
+Type ==> make uninstall
 Go to this url ==> http://libusbx.org/
 Go to this url ==> http://libusbx.org/
 Click on the "Downloads" tab.
 Click on the "Downloads" tab.
 Click on "releases".
 Click on "releases".
-Click on the latest version. I downloaded 1.0.12; yours may be newer.
+Click on the latest version. I downloaded 1.0.14; yours may be newer.
 Do not download from the link that says "Looking for the latest version?".
 Do not download from the link that says "Looking for the latest version?".
 Click on "Windows"
 Click on "Windows"
 Click on the file and download it. I downloaded libusbx-1.0.12-win.7z.
 Click on the file and download it. I downloaded libusbx-1.0.12-win.7z.