Browse Source

Merge branch 'bitfury' into bfgminer

Conflicts:
	configure.ac
	driver-getwork.c
Luke Dashjr 12 years ago
parent
commit
7ecedafd9f
27 changed files with 3576 additions and 37 deletions
  1. 20 0
      Makefile.am
  2. 6 0
      README
  3. 33 1
      README.ASIC
  4. 4 1
      api.c
  5. 112 7
      configure.ac
  6. 44 0
      deviceapi.c
  7. 2 0
      deviceapi.h
  8. 213 0
      driver-bfsb.c
  9. 312 0
      driver-bigpic.c
  10. 44 0
      driver-bigpic.h
  11. 751 0
      driver-bitfury.c
  12. 24 0
      driver-bitfury.h
  13. 1 0
      driver-cpu.c
  14. 1 8
      driver-getwork.c
  15. 444 0
      driver-littlefury.c
  16. 244 0
      driver-metabank.c
  17. 615 0
      libbitfury.c
  18. 76 0
      libbitfury.h
  19. 13 0
      logging.h
  20. 74 19
      miner.c
  21. 10 0
      miner.h
  22. 1 0
      ocl.c
  23. 293 0
      spidevc.c
  24. 77 0
      spidevc.h
  25. 112 0
      tm_i2c.c
  26. 43 0
      tm_i2c.h
  27. 7 1
      util.h

+ 20 - 0
Makefile.am

@@ -199,6 +199,10 @@ bitforce_firmware_flash_SOURCES = bitforce-firmware-flash.c
 endif
 endif
 
+if HAS_BIGPIC
+bfgminer_SOURCES += driver-bigpic.c driver-bigpic.h
+endif
+
 if HAS_ICARUS
 bfgminer_SOURCES += driver-icarus.c icarus-common.h
 bfgminer_SOURCES += driver-cairnsmore.c
@@ -221,6 +225,22 @@ if HAS_ZTEX
 bfgminer_SOURCES += driver-ztex.c libztex.c libztex.h
 endif
 
+if HAS_BITFURY
+bfgminer_SOURCES += driver-bitfury.c driver-bitfury.h libbitfury.c libbitfury.h spidevc.h spidevc.c
+
+if HAS_BFSB
+bfgminer_SOURCES += driver-bfsb.c
+endif
+
+if HAS_METABANK
+bfgminer_SOURCES += driver-metabank.c tm_i2c.h tm_i2c.c
+endif
+
+if HAS_LITTLEFURY
+bfgminer_SOURCES += driver-littlefury.c
+endif
+endif
+
 bin_PROGRAMS += bfgminer-rpc
 bfgminer_rpc_SOURCES = api-example.c
 bfgminer_rpc_LDADD = @WS2_LIBS@

+ 6 - 0
README

@@ -127,6 +127,12 @@ BFGMiner specific configuration options:
 	--enable-cpumining      Build with cpu mining support(default disabled)
 	--disable-opencl        Build without support for OpenCL (default enabled)
 	--disable-adl           Build without ADL monitoring (default enabled)
+	--disable-bitfury       Compile support for Bitfury (default enabled)
+	--enable-bfsb           Compile support for BFSB (default disabled)
+	--disable-bigpic        Compile support for Big Picture Mining USB (default
+	                        enabled)
+	--disable-littlefury    Compile support for LittleFury (default enabled)
+	--enable-metabank       Compile support for Metabank (default disabled)
 	--disable-bitforce      Compile support for BitForce (default enabled)
 	--disable-icarus        Compile support for Icarus (default enabled)
 	--disable-modminer      Compile support for ModMiner (default enabled)

+ 33 - 1
README.ASIC

@@ -1,7 +1,8 @@
 SUPPORTED DEVICES
 
 Currently supported ASIC devices include Avalon, Bitfountain's Block Erupter
-series (both USB and blades), and Butterfly Labs' SC range of devices.
+series (both USB and blades), a large variety of Bitfury-based miners, and
+Butterfly Labs' SC range of devices.
 
 
 AVALON
@@ -65,6 +66,37 @@ ambient temp / highest device temp  set fan % / lowest detected fan RPM.
 Use the API for more detailed information than this.
 
 
+BFSB, MEGABIGPOWER, AND METABANK BITFURY BOARDS
+-----------------------------------------------
+
+Both BFSB and MegaBigPower (V2 only at this time) boards are supported with the
+"bfsb" driver. Metabank boards are supported with the "metabank" driver. These
+drivers are not enabled by default, since they must be run on a Raspberry Pi in
+a specific hardware configuration with the boards. To enable them, you must
+build with --enable-bfsb or --enable-metabank. Do not try to use these drivers
+without the manufacturer-supported hardware configuration! Also note that these
+drivers do not properly support thermal shutdown at this time, and without
+sufficient cooling you may destroy your board or chips!
+
+To start BFGMiner, ensure your Raspberry Pi's SPI is enabled (you can run the
+raspi-config utility for this). For Metabank boards, you must also load the I2C
+drivers (do not try to modprobe both with a single command; it won't work):
+    modprobe i2c-bcm2708
+    modprobe i2c-dev
+Then you must run BFGMiner as root, with the proper driver selected.
+For example:
+    sudo bfgminer -S bfsb:auto
+
+
+BIG PICTURE MINING BITFURY USB
+------------------------------
+
+These miners are sensitive to unexpected data. Usually you can re-plug them to
+reset to a known-good initialisation state. To ensure they are properly detected
+and used with BFGMiner, you must specify -S bigpic:all (or equivalent) options
+prior to any other -S options (which might probe the device and confuse it).
+
+
 BLOCK ERUPTER BLADE
 -------------------
 

+ 4 - 1
api.c

@@ -33,7 +33,7 @@
 #include "util.h"
 #include "driver-cpu.h" /* for algo_names[], TODO: re-factor dependency */
 
-#if defined(USE_AVALON) || defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_MODMINER) || defined(USE_X6500) || defined(USE_ZTEX)
+#if defined(USE_AVALON) || defined(USE_BIGPIC) || defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_MODMINER) || defined(USE_X6500) || defined(USE_ZTEX)
 #define HAVE_AN_FPGA 1
 #endif
 
@@ -95,6 +95,9 @@ static const char *DEVICECODE = ""
 #ifdef USE_BITFORCE
 			"BFL "
 #endif
+#ifdef USE_BIGPIC
+			"BPM "
+#endif
 #ifdef USE_ICARUS
 			"ICA "
 #endif

+ 112 - 7
configure.ac

@@ -73,6 +73,7 @@ AC_CHECK_HEADERS(syslog.h)
 AC_CHECK_HEADERS([sys/epoll.h])
 AC_CHECK_HEADERS([sys/prctl.h])
 AC_CHECK_HEADERS([sys/file.h])
+AC_CHECK_HEADERS([linux/spi/spidev.h])
 
 AC_CHECK_HEADERS([sys/file.h])
 
@@ -84,6 +85,8 @@ AC_CHECK_FUNCS([chroot])
 
 AC_FUNC_ALLOCA
 
+need_dynclock=no
+need_fpgautils=no
 have_cygwin=false
 have_win32=false
 have_macho=false
@@ -314,6 +317,7 @@ AC_ARG_ENABLE([bitforce],
 	)
 if test "x$bitforce" = xyes; then
 	AC_DEFINE([USE_BITFORCE], [1], [Defined to 1 if BitForce support is wanted])
+	need_fpgautils=yes
 fi
 AM_CONDITIONAL([HAS_BITFORCE], [test x$bitforce = xyes])
 
@@ -324,6 +328,8 @@ AC_ARG_ENABLE([icarus],
 	)
 if test "x$icarus" = xyes; then
 	AC_DEFINE([USE_ICARUS], [1], [Defined to 1 if Icarus support is wanted])
+	need_dynclock=yes
+	need_fpgautils=yes
 fi
 AM_CONDITIONAL([HAS_ICARUS], [test x$icarus = xyes])
 
@@ -336,6 +342,7 @@ AC_ARG_ENABLE([avalon],
 	)
 if test "x$avalon" = xyes; then
 	AC_DEFINE([USE_AVALON], [1], [Defined to 1 if Avalon support is wanted])
+	need_fpgautils=yes
 fi
 AM_CONDITIONAL([HAS_AVALON], [test x$avalon = xyes])
 
@@ -386,6 +393,8 @@ AC_ARG_ENABLE([modminer],
 	)
 if test "x$modminer" = xyes; then
 	AC_DEFINE([USE_MODMINER], [1], [Defined to 1 if ModMiner support is wanted])
+	need_dynclock=yes
+	need_fpgautils=yes
 fi
 AM_CONDITIONAL([HAS_MODMINER], [test x$modminer = xyes])
 
@@ -436,6 +445,8 @@ elif test "x$x6500" = xauto; then
 fi
 if test "x$x6500" = xyes; then
 	AC_DEFINE([USE_X6500], [1], [Defined to 1 if X6500 support is wanted])
+	need_dynclock=yes
+	need_fpgautils=yes
 fi
 AM_CONDITIONAL([HAS_X6500], [test x$x6500 = xyes])
 
@@ -455,10 +466,93 @@ elif test "x$ztex" = xauto; then
 fi
 if test "x$ztex" = xyes; then
 	AC_DEFINE([USE_ZTEX], [1], [Defined to 1 if ZTEX support is wanted])
+	need_dynclock=yes
+	need_fpgautils=yes
 fi
 AM_CONDITIONAL([HAS_ZTEX], [test x$ztex = xyes])
 
 
+bitfury=yes
+AC_ARG_ENABLE([bitfury],
+	[AC_HELP_STRING([--disable-bitfury],[Compile support for Bitfury (default enabled)])],
+	[bitfury=$enableval]
+	)
+if test "x$bitfury" = xyes; then
+	AC_DEFINE([USE_BITFURY], [1], [Defined to 1 if Bitfury support is wanted])
+fi
+AM_CONDITIONAL([HAS_BITFURY], [test x$bitfury = xyes])
+
+
+bfsb=no
+AC_ARG_ENABLE([bfsb],
+	[AC_HELP_STRING([--enable-bfsb],[Compile support for BFSB (default disabled)])],
+	[bfsb=$enableval]
+	)
+if test "x$bfsb" = "xyes"; then
+	if test "x$bitfury" = "xno"; then
+		AC_MSG_ERROR([You explicitly disabled Bitfury and explicitly enabled BFSB])
+	fi
+	AC_DEFINE([USE_BFSB], [1], [Defined to 1 if BFSB support is wanted])
+fi
+AM_CONDITIONAL([HAS_BFSB], [test x$bfsb = xyes])
+
+
+bigpic=auto
+AC_ARG_ENABLE([bigpic],
+	[AC_HELP_STRING([--disable-bigpic],[Compile support for Big Picture Mining USB (default enabled)])],
+	[bigpic=$enableval]
+	)
+if test "x$bigpic" = "xno"; then
+	true
+elif test "x$bitfury" = "xyes"; then
+	bigpic=yes
+elif test "x$bigpic" = "xyes"; then
+	AC_MSG_ERROR([You explicitly disabled Bitfury and explicitly enabled BigPic])
+else
+	bigpic=no
+fi
+if test "x$bigpic" = "xyes"; then
+	AC_DEFINE([USE_BIGPIC], [1], [Defined to 1 if Big Picture Mining USB support is wanted])
+	need_fpgautils=yes
+fi
+AM_CONDITIONAL([HAS_BIGPIC], [test x$bigpic = xyes])
+
+
+littlefury=auto
+AC_ARG_ENABLE([littlefury],
+	[AC_HELP_STRING([--disable-littlefury],[Compile support for LittleFury (default enabled)])],
+	[littlefury=$enableval]
+	)
+if test "x$littlefury" = "xno"; then
+	true
+elif test "x$bitfury" = "xyes"; then
+	littlefury=yes
+elif test "x$littlefury" = "xyes"; then
+	AC_MSG_ERROR([You explicitly disabled Bitfury and explicitly enabled LittleFury])
+else
+	littlefury=no
+fi
+if test "x$littlefury" = "xyes"; then
+	AC_DEFINE([USE_LITTLEFURY], [1], [Defined to 1 if LittleFury support is wanted])
+	need_fpgautils=yes
+fi
+AM_CONDITIONAL([HAS_LITTLEFURY], [test x$littlefury = xyes])
+
+
+metabank=no
+AC_ARG_ENABLE([metabank],
+	[AC_HELP_STRING([--enable-metabank],[Compile support for Metabank (default disabled)])],
+	[metabank=$enableval]
+	)
+if test "x$metabank" = "xyes"; then
+	if test "x$bitfury" = "xno"; then
+		AC_MSG_ERROR([You explicitly disabled Bitfury and explicitly enabled Metabank])
+	fi
+	AC_DEFINE([USE_METABANK], [1], [Defined to 1 if Metabank support is wanted])
+fi
+AM_CONDITIONAL([HAS_METABANK], [test x$metabank = xyes])
+
+
 if test "x$x6500$ztex" = "xnono"; then
 	libusb=no
 	LIBUSB_LIBS=''
@@ -484,9 +578,7 @@ if test "x$scrypt" = xyes; then
 fi
 
 
-need_fpgautils=no
-if test x$avalon$icarus$bitforce$modminer$x6500$ztex != xnononononono; then
-	need_fpgautils=yes
+if test x$need_fpgautils = xyes; then
 	AC_DEFINE([HAVE_FPGAUTILS], [1], [Defined to 1 if fpgautils is being used])
 	
 	if $have_win32; then
@@ -643,7 +735,7 @@ AC_SUBST(libblkmaker_LIBS)
 
 
 AM_CONDITIONAL([NEED_LIBBLKMAKER], [test x$with_system_libblkmaker != xyes])
-AM_CONDITIONAL([NEED_DYNCLOCK], [test x$icarus$modminer$x6500$ztex != xnonono])
+AM_CONDITIONAL([NEED_DYNCLOCK], [test x$need_dynclock = xyes])
 AM_CONDITIONAL([NEED_FPGAUTILS], [test x$need_fpgautils = xyes])
 AM_CONDITIONAL([HAS_SCRYPT], [test x$scrypt = xyes])
 AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes])
@@ -652,7 +744,7 @@ AM_CONDITIONAL([HAVE_CYGWIN], [test x$have_cygwin = xtrue])
 AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue])
 AM_CONDITIONAL([HAVE_x86_64], [test x$have_x86_64 = xtrue])
 AM_CONDITIONAL([HAS_FPGA], [test x$bitforce$icarus$modminer$x6500$ztex != xnonononono])
-AM_CONDITIONAL([HAS_ASIC], [test x$avalon$icarus$httpsrv != xnonono])
+AM_CONDITIONAL([HAS_ASIC], [test x$avalon$bfsb$bigpic$icarus$httpsrv$metabank != xnononononono])
 
 dnl Find YASM
 has_yasm=false
@@ -747,7 +839,7 @@ if test "x$cpumining$have_x86_32" = "xyestrue"; then
 fi
 AM_CONDITIONAL([HAVE_SSE2], [test "x$have_sse2" = "xyes"])
 
-if test "x$bitforce$modminer$icarus" != "xnonono"; then
+if test "x$need_fpgautils" = "xyes"; then
 	AC_ARG_WITH([libudev], [AC_HELP_STRING([--without-libudev], [Autodetect FPGAs using libudev (default enabled)])],
 		[libudev=$withval],
 		[libudev=auto]
@@ -1053,6 +1145,12 @@ else
 	echo "  Avalon.ASICs.........: Disabled"
 fi
 
+if test "x$bigpic" = xyes; then
+	echo "  BPM.USB.ASICs........: Enabled"
+else
+	echo "  BPM.USB.ASICs........: Disabled"
+fi
+
 if test "x$bitforce" = xyes; then
 	echo "  BitForce.devices.....: Enabled"
 else
@@ -1093,10 +1191,16 @@ else
 	echo "  getwork.proxy.server.: Disabled"
 fi
 
-if test "x$bitforce$modminer" != xnono; then
+if test "x$need_fpgautils" = xyes; then
 	echo "  libudev.detection....: $libudev"
 fi
 
+if test "x$bitfury" = xyes; then
+	echo "  Bitfury.ASICs........: Enabled"
+else
+	echo "  Bitfury.ASICs........: Disabled"
+fi
+
 echo
 if test "x$cpumining" = xyes; then
 	echo "  CPU Mining...........: Enabled"
@@ -1105,6 +1209,7 @@ else
 	echo "  CPU Mining...........: Disabled"
 fi
 
+
 echo
 echo "Compilation............: make (or gmake)"
 echo "  CFLAGS...............: $CPPFLAGS $NCURSES_CPPFLAGS $PTHREAD_FLAGS $CFLAGS $LIBUSB_CFLAGS $JANSSON_CFLAGS $PTHREAD_FLAGS $libblkmaker_CFLAGS"

+ 44 - 0
deviceapi.c

@@ -84,6 +84,15 @@ bool hashes_done(struct thr_info *thr, int64_t hashes, struct timeval *tvp_hashe
 	return true;
 }
 
+bool hashes_done2(struct thr_info *thr, int64_t hashes, uint32_t *max_nonce)
+{
+	struct timeval tv_now, tv_delta;
+	timer_set_now(&tv_now);
+	timersub(&tv_now, &thr->_tv_last_hashes_done_call, &tv_delta);
+	thr->_tv_last_hashes_done_call = tv_now;
+	return hashes_done(thr, hashes, &tv_delta, max_nonce);
+}
+
 /* A generic wait function for threads that poll that will wait a specified
  * time tdiff waiting on a work restart request. Returns zero if the condition
  * was met (work restart requested) or ETIMEDOUT if not.
@@ -275,6 +284,7 @@ void job_results_fetched(struct thr_info *mythr)
 	if (mythr->_proceed_with_new_job)
 		do_job_start(mythr);
 	else
+	if (likely(mythr->prev_work))
 	{
 		struct timeval tv_now;
 		
@@ -316,6 +326,9 @@ void job_start_complete(struct thr_info *mythr)
 {
 	struct timeval tv_now;
 	
+	if (unlikely(!mythr->prev_work))
+		return;
+	
 	timer_set_now(&tv_now);
 	
 	do_process_results(mythr, &tv_now, mythr->prev_work, false);
@@ -405,6 +418,12 @@ void minerloop_async(struct thr_info *mythr)
 	
 	if (mythr->work_restart_notifier[1] == -1)
 		notifier_init(mythr->work_restart_notifier);
+	for (proc = cgpu; proc; proc = proc->next_proc)
+	{
+		mythr = proc->thr[0];
+		timer_set_now(&mythr->tv_watchdog);
+		proc->disable_watchdog = true;
+	}
 	
 	while (likely(!cgpu->shutdown)) {
 		tv_timeout.tv_sec = -1;
@@ -455,8 +474,15 @@ defer_events:
 			if (timer_passed(&mythr->tv_poll, &tv_now))
 				api->poll(mythr);
 			
+			if (timer_passed(&mythr->tv_watchdog, &tv_now))
+			{
+				timer_set_delay(&mythr->tv_watchdog, &tv_now, WATCHDOG_INTERVAL * 1000000);
+				bfg_watchdog(proc, &tv_now);
+			}
+			
 			reduce_timeout_to(&tv_timeout, &mythr->tv_morework);
 			reduce_timeout_to(&tv_timeout, &mythr->tv_poll);
+			reduce_timeout_to(&tv_timeout, &mythr->tv_watchdog);
 		}
 		
 		do_notifier_select(thr, &tv_timeout);
@@ -682,6 +708,24 @@ void add_cgpu_live(void *p)
 	add_cgpu(p);
 }
 
+bool add_cgpu_slave(struct cgpu_info *cgpu, struct cgpu_info *prev_cgpu)
+{
+	int old_total_devices = total_devices_new;
+	
+	if (!prev_cgpu)
+		return add_cgpu(cgpu);
+	
+	while (prev_cgpu->next_proc)
+		prev_cgpu = prev_cgpu->next_proc;
+	
+	if (!add_cgpu(cgpu))
+		return false;
+	
+	prev_cgpu->next_proc = devices_new[old_total_devices];
+	
+	return true;
+}
+
 int _serial_detect(struct device_drv *api, detectone_func_t detectone, autoscan_func_t autoscan, int flags)
 {
 	struct string_elist *iter, *tmp;

+ 2 - 0
deviceapi.h

@@ -10,6 +10,7 @@
 extern void request_work(struct thr_info *);
 extern struct work *get_work(struct thr_info *);
 extern bool hashes_done(struct thr_info *, int64_t hashes, struct timeval *tvp_hashes, uint32_t *max_nonce);
+extern bool hashes_done2(struct thr_info *, int64_t hashes, uint32_t *max_nonce);
 extern void mt_disable_start(struct thr_info *);
 extern void mt_disable_finish(struct thr_info *);
 extern void mt_disable(struct thr_info *);  // blocks until reenabled
@@ -33,6 +34,7 @@ extern void minerloop_queue(struct thr_info *);
 extern void *miner_thread(void *);
 
 extern void add_cgpu_live(void*);
+extern bool add_cgpu_slave(struct cgpu_info *, struct cgpu_info *master);
 
 typedef bool(*detectone_func_t)(const char*);
 typedef int(*autoscan_func_t)();

+ 213 - 0
driver-bfsb.c

@@ -0,0 +1,213 @@
+/*
+ * Copyright 2013 bitfury
+ * Copyright 2013 legkodymov
+ * Copyright 2013 Luke Dashjr
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "deviceapi.h"
+#include "libbitfury.h"
+#include "spidevc.h"
+#include "driver-bitfury.h"
+
+struct device_drv bfsb_drv;
+
+static
+bool bfsb_spi_txrx(struct spi_port *port)
+{
+	struct cgpu_info * const proc = port->cgpu;
+	struct bitfury_device * const bitfury = proc->device_data;
+	spi_bfsb_select_bank(bitfury->slot);
+	const bool rv = sys_spi_txrx(port);
+
+	return rv;
+}
+
+static
+int bfsb_autodetect()
+{
+	RUNONCE(0);
+	
+	struct cgpu_info *cgpu = NULL, *proc1 = NULL, *prev_cgpu = NULL;
+	int proc_count = 0;
+	
+	applog(LOG_INFO, "INFO: bitfury_detect");
+	spi_init();
+	if (!sys_spi)
+		return 0;
+	
+	
+	struct bitfury_device **devicelist, *bitfury;
+	struct spi_port *port;
+	int i, j;
+	bool slot_on[32];
+	struct timespec t1, t2;
+	struct bitfury_device dummy_bitfury;
+	struct cgpu_info dummy_cgpu;
+
+	dummy_cgpu.device_data = &dummy_bitfury;
+	
+	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t1);
+	for (i = 0; i < 4; i++) {
+		slot_on[i] = 1;
+	}
+
+	for (i = 0; i < 32; i++) {
+		if (slot_on[i]) {
+			int chip_n;
+			
+			port = malloc(sizeof(*port));
+			*port = *sys_spi;
+			port->cgpu = &dummy_cgpu;
+			port->txrx = bfsb_spi_txrx;
+			port->speed = 625000;
+			dummy_bitfury.slot = i;
+			
+			chip_n = libbitfury_detectChips1(port);
+			if (chip_n)
+			{
+				applog(LOG_WARNING, "BITFURY slot %d: %d chips detected", i, chip_n);
+				
+				devicelist = malloc(sizeof(*devicelist) * chip_n);
+				for (j = 0; j < chip_n; ++j)
+				{
+					devicelist[j] = bitfury = malloc(sizeof(*bitfury));
+					*bitfury = (struct bitfury_device){
+						.spi = port,
+						.slot = i,
+						.fasync = j,
+					};
+				}
+				
+				cgpu = malloc(sizeof(*cgpu));
+				*cgpu = (struct cgpu_info){
+					.drv = &bfsb_drv,
+					.procs = chip_n,
+					.device_data = devicelist,
+				};
+				add_cgpu_slave(cgpu, prev_cgpu);
+				
+				proc_count += chip_n;
+				if (!proc1)
+					proc1 = cgpu;
+				prev_cgpu = cgpu;
+			}
+			else
+				free(port);
+		}
+	}
+
+	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &t2);
+	
+	if (proc1)
+		proc1->threads = 1;
+	
+	return proc_count;
+}
+
+static void bfsb_detect(void)
+{
+	noserial_detect_manual(&bfsb_drv, bfsb_autodetect);
+}
+
+static
+bool bfsb_init(struct thr_info *thr)
+{
+	struct bitfury_device **devicelist;
+	struct cgpu_info *proc;
+	struct bitfury_device *bitfury;
+	
+	for (proc = thr->cgpu; proc; proc = proc->next_proc)
+	{
+		devicelist = proc->device_data;
+		bitfury = devicelist[proc->proc_id];
+		proc->device_data = bitfury;
+		bitfury->spi->cgpu = proc;
+		bitfury_init_chip(proc);
+		bitfury->osc6_bits = 54;
+		send_reinit(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
+		
+		if (proc->proc_id == proc->procs - 1)
+			free(devicelist);
+	}
+	
+	timer_set_now(&thr->tv_poll);
+	
+	return true;
+}
+
+static
+void bfsb_disable(struct thr_info * const thr)
+{
+	struct cgpu_info * const proc = thr->cgpu;
+	struct bitfury_device * const bitfury = proc->device_data;
+	
+	applog(LOG_DEBUG, "%"PRIpreprv": Shutting down chip (disable)", proc->proc_repr);
+	send_shutdown(bitfury->spi, bitfury->slot, bitfury->fasync);
+}
+
+static
+void bfsb_enable(struct thr_info * const thr)
+{
+	struct cgpu_info * const proc = thr->cgpu;
+	struct bitfury_device * const bitfury = proc->device_data;
+	
+	applog(LOG_DEBUG, "%"PRIpreprv": Reinitialising chip (enable)", proc->proc_repr);
+	send_reinit(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
+	bitfury_init_chip(proc);
+}
+
+extern void bitfury_shutdown(struct thr_info *);
+
+static void bfsb_shutdown(struct thr_info *thr)
+{
+	bitfury_shutdown(thr);
+	spi_bfsb_select_bank(-1);
+}
+
+static struct api_data *bfsb_api_device_detail(struct cgpu_info *cgpu)
+{
+	struct bitfury_device * const bitfury = cgpu->device_data;
+	struct api_data *root = bitfury_api_device_detail(cgpu);
+	
+	root = api_add_uint(root, "Slot", &(bitfury->slot), false);
+	
+	return root;
+}
+
+struct device_drv bfsb_drv = {
+	.dname = "bfsb",
+	.name = "BSB",
+	.drv_detect = bfsb_detect,
+	.minerloop = minerloop_async,
+	.job_prepare = bitfury_job_prepare,
+	.thread_init = bfsb_init,
+	.poll = bitfury_do_io,
+	.job_start = bitfury_noop_job_start,
+	.job_process_results = bitfury_job_process_results,
+	.get_api_extra_device_detail = bfsb_api_device_detail,
+	.get_api_extra_device_status = bitfury_api_device_status,
+	.set_device = bitfury_set_device,
+	.thread_disable = bfsb_disable,
+	.thread_enable = bfsb_enable,
+	.thread_shutdown = bfsb_shutdown,
+};

+ 312 - 0
driver-bigpic.c

@@ -0,0 +1,312 @@
+/*
+ * Copyright 2013 DI Andreas Auer
+ *
+ * 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.
+ */
+
+/*
+ * Big Picture Mining USB miner with Bitfury ASIC
+ */
+
+#include "config.h"
+#include "miner.h"
+#include "fpgautils.h"
+#include "logging.h"
+
+#include "libbitfury.h"
+#include "deviceapi.h"
+#include "sha2.h"
+
+#include "driver-bigpic.h"
+
+#include <stdio.h>
+
+struct device_drv bigpic_drv;
+
+//------------------------------------------------------------------------------
+static bool bigpic_detect_custom(const char *devpath, struct device_drv *api, struct bigpic_info *info)
+{
+	int fd = serial_open(devpath, info->baud, 1, true);
+
+	if(fd < 0)
+	{
+		return false;
+	}
+
+	char buf[sizeof(struct bigpic_identity)+1];
+	int len;
+
+	write(fd, "I", 1);
+	len = serial_read(fd, buf, sizeof(buf));
+	if(len != 14)
+	{
+		serial_close(fd);
+		return false;
+	}
+
+	info->id.version = buf[1];
+	memcpy(info->id.product, buf+2, 8);
+	memcpy(&info->id.serial, buf+10, 4);
+	applog(LOG_DEBUG, "%s: %s: %d, %s %08x",
+	       bigpic_drv.dname,
+	       devpath,
+	       info->id.version, info->id.product, info->id.serial);
+
+	char buf_state[sizeof(struct bigpic_state)+1];
+	len = 0;
+	write(fd, "R", 1);
+
+	while(len == 0)
+	{
+		len = serial_read(fd, buf, sizeof(buf_state));
+		cgsleep_ms(100);
+	}
+	serial_close(fd);
+
+	if(len != 7)
+	{
+		applog(LOG_ERR, "%s: %s not responding to reset: %d",
+		       bigpic_drv.dname,
+		       devpath, len);
+		return false;
+	}
+
+	if (serial_claim_v(devpath, api))
+		return false;
+
+	struct cgpu_info *bigpic;
+	bigpic = calloc(1, sizeof(struct cgpu_info));
+	bigpic->drv = api;
+	bigpic->device_path = strdup(devpath);
+	bigpic->device_fd = -1;
+	bigpic->threads = 1;
+	add_cgpu(bigpic);
+
+	applog(LOG_INFO, "Found %"PRIpreprv" at %s", bigpic->proc_repr, devpath);
+
+	applog(LOG_DEBUG, "%"PRIpreprv": Init: baud=%d",
+		bigpic->proc_repr, info->baud);
+
+	bigpic->device_data = info;
+
+	return true;
+}
+
+//------------------------------------------------------------------------------
+static bool bigpic_detect_one(const char *devpath)
+{
+	struct bigpic_info *info = calloc(1, sizeof(struct bigpic_info));
+	if (unlikely(!info))
+		quit(1, "Failed to malloc bigpicInfo");
+
+	info->baud = BPM_BAUD;
+
+	if (!bigpic_detect_custom(devpath, &bigpic_drv, info))
+	{
+		free(info);
+		return false;
+	}
+	return true;
+}
+
+//------------------------------------------------------------------------------
+static int bigpic_detect_auto(void)
+{
+	return serial_autodetect(bigpic_detect_one, "Bitfury_BF1");
+}
+
+//------------------------------------------------------------------------------
+static void bigpic_detect()
+{
+	serial_detect_auto(&bigpic_drv, bigpic_detect_one, bigpic_detect_auto);
+}
+
+//------------------------------------------------------------------------------
+static bool bigpic_init(struct thr_info *thr)
+{
+	struct cgpu_info *bigpic = thr->cgpu;
+	struct bigpic_info *info = (struct bigpic_info *)bigpic->device_data;
+
+	applog(LOG_DEBUG, "%"PRIpreprv": init", bigpic->proc_repr);
+
+	int fd = serial_open(bigpic->device_path, info->baud, 1, true);
+	if (unlikely(-1 == fd))
+	{
+		applog(LOG_ERR, "%"PRIpreprv": Failed to open %s",
+		       bigpic->proc_repr, bigpic->device_path);
+		return false;
+	}
+
+	bigpic->device_fd = fd;
+
+	applog(LOG_INFO, "%"PRIpreprv": Opened %s", bigpic->proc_repr, bigpic->device_path);
+
+	struct timeval tv_now;
+	gettimeofday(&tv_now, NULL);
+	timer_set_delay(&thr->tv_poll, &tv_now, 1000000);
+
+	info->tx_buffer[0] = 'W';
+
+	return true;
+}
+
+//------------------------------------------------------------------------------
+static bool duplicate(uint32_t *results, uint32_t size, uint32_t test_nonce)
+{
+	for(uint32_t i=0; i<size; i++)
+	{
+		if(results[i] == test_nonce)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+//------------------------------------------------------------------------------
+static void bigpic_process_results(struct thr_info *thr, struct work *work)
+{
+	struct cgpu_info *board = thr->cgpu;
+	struct bigpic_info *info = (struct bigpic_info *)board->device_data;
+
+	uint32_t results[16*6];
+	uint32_t num_results;
+
+	uint32_t m7    = *((uint32_t *)&work->data[64]);
+	uint32_t ntime = *((uint32_t *)&work->data[68]);
+	uint32_t nbits = *((uint32_t *)&work->data[72]);
+
+	int32_t nonces = (info->rx_len / 7) - 1;
+
+	num_results = 0;
+	for(int i=0; i<info->rx_len; i+=7)
+	{
+		struct bigpic_state state;
+		state.state = info->rx_buffer[i + 1];
+		state.switched = info->rx_buffer[i + 2];
+		memcpy(&state.nonce, info->rx_buffer + i + 3, 4);
+
+		if(duplicate(results, num_results, state.nonce))
+		{
+			continue;
+		}
+
+		uint32_t nonce = bitfury_decnonce(state.nonce);
+		results[num_results++] = state.nonce;
+
+		//applog(LOG_DEBUG, "%"PRIpreprv": Len: %d Cmd: %c State: %c Switched: %d Nonce: %08X", board->proc_repr, info->rx_len, info->rx_buffer[i], state->state, state->switched, nonce);
+		if (bitfury_fudge_nonce(work->midstate, m7, ntime, nbits, &nonce))
+		{
+			submit_nonce(thr, work, nonce);
+			nonces--;
+			continue;
+		}
+		inc_hw_errors(thr, work, nonce);
+	}
+}
+
+static
+bool bigpic_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused uint64_t max_nonce)
+{
+	struct cgpu_info *board = thr->cgpu;
+	struct bigpic_info *info = (struct bigpic_info *)board->device_data;
+	
+	memcpy(&info->tx_buffer[ 1], work->midstate, 32);
+	memcpy(&info->tx_buffer[33], &work->data[64], 12);
+	
+	work->blk.nonce = 0xffffffff;
+	return true;
+}
+
+static
+void bigpic_job_start(struct thr_info *thr)
+{
+	struct cgpu_info *board = thr->cgpu;
+	struct bigpic_info *info = (struct bigpic_info *)board->device_data;
+	
+	if (opt_dev_protocol && opt_debug)
+	{
+		char hex[91];
+		bin2hex(hex, info->tx_buffer, 45);
+		applog(LOG_DEBUG, "%"PRIpreprv": SEND: %s",
+		       board->proc_repr, hex);
+	}
+	
+	write(board->device_fd, info->tx_buffer, 45);
+	
+	while(1)
+	{
+		uint8_t buffer[7];
+		int len;
+		len = serial_read(board->device_fd, buffer, 7);
+		if(len > 0)
+			break;
+	}
+	
+	applog(LOG_DEBUG, "%"PRIpreprv": Work Task sent", board->proc_repr);
+	
+	while(1)
+	{
+		info->rx_len = serial_read(board->device_fd, info->rx_buffer, sizeof(info->rx_buffer));
+		if(info->rx_len > 0)
+			break;
+	}
+	applog(LOG_DEBUG, "%"PRIpreprv": Work Task accepted", board->proc_repr);
+
+	applog(LOG_DEBUG, "%"PRIpreprv": Nonces sent back: %d",
+	       board->proc_repr, info->rx_len / 7);
+	
+	mt_job_transition(thr);
+	// TODO: Delay morework until right before it's needed
+	timer_set_now(&thr->tv_morework);
+	job_start_complete(thr);
+}
+
+static
+int64_t bigpic_job_process_results(struct thr_info *thr, struct work *work, bool stopping)
+{
+	// FIXME: not sure how to handle stopping
+	bigpic_process_results(thr, work);
+	
+	return 0xBD000000;
+}
+
+//------------------------------------------------------------------------------
+static void bigpic_shutdown(struct thr_info *thr)
+{
+	struct cgpu_info *cgpu = thr->cgpu;
+
+	serial_close(cgpu->device_fd);
+}
+
+//------------------------------------------------------------------------------
+static bool bigpic_identify(struct cgpu_info *cgpu)
+{
+	char buf[] = "L";
+	write(cgpu->device_fd, buf, sizeof(buf));
+	
+	return true;
+}
+
+//------------------------------------------------------------------------------
+struct device_drv bigpic_drv = {
+	.dname = "bigpic",
+	.name = "BPM",
+
+	.drv_detect = bigpic_detect,
+
+	.identify_device = bigpic_identify,
+
+	.thread_init = bigpic_init,
+	
+	.minerloop = minerloop_async,
+	.job_prepare = bigpic_job_prepare,
+	.job_start = bigpic_job_start,
+	.job_process_results = bigpic_job_process_results,
+	
+	.thread_shutdown = bigpic_shutdown,
+};

+ 44 - 0
driver-bigpic.h

@@ -0,0 +1,44 @@
+/*
+ * Copyright 2013 DI Andreas Auer
+ *
+ * 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.
+ *
+ *  Created on: 09.10.2013
+ *      Author: DI Andreas Auer
+ *        Mail: aauer1@gmail.com
+ */
+
+#ifndef BFG_DRIVER_BIGPIC_H
+#define BFG_DRIVER_BIGPIC_H
+
+#define BPM_BAUD	115200
+
+struct bigpic_identity
+{
+	uint8_t version;
+	char    product[8];
+	uint32_t serial;
+} __attribute__((packed));
+
+struct bigpic_state
+{
+    uint8_t state;
+    uint8_t switched;
+    uint32_t nonce;
+} __attribute__((packed));
+
+struct bigpic_info
+{
+	uint32_t baud;
+
+	struct bigpic_identity id;
+
+	char tx_buffer[45];
+	char rx_buffer[1024];
+	uint32_t rx_len;
+};
+
+#endif /* DRIVER_S6LX75_H_ */

+ 751 - 0
driver-bitfury.c

@@ -0,0 +1,751 @@
+/*
+ * Copyright 2013 bitfury
+ * Copyright 2013 legkodymov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <limits.h>
+#include "miner.h"
+#include <unistd.h>
+#include <sha2.h>
+
+#include "deviceapi.h"
+#include "libbitfury.h"
+#include "util.h"
+#include "spidevc.h"
+
+#define GOLDEN_BACKLOG 5
+#define LINE_LEN 2048
+
+struct device_drv bitfury_drv;
+
+int calc_stat(time_t * stat_ts, time_t stat, struct timeval now);
+double shares_to_ghashes(int shares, int seconds);
+
+static
+int bitfury_autodetect()
+{
+	RUNONCE(0);
+	
+	int chip_n;
+	struct cgpu_info *bitfury_info;
+
+	bitfury_info = calloc(1, sizeof(struct cgpu_info));
+	bitfury_info->drv = &bitfury_drv;
+	bitfury_info->threads = 1;
+
+	applog(LOG_INFO, "INFO: bitfury_detect");
+	spi_init();
+	if (!sys_spi)
+		return 0;
+	chip_n = libbitfury_detectChips1(sys_spi);
+	if (!chip_n) {
+		applog(LOG_WARNING, "No Bitfury chips detected!");
+		return 0;
+	} else {
+		applog(LOG_WARNING, "BITFURY: %d chips detected!", chip_n);
+	}
+
+	bitfury_info->procs = chip_n;
+	add_cgpu(bitfury_info);
+	
+	return 1;
+}
+
+static void bitfury_detect(void)
+{
+	noserial_detect_manual(&bitfury_drv, bitfury_autodetect);
+}
+
+
+static
+void *bitfury_just_io(struct bitfury_device * const bitfury)
+{
+	struct spi_port * const spi = bitfury->spi;
+	const int chip = bitfury->fasync;
+	void *rv;
+	
+	spi_clear_buf(spi);
+	spi_emit_break(spi);
+	spi_emit_fasync(spi, chip);
+	rv = spi_emit_data(spi, 0x3000, &bitfury->atrvec[0], 19 * 4);
+	spi_txrx(spi);
+	return rv;
+}
+
+static
+void bitfury_debug_nonce_array(const struct cgpu_info * const proc, const char *msg, const uint32_t * const inp)
+{
+	const struct bitfury_device * const bitfury = proc->device_data;
+	const int active = bitfury->active;
+	char s[((1 + 8) * 0x10) + 1];
+	char *sp = s;
+	for (int i = 0; i < 0x10; ++i)
+		sp += sprintf(sp, "%c%08lx",
+		              (active == i) ? '>' : ' ',
+		              (unsigned long)bitfury_decnonce(inp[i]));
+	applog(LOG_DEBUG, "%"PRIpreprv": %s%s (job=%08lx)",
+	       proc->proc_repr, msg, s, (unsigned long)inp[0x10]);
+}
+
+static
+bool bitfury_init_oldbuf(struct cgpu_info * const proc, const uint32_t *inp)
+{
+	struct bitfury_device * const bitfury = proc->device_data;
+	uint32_t * const oldbuf = &bitfury->oldbuf[0];
+	uint32_t * const buf = &bitfury->newbuf[0];
+	int i, differ, tried = 0;
+	
+	if (!inp)
+		inp = bitfury_just_io(bitfury);
+tryagain:
+	if (tried > 3)
+	{
+		applog(LOG_ERR, "%"PRIpreprv": %s: Giving up after %d tries",
+		       proc->proc_repr, __func__, tried);
+		bitfury->desync_counter = 99;
+		return false;
+	}
+	++tried;
+	memcpy(buf, inp, 0x10 * 4);
+	inp = bitfury_just_io(bitfury);
+	differ = -1;
+	for (i = 0; i < 0x10; ++i)
+	{
+		if (inp[i] != buf[i])
+		{
+			if (differ != -1)
+			{
+				applog(LOG_DEBUG, "%"PRIpreprv": %s: Second differ at %d; trying again",
+				       proc->proc_repr, __func__, i);
+				goto tryagain;
+			}
+			differ = i;
+			applog(LOG_DEBUG, "%"PRIpreprv": %s: Differ at %d",
+			       proc->proc_repr, __func__, i);
+		}
+	}
+	if (-1 == differ)
+	{
+		applog(LOG_DEBUG, "%"PRIpreprv": %s: No differ found; trying again",
+		       proc->proc_repr, __func__);
+		goto tryagain;
+	}
+	
+	bitfury->active = differ;
+	memcpy(&oldbuf[0], &inp[bitfury->active], 4 * (0x10 - bitfury->active));
+	memcpy(&oldbuf[0x10 - bitfury->active], &inp[0], 4 * bitfury->active);
+	bitfury->oldjob = inp[0x10];
+	bitfury->desync_counter = 0;
+	
+	if (opt_debug)
+		bitfury_debug_nonce_array(proc, "Init", inp);
+	
+	return true;
+}
+
+bool bitfury_init_chip(struct cgpu_info * const proc)
+{
+	struct bitfury_device * const bitfury = proc->device_data;
+	struct bitfury_payload payload = {
+		.midstate = "\xf9\x9a\xf0\xd5\x72\x34\x41\xdc\x9e\x10\xd1\x1f\xeb\xcd\xe3\xf5"
+		            "\x52\xf1\x14\x63\x06\x14\xd1\x12\x15\x25\x39\xd1\x7d\x77\x5a\xfd",
+		.m7    = 0xafbd0b42,
+		.ntime = 0xb6c24563,
+		.nbits = 0x6dfa4352,
+	};
+	payload_to_atrvec(bitfury->atrvec, &payload);
+	return bitfury_init_oldbuf(proc, NULL);
+}
+
+static
+bool bitfury_init(struct thr_info *thr)
+{
+	struct cgpu_info *proc;
+	struct bitfury_device *bitfury;
+	
+	for (proc = thr->cgpu; proc; proc = proc->next_proc)
+	{
+		bitfury = proc->device_data = malloc(sizeof(struct bitfury_device));
+		*bitfury = (struct bitfury_device){
+			.spi = sys_spi,
+			.fasync = proc->proc_id,
+		};
+		bitfury_init_chip(proc);
+	}
+	
+	return true;
+}
+
+static
+bool bitfury_queue_full(struct cgpu_info *cgpu)
+{
+	struct cgpu_info *proc;
+	struct bitfury_device *bitfury;
+	
+	for (proc = cgpu; proc; proc = proc->next_proc)
+	{
+		bitfury = proc->device_data;
+		
+		if (bitfury->work)
+			continue;
+		
+		bitfury->work = get_queued(cgpu);
+		if (!bitfury->work)
+			return false;
+		
+		work_to_payload(&bitfury->payload, bitfury->work);
+	}
+	
+	return true;
+}
+
+int64_t bitfury_scanHash(struct thr_info *thr)
+{
+	struct cgpu_info * const cgpu = thr->cgpu;
+	struct bitfury_device * const sds = cgpu->device_data;
+	struct cgpu_info *proc;
+	struct thr_info *pthr;
+	struct bitfury_device *bitfury;
+	struct timeval now;
+	char line[LINE_LEN];
+	int short_stat = 10;
+	int long_stat = 1800;
+	int i;
+
+	if (!bitfury_queue_full(cgpu))
+		return 0;
+	
+	for (proc = cgpu; proc; proc = proc->next_proc)
+	{
+		const int chip = proc->proc_id;
+		pthr = proc->thr[0];
+		bitfury = proc->device_data;
+		
+		bitfury->job_switched = 0;
+		payload_to_atrvec(bitfury->atrvec, &bitfury->payload);
+		libbitfury_sendHashData1(chip, bitfury, pthr);
+	}
+
+	cgsleep_ms(5);
+
+	cgtime(&now);
+	for (proc = cgpu; proc; proc = proc->next_proc)
+	{
+		pthr = proc->thr[0];
+		bitfury = proc->device_data;
+		
+		if (bitfury->job_switched) {
+			int i,j;
+			unsigned int * const res = bitfury->results;
+			struct work * const work = bitfury->work;
+			struct work * const owork = bitfury->owork;
+			struct work * const o2work = bitfury->o2work;
+			i = bitfury->results_n;
+			for (j = i - 1; j >= 0; j--) {
+				if (owork) {
+					submit_nonce(pthr, owork, bswap_32(res[j]));
+					bitfury->stat_ts[bitfury->stat_counter++] =
+						now.tv_sec;
+					if (bitfury->stat_counter == BITFURY_STAT_N) {
+						bitfury->stat_counter = 0;
+					}
+				}
+				if (o2work) {
+					// TEST
+					//submit_nonce(pthr, owork, bswap_32(res[j]));
+				}
+			}
+			bitfury->results_n = 0;
+			bitfury->job_switched = 0;
+			if (bitfury->old_nonce && o2work) {
+					submit_nonce(pthr, o2work, bswap_32(bitfury->old_nonce));
+					i++;
+			}
+			if (bitfury->future_nonce) {
+					submit_nonce(pthr, work, bswap_32(bitfury->future_nonce));
+					i++;
+			}
+
+			if (o2work)
+				work_completed(cgpu, o2work);
+
+			bitfury->o2work = bitfury->owork;
+			bitfury->owork = bitfury->work;
+			bitfury->work = NULL;
+			hashes_done2(pthr, 0xbd000000, NULL);
+		}
+	}
+
+	if (now.tv_sec - sds->short_out_t > short_stat) {
+		int shares_first = 0, shares_last = 0, shares_total = 0;
+		char stat_lines[32][LINE_LEN] = {{0}};
+		int len, k;
+		double gh[32][8] = {{0}};
+		double ghsum = 0, gh1h = 0, gh2h = 0;
+		unsigned strange_counter = 0;
+
+		for (proc = cgpu; proc; proc = proc->next_proc)
+		{
+			const int chip = proc->proc_id;
+			bitfury = proc->device_data;
+			
+			int shares_found = calc_stat(bitfury->stat_ts, short_stat, now);
+			double ghash;
+			len = strlen(stat_lines[bitfury->slot]);
+			ghash = shares_to_ghashes(shares_found, short_stat);
+			gh[bitfury->slot][chip & 0x07] = ghash;
+			snprintf(stat_lines[bitfury->slot] + len, LINE_LEN - len, "%.1f-%3.0f ", ghash, bitfury->mhz);
+
+			if(sds->short_out_t && ghash < 0.5) {
+				applog(LOG_WARNING, "Chip_id %d FREQ CHANGE", chip);
+				send_freq(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits - 1);
+				cgsleep_ms(1);
+				send_freq(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
+			}
+			shares_total += shares_found;
+			shares_first += chip < 4 ? shares_found : 0;
+			shares_last += chip > 3 ? shares_found : 0;
+			strange_counter += bitfury->strange_counter;
+			bitfury->strange_counter = 0;
+		}
+		sprintf(line, "vvvvwww SHORT stat %ds: wwwvvvv", short_stat);
+		applog(LOG_WARNING, "%s", line);
+		sprintf(line, "stranges: %u", strange_counter);
+		applog(LOG_WARNING, "%s", line);
+		for(i = 0; i < 32; i++)
+			if(strlen(stat_lines[i])) {
+				len = strlen(stat_lines[i]);
+				ghsum = 0;
+				gh1h = 0;
+				gh2h = 0;
+				for(k = 0; k < 4; k++) {
+					gh1h += gh[i][k];
+					gh2h += gh[i][k+4];
+					ghsum += gh[i][k] + gh[i][k+4];
+				}
+				snprintf(stat_lines[i] + len, LINE_LEN - len, "- %2.1f + %2.1f = %2.1f slot %i ", gh1h, gh2h, ghsum, i);
+				applog(LOG_WARNING, "%s", stat_lines[i]);
+			}
+		sds->short_out_t = now.tv_sec;
+	}
+
+	if (now.tv_sec - sds->long_out_t > long_stat) {
+		int shares_first = 0, shares_last = 0, shares_total = 0;
+		char stat_lines[32][LINE_LEN] = {{0}};
+		int len, k;
+		double gh[32][8] = {{0}};
+		double ghsum = 0, gh1h = 0, gh2h = 0;
+
+		for (proc = cgpu; proc; proc = proc->next_proc)
+		{
+			const int chip = proc->proc_id;
+			bitfury = proc->device_data;
+			
+			int shares_found = calc_stat(bitfury->stat_ts, long_stat, now);
+			double ghash;
+			len = strlen(stat_lines[bitfury->slot]);
+			ghash = shares_to_ghashes(shares_found, long_stat);
+			gh[bitfury->slot][chip & 0x07] = ghash;
+			snprintf(stat_lines[bitfury->slot] + len, LINE_LEN - len, "%.1f-%3.0f ", ghash, bitfury->mhz);
+
+			shares_total += shares_found;
+			shares_first += chip < 4 ? shares_found : 0;
+			shares_last += chip > 3 ? shares_found : 0;
+		}
+		sprintf(line, "!!!_________ LONG stat %ds: ___________!!!", long_stat);
+		applog(LOG_WARNING, "%s", line);
+		for(i = 0; i < 32; i++)
+			if(strlen(stat_lines[i])) {
+				len = strlen(stat_lines[i]);
+				ghsum = 0;
+				gh1h = 0;
+				gh2h = 0;
+				for(k = 0; k < 4; k++) {
+					gh1h += gh[i][k];
+					gh2h += gh[i][k+4];
+					ghsum += gh[i][k] + gh[i][k+4];
+				}
+				snprintf(stat_lines[i] + len, LINE_LEN - len, "- %2.1f + %2.1f = %2.1f slot %i ", gh1h, gh2h, ghsum, i);
+				applog(LOG_WARNING, "%s", stat_lines[i]);
+			}
+		sds->long_out_t = now.tv_sec;
+	}
+
+	return 0;
+}
+
+double shares_to_ghashes(int shares, int seconds) {
+	return (double)shares / (double)seconds * 4.84387;  //orig: 4.77628
+}
+
+int calc_stat(time_t * stat_ts, time_t stat, struct timeval now) {
+	int j;
+	int shares_found = 0;
+	for(j = 0; j < BITFURY_STAT_N; j++) {
+		if (now.tv_sec - stat_ts[j] < stat) {
+			shares_found++;
+		}
+	}
+	return shares_found;
+}
+
+bool bitfury_prepare(struct thr_info *thr)
+{
+	struct cgpu_info *cgpu = thr->cgpu;
+
+	get_now_datestamp(cgpu->init, sizeof(cgpu->init));
+
+	applog(LOG_INFO, "INFO bitfury_prepare");
+	return true;
+}
+
+void bitfury_shutdown(struct thr_info *thr) {
+	struct cgpu_info *cgpu = thr->cgpu, *proc;
+	struct bitfury_device *bitfury;
+	
+	applog(LOG_INFO, "INFO bitfury_shutdown");
+	for (proc = cgpu; proc; proc = proc->next_proc)
+	{
+		bitfury = proc->device_data;
+		send_shutdown(bitfury->spi, bitfury->slot, bitfury->fasync);
+	}
+}
+
+bool bitfury_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused uint64_t max_nonce)
+{
+	struct cgpu_info * const proc = thr->cgpu;
+	struct bitfury_device * const bitfury = proc->device_data;
+	
+	if (opt_debug)
+	{
+		char hex[153];
+		bin2hex(hex, &work->data[0], 76);
+		applog(LOG_DEBUG, "%"PRIpreprv": Preparing work %s",
+		       proc->proc_repr, hex);
+	}
+	work_to_payload(&bitfury->payload, work);
+	payload_to_atrvec(bitfury->atrvec, &bitfury->payload);
+	
+	work->blk.nonce = 0xffffffff;
+	return true;
+}
+
+static
+bool fudge_nonce(struct work * const work, uint32_t *nonce_p) {
+	static const uint32_t offsets[] = {0, 0xffc00000, 0xff800000, 0x02800000, 0x02C00000, 0x00400000};
+	uint32_t nonce;
+	int i;
+	
+	if (unlikely(!work))
+		return false;
+	
+	for (i = 0; i < 6; ++i)
+	{
+		nonce = *nonce_p + offsets[i];
+		if (test_nonce(work, nonce, false))
+		{
+			*nonce_p = nonce;
+			return true;
+		}
+	}
+	return false;
+}
+
+void bitfury_noop_job_start(struct thr_info __maybe_unused * const thr)
+{
+}
+
+typedef uint32_t bitfury_inp_t[0x11];
+
+void bitfury_do_io(struct thr_info * const master_thr)
+{
+	struct cgpu_info *proc;
+	struct thr_info *thr;
+	struct bitfury_device *bitfury;
+	const uint32_t *inp;
+	int n, i, j;
+	bool newjob;
+	uint32_t nonce;
+	int n_chips = 0, lastchip;
+	struct spi_port *spi = NULL;
+	bool should_be_running;
+	
+	for (proc = master_thr->cgpu; proc; proc = proc->next_proc)
+		++n_chips;
+	
+	struct cgpu_info *procs[n_chips];
+	void *rxbuf[n_chips];
+	bitfury_inp_t rxbuf_copy[n_chips];
+	
+	// NOTE: This code assumes:
+	// 1) that chips on the same SPI bus are grouped together
+	// 2) that chips are in sequential fasync order
+	n_chips = 0;
+	for (proc = master_thr->cgpu; proc; proc = proc->next_proc)
+	{
+		thr = proc->thr[0];
+		bitfury = proc->device_data;
+		
+		should_be_running = (proc->deven == DEV_ENABLED && !thr->pause);
+		
+		if (should_be_running)
+		{
+			if (spi != bitfury->spi)
+			{
+				if (spi)
+					spi_txrx(spi);
+				spi = bitfury->spi;
+				spi_clear_buf(spi);
+				spi_emit_break(spi);
+				lastchip = 0;
+			}
+			procs[n_chips] = proc;
+			spi_emit_fasync(spi, bitfury->fasync - lastchip);
+			lastchip = bitfury->fasync;
+			rxbuf[n_chips] = spi_emit_data(spi, 0x3000, &bitfury->atrvec[0], 19 * 4);
+			++n_chips;
+		}
+		else
+		if (thr->work /* is currently running */ && thr->busy_state != TBS_STARTING_JOB)
+			;//FIXME: shutdown chip
+	}
+	spi_txrx(spi);
+	
+	for (j = 0; j < n_chips; ++j)
+	{
+		memcpy(rxbuf_copy[j], rxbuf[j], 0x11 * 4);
+		rxbuf[j] = rxbuf_copy[j];
+	}
+	
+	for (j = 0; j < n_chips; ++j)
+	{
+		proc = procs[j];
+		thr = proc->thr[0];
+		bitfury = proc->device_data;
+		uint32_t * const newbuf = &bitfury->newbuf[0];
+		uint32_t * const oldbuf = &bitfury->oldbuf[0];
+		
+		inp = rxbuf[j];
+		
+		if (unlikely(bitfury->desync_counter == 99))
+		{
+			bitfury_init_oldbuf(proc, inp);
+			goto out;
+		}
+		
+		if (opt_debug)
+			bitfury_debug_nonce_array(proc, "Read", inp);
+		
+		// To avoid dealing with wrap-around entirely, we rotate array so previous active uint32_t is at index 0
+		memcpy(&newbuf[0], &inp[bitfury->active], 4 * (0x10 - bitfury->active));
+		memcpy(&newbuf[0x10 - bitfury->active], &inp[0], 4 * bitfury->active);
+		newjob = inp[0x10];
+		
+		if (newbuf[0xf] != oldbuf[0xf])
+		{
+			inc_hw_errors2(thr, NULL, NULL);
+			if (unlikely(++bitfury->desync_counter >= 4))
+			{
+				applog(LOG_WARNING, "%"PRIpreprv": Previous nonce mismatch (4th try), recalibrating",
+				       proc->proc_repr);
+				bitfury_init_oldbuf(proc, inp);
+				continue;
+			}
+			applog(LOG_DEBUG, "%"PRIpreprv": Previous nonce mismatch, ignoring response",
+			       proc->proc_repr);
+			goto out;
+		}
+		else
+			bitfury->desync_counter = 0;
+		
+		if (bitfury->oldjob != newjob && thr->next_work)
+		{
+			mt_job_transition(thr);
+			// TODO: Delay morework until right before it's needed
+			timer_set_now(&thr->tv_morework);
+			job_start_complete(thr);
+		}
+		
+		for (n = 0; newbuf[n] == oldbuf[n]; ++n)
+		{
+			if (unlikely(n >= 0xf))
+			{
+				inc_hw_errors2(thr, NULL, NULL);
+				applog(LOG_DEBUG, "%"PRIpreprv": Full result match, reinitialising",
+				       proc->proc_repr);
+				send_reinit(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
+				bitfury->desync_counter = 99;
+				goto out;
+			}
+		}
+		
+		if (n)
+		{
+			for (i = 0; i < n; ++i)
+			{
+				nonce = bitfury_decnonce(newbuf[i]);
+				if (fudge_nonce(thr->work, &nonce))
+				{
+					applog(LOG_DEBUG, "%"PRIpreprv": nonce %x = %08lx (work=%p)",
+					       proc->proc_repr, i, (unsigned long)nonce, thr->work);
+					submit_nonce(thr, thr->work, nonce);
+				}
+				else
+				if (fudge_nonce(thr->prev_work, &nonce))
+				{
+					applog(LOG_DEBUG, "%"PRIpreprv": nonce %x = %08lx (prev work=%p)",
+					       proc->proc_repr, i, (unsigned long)nonce, thr->prev_work);
+					submit_nonce(thr, thr->prev_work, nonce);
+				}
+				else
+				{
+					inc_hw_errors(thr, thr->work, nonce);
+					++bitfury->sample_hwe;
+				}
+				if (++bitfury->sample_tot >= 0x40 || bitfury->sample_hwe >= 8)
+				{
+					if (bitfury->sample_hwe >= 8)
+					{
+						applog(LOG_WARNING, "%"PRIpreprv": %d of the last %d results were bad, reinitialising",
+						       proc->proc_repr, bitfury->sample_hwe, bitfury->sample_tot);
+						send_reinit(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
+						bitfury->desync_counter = 99;
+					}
+					bitfury->sample_tot = bitfury->sample_hwe = 0;
+				}
+			}
+			bitfury->active = (bitfury->active + n) % 0x10;
+		}
+		
+		memcpy(&oldbuf[0], &newbuf[n], 4 * (0x10 - n));
+		memcpy(&oldbuf[0x10 - n], &newbuf[0], 4 * n);
+		bitfury->oldjob = newjob;
+		
+out:
+		if (unlikely(bitfury->force_reinit))
+		{
+			applog(LOG_DEBUG, "%"PRIpreprv": Forcing reinitialisation",
+			       proc->proc_repr);
+			send_reinit(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
+			bitfury->desync_counter = 99;
+		}
+	}
+	
+	timer_set_delay_from_now(&master_thr->tv_poll, 10000);
+}
+
+int64_t bitfury_job_process_results(struct thr_info *thr, struct work *work, bool stopping)
+{
+	// Bitfury chips process only 768/1024 of the nonce range
+	return 0xbd000000;
+}
+
+struct api_data *bitfury_api_device_detail(struct cgpu_info * const cgpu)
+{
+	struct bitfury_device * const bitfury = cgpu->device_data;
+	struct api_data *root = NULL;
+	
+	root = api_add_uint(root, "fasync", &bitfury->fasync, false);
+	
+	return root;
+}
+
+struct api_data *bitfury_api_device_status(struct cgpu_info * const cgpu)
+{
+	struct bitfury_device * const bitfury = cgpu->device_data;
+	struct api_data *root = NULL;
+	int clock_bits = bitfury->osc6_bits;
+	
+	root = api_add_int(root, "Clock Bits", &clock_bits, true);
+	
+	return root;
+}
+
+static
+bool _bitfury_set_device_parse_setting(int * const rv, char * const setting, char * const replybuf, const int maxval)
+{
+	char *p;
+	long int nv;
+	
+	if (!setting || !*setting)
+	{
+		sprintf(replybuf, "missing setting");
+		return false;
+	}
+	nv = strtol(setting, &p, 0);
+	if ((p && p[0]) || nv > maxval || nv < 1)
+	{
+		sprintf(replybuf, "invalid setting");
+		return false;
+	}
+	*rv = nv;
+	return true;
+}
+
+char *bitfury_set_device(struct cgpu_info * const proc, char * const option, char * const setting, char * const replybuf)
+{
+	struct bitfury_device * const bitfury = proc->device_data;
+	int newval;
+	
+	if (!strcasecmp(option, "help"))
+	{
+		sprintf(replybuf, "baud: SPI baud rate\nosc6_bits: range 1-55 (slow to fast)");
+		return replybuf;
+	}
+	
+	if (!strcasecmp(option, "baud"))
+	{
+		if (!_bitfury_set_device_parse_setting(&bitfury->spi->speed, setting, replybuf, INT_MAX))
+			return replybuf;
+		
+		return NULL;
+	}
+	
+	if (!strcasecmp(option, "osc6_bits"))
+	{
+		newval = bitfury->osc6_bits;
+		if (!_bitfury_set_device_parse_setting(&newval, setting, replybuf, 55))
+			return replybuf;
+		
+		bitfury->osc6_bits = newval;
+		bitfury->force_reinit = true;
+		
+		return NULL;
+	}
+	
+	sprintf(replybuf, "Unknown option: %s", option);
+	return replybuf;
+}
+
+struct device_drv bitfury_drv = {
+	.dname = "bitfury_gpio",
+	.name = "BFY",
+	.drv_detect = bitfury_detect,
+	.thread_prepare = bitfury_prepare,
+	.thread_init = bitfury_init,
+	.queue_full = bitfury_queue_full,
+	.scanwork = bitfury_scanHash,
+	.thread_shutdown = bitfury_shutdown,
+	.minerloop = hash_queued_work,
+};
+

+ 24 - 0
driver-bitfury.h

@@ -0,0 +1,24 @@
+#ifndef BFG_DRIVER_BITFURY_H
+#define BFG_DRIVER_BITFURY_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "miner.h"
+
+extern bool bitfury_prepare(struct thr_info *);
+extern bool bitfury_init_chip(struct cgpu_info *);
+
+extern int64_t bitfury_scanHash(struct thr_info *);
+
+extern bool bitfury_job_prepare(struct thr_info *, struct work *, uint64_t max_nonce);
+extern void bitfury_noop_job_start(struct thr_info *);
+extern void bitfury_do_io(struct thr_info *);
+extern int64_t bitfury_job_process_results(struct thr_info *, struct work *, bool stopping);
+extern struct api_data *bitfury_api_device_detail(struct cgpu_info *);
+extern struct api_data *bitfury_api_device_status(struct cgpu_info *);
+extern char *bitfury_set_device(struct cgpu_info *, char *, char *, char *);
+
+extern void bitfury_shutdown(struct thr_info *);
+
+#endif

+ 1 - 0
driver-cpu.c

@@ -33,6 +33,7 @@
 #include "deviceapi.h"
 #include "miner.h"
 #include "bench_block.h"
+#include "logging.h"
 #include "util.h"
 #include "driver-cpu.h"
 

+ 1 - 8
driver-getwork.c

@@ -195,14 +195,7 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 	
 out:
 	if (hashesdone)
-	{
-		struct timeval tv_now, tv_delta;
-		long long lld = strtoll(hashesdone, NULL, 0);
-		timer_set_now(&tv_now);
-		timersub(&tv_now, &client->tv_hashes_done, &tv_delta);
-		client->tv_hashes_done = tv_now;
-		hashes_done(thr, lld, &tv_delta, NULL);
-	}
+		hashes_done2(thr, strtoll(hashesdone, NULL, 0), NULL);
 	
 	free(idstr);
 	if (json)

+ 444 - 0
driver-littlefury.c

@@ -0,0 +1,444 @@
+/*
+ * Copyright 2013 Luke Dashjr
+ *
+ * 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 <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "deviceapi.h"
+#include "driver-bitfury.h"
+#include "fpgautils.h"
+#include "libbitfury.h"
+#include "logging.h"
+#include "miner.h"
+#include "spidevc.h"
+#include "util.h"
+
+
+enum littlefury_opcode {
+	LFOP_VERSION = 0,
+	LFOP_SPI     = 1,
+	LFOP_REGVOLT = 2,
+	LFOP_REGINFO = 3,
+	LFOP_REGPWR  = 4,
+	LFOP_TEMP    = 5,
+	LFOP_LED     = 6,
+	LFOP_ADC     = 7,
+};
+
+struct device_drv littlefury_drv;
+
+static uint16_t crc16tab[] = {
+	0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
+	0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
+	0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
+	0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
+	0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
+	0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
+	0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
+	0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
+	0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
+	0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
+	0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
+	0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
+	0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
+	0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
+	0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
+	0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
+	0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
+	0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
+	0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
+	0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
+	0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
+	0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
+	0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
+	0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
+	0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
+	0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
+	0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
+	0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
+	0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
+	0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
+	0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
+	0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0,
+};
+
+static
+uint16_t crc16_floating(uint16_t next_byte, uint16_t seed)
+{
+	return ((seed << 8) ^ crc16tab[(seed >> 8) ^ next_byte]) & 0xFFFF;
+}
+
+static
+uint16_t crc16(void *p, size_t sz)
+{
+	const uint8_t * const s = p;
+	uint16_t crc = 0xFFFF;
+	for (size_t i = 0; i < sz; ++i)
+		crc = crc16_floating(s[i], crc);
+	return crc;
+}
+
+static
+ssize_t keep_reading(int fd, void *buf, size_t count)
+{
+	ssize_t r, rv = 0;
+	
+	while (count)
+	{
+		r = read(fd, buf, count);
+		if (unlikely(r <= 0))
+		{
+			applog(LOG_ERR, "Read of fd %d returned %d", fd, (int)r);
+			return rv ?: r;
+		}
+		rv += r;
+		count -= r;
+		buf += r;
+	}
+	
+	return rv;
+}
+
+static
+bool bitfury_do_packet(int prio, const char *repr, const int fd, void * const buf, uint16_t * const bufsz, const uint8_t op, const void * const payload, const uint16_t payloadsz)
+{
+	uint16_t crc;
+	size_t sz;
+	ssize_t r;
+	uint8_t pkt[0x407];
+	bool b;
+	
+	{
+		sz = 2 + 1 + 2 + payloadsz + 2;
+		pkt[0] = 0xab;
+		pkt[1] = 0xcd;
+		pkt[2] = op;
+		pkt[3] = payloadsz >> 8;
+		pkt[4] = payloadsz & 0xff;
+		if (payloadsz)
+			memcpy(&pkt[5], payload, payloadsz);
+		crc = crc16(&pkt[2], 3 + (size_t)payloadsz);
+		pkt[sz - 2] = crc >> 8;
+		pkt[sz - 1] = crc & 0xff;
+		if (unlikely(opt_dev_protocol))
+		{
+			char hex[(sz * 2) + 1];
+			bin2hex(hex, pkt, sz);
+			applog(LOG_DEBUG, "%s: DEVPROTO: SEND %s", repr, hex);
+		}
+		r = write(fd, pkt, sz);
+		if (sz != r)
+		{
+			applog(prio, "%s: Failed to write packet (%d bytes succeeded)", repr, (int)r);
+			return false;
+		}
+	}
+	
+	{
+		r = keep_reading(fd, pkt, 5);
+		if (5 != r || pkt[0] != 0xab || pkt[1] != 0xcd || pkt[2] != op)
+		{
+			char hex[(r * 2) + 1];
+			bin2hex(hex, pkt, r);
+			applog(prio, "%s: DEVPROTO: RECV %s", repr, hex);
+			applog(prio, "%s: Failed to read correct packet header", repr);
+			return false;
+		}
+		sz = (((unsigned)pkt[3] << 8) | pkt[4]) + 2;
+		r = keep_reading(fd, &pkt[5], sz);
+		if (sz != r)
+		{
+			r += 5;
+			char hex[(r * 2) + 1];
+			bin2hex(hex, pkt, r);
+			applog(prio, "%s: DEVPROTO: RECV %s", repr, hex);
+			applog(prio, "%s: Failed to read packet payload (len=%d)", repr, (int)sz);
+			return false;
+		}
+		crc = (pkt[sz + 3] << 8) | pkt[sz + 4];
+		b = (crc != crc16(&pkt[2], sz + 1));
+		if (unlikely(opt_dev_protocol || b))
+		{
+			char hex[((sz + 5) * 2) + 1];
+			bin2hex(hex, pkt, sz + 5);
+			applog(b ? prio : LOG_DEBUG, "%s: DEVPROTO: RECV %s", repr, hex);
+			if (b)
+			{
+				applog(prio, "%s: Packet checksum mismatch", repr);
+				return false;
+			}
+		}
+		sz -= 2;
+		memcpy(buf, &pkt[5], (*bufsz < sz ? *bufsz : sz));
+		*bufsz = sz;
+	}
+	
+	return true;
+}
+
+static
+bool littlefury_txrx(struct spi_port *port)
+{
+	const struct cgpu_info * const cgpu = port->cgpu;
+	const void *wrbuf = spi_gettxbuf(port);
+	void *rdbuf = spi_getrxbuf(port);
+	size_t bufsz = spi_getbufsz(port);
+	uint16_t rbufsz, xfer;
+	const int logprio = port->logprio;
+	const char * const repr = port->repr;
+	const int fd = cgpu->device->device_fd;
+	
+	rbufsz = 1;
+	if (!bitfury_do_packet(logprio, repr, fd, rdbuf, &rbufsz, LFOP_SPI, NULL, 0))
+		return false;
+	
+	while (bufsz)
+	{
+		xfer = (bufsz > 1024) ? 1024 : bufsz;
+		rbufsz = xfer;
+		if (!bitfury_do_packet(logprio, repr, fd, rdbuf, &rbufsz, LFOP_SPI, wrbuf, xfer))
+			return false;
+		if (rbufsz < xfer)
+		{
+			applog(port->logprio, "%s: SPI: Got fewer bytes back than sent (%d < %d)",
+			       repr, rbufsz, xfer);
+			return false;
+		}
+		bufsz -= xfer;
+		rdbuf += xfer;
+		wrbuf += xfer;
+	}
+	
+	return true;
+}
+
+static
+bool littlefury_detect_one(const char *devpath)
+{
+	int fd, chips;
+	uint8_t buf[255];
+	uint16_t bufsz;
+	struct spi_port spi;
+	struct cgpu_info dummy;
+	char *devname;
+	
+	fd = serial_open(devpath, 0, 10, true);
+	applog(LOG_DEBUG, "%s: %s %s",
+	       littlefury_drv.dname,
+	       ((fd == -1) ? "Failed to open" : "Successfully opened"),
+	       devpath);
+	
+	if (unlikely(fd == -1))
+		goto err;
+	
+	bufsz = sizeof(buf);
+	if (!bitfury_do_packet(LOG_DEBUG, littlefury_drv.dname, fd, buf, &bufsz, LFOP_VERSION, NULL, 0))
+		goto err;
+	
+	if (bufsz < 4)
+	{
+		applog(LOG_DEBUG, "%s: Incomplete version response", littlefury_drv.dname);
+		goto err;
+	}
+	
+	devname = malloc(bufsz - 3);
+	memcpy(devname, (char*)&buf[4], bufsz - 4);
+	devname[bufsz - 4] = '\0';
+	applog(LOG_DEBUG, "%s: Identified %s %d.%d.%d (features %02x)",
+	       littlefury_drv.dname, devname, buf[0], buf[1], buf[2], buf[3]);
+	
+	bufsz = sizeof(buf);
+	if (!(bitfury_do_packet(LOG_DEBUG, littlefury_drv.dname, fd, buf, &bufsz, LFOP_REGPWR, "\1", 1) && bufsz && buf[0]))
+		applog(LOG_WARNING, "%s: Unable to power on chip(s) for %s",
+		       littlefury_drv.dname, devpath);
+	
+	dummy.device = &dummy;
+	dummy.device_fd = fd;
+	spi = (struct spi_port){
+		.txrx = littlefury_txrx,
+		.cgpu = &dummy,
+		.repr = littlefury_drv.dname,
+		.logprio = LOG_DEBUG,
+	};
+	
+	chips = libbitfury_detectChips1(&spi);
+	if (!chips) {
+		applog(LOG_WARNING, "%s: No Bitfury chips detected on %s",
+		       littlefury_drv.dname, devpath);
+		free(devname);
+		goto err;
+	} else {
+		applog(LOG_DEBUG, "%s: %d chips detected",
+		       littlefury_drv.dname, chips);
+	}
+	
+	bufsz = sizeof(buf);
+	bitfury_do_packet(LOG_DEBUG, littlefury_drv.dname, fd, buf, &bufsz, LFOP_REGPWR, "\0", 1);
+	
+	serial_close(fd);
+	
+	struct cgpu_info *cgpu;
+	cgpu = malloc(sizeof(*cgpu));
+	*cgpu = (struct cgpu_info){
+		.drv = &littlefury_drv,
+		.device_path = strdup(devpath),
+		.device_fd = -1,
+		.deven = DEV_ENABLED,
+		.procs = chips,
+		.threads = 1,
+		.name = devname,
+		.cutofftemp = 85,
+	};
+	
+	return add_cgpu(cgpu);
+
+err:
+	return false;
+}
+
+static
+int littlefury_detect_auto(void)
+{
+	return serial_autodetect(littlefury_detect_one, "LittleFury");
+}
+
+static
+void littlefury_detect(void)
+{
+	serial_detect_auto(&littlefury_drv, littlefury_detect_one, littlefury_detect_auto);
+}
+
+static
+bool littlefury_thread_init(struct thr_info *thr)
+{
+	struct cgpu_info * const cgpu = thr->cgpu;
+	struct cgpu_info *proc;
+	struct spi_port *spi;
+	struct bitfury_device *bitfury;
+	uint8_t buf[1];
+	uint16_t bufsz = 1;
+	int fd;
+	int i = 0;
+	
+	for (proc = cgpu; proc; proc = proc->next_proc)
+	{
+		spi = malloc(sizeof(*spi));
+		*spi = (struct spi_port){
+			.txrx = littlefury_txrx,
+			.cgpu = proc,
+			.repr = proc->proc_repr,
+			.logprio = LOG_ERR,
+		};
+		
+		bitfury = malloc(sizeof(*bitfury));
+		*bitfury = (struct bitfury_device){
+			.spi = spi,
+			.fasync = i++,
+		};
+		
+		proc->device_data = bitfury;
+	}
+	
+	fd = cgpu->device_fd = serial_open(cgpu->device_path, 0, 10, true);
+	if (unlikely(fd == -1))
+	{
+		applog(LOG_DEBUG, "%s: %s %s",
+		       cgpu->dev_repr, "Failed to open", cgpu->device_path);
+		return true;
+	}
+	
+	if (!(bitfury_do_packet(LOG_DEBUG, littlefury_drv.dname, fd, buf, &bufsz, LFOP_REGPWR, "\1", 1) && bufsz && buf[0]))
+		applog(LOG_WARNING, "%s: Unable to power on chip(s)", cgpu->dev_repr);
+	
+	return true;
+}
+
+static
+bool littlefury_do_io(struct thr_info *thr)
+{
+	struct cgpu_info * const proc = thr->cgpu;
+	struct bitfury_device * const bitfury = proc->device_data;
+	bitfury->results_n = 0;
+	libbitfury_sendHashData1(proc->proc_id, bitfury, thr);
+	if (bitfury->job_switched && thr->next_work)
+	{
+		mt_job_transition(thr);
+		// TODO: Delay morework until right before it's needed
+		timer_set_now(&thr->tv_morework);
+		job_start_complete(thr);
+	}
+	if (thr->work && bitfury->results_n)
+		for (int i = bitfury->results_n; i--; )
+			submit_nonce(thr, thr->work, be32toh(bitfury->results[i]));
+	timer_set_delay_from_now(&thr->tv_poll, 10000);
+	return true;
+}
+
+static
+void littlefury_poll(struct thr_info *thr)
+{
+	littlefury_do_io(thr);
+}
+
+static
+bool littlefury_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused uint64_t max_nonce)
+{
+	struct bitfury_device * const bitfury = thr->cgpu->device_data;
+	work_to_payload(&bitfury->payload, thr->next_work);
+	payload_to_atrvec(bitfury->atrvec, &bitfury->payload);
+	return true;
+}
+
+static
+void littlefury_job_start(struct thr_info *thr)
+{
+	littlefury_do_io(thr);
+}
+
+static
+int64_t littlefury_job_process_results(struct thr_info *thr, struct work *work, bool stopping)
+{
+	if (unlikely(stopping))
+		timer_unset(&thr->tv_poll);
+	return 0x100000000;
+}
+
+static void littlefury_shutdown(struct thr_info *thr)
+{
+	struct cgpu_info * const cgpu = thr->cgpu;
+	const int fd = cgpu->device->device_fd;
+	uint8_t buf[1];
+	uint16_t bufsz = 1;
+	
+	bitfury_shutdown(thr);
+	if (!(bitfury_do_packet(LOG_DEBUG, cgpu->dev_repr, fd, buf, &bufsz, LFOP_REGPWR, "\0", 1) && bufsz && !buf[0]))
+		applog(LOG_WARNING, "%s: Unable to power off chip(s)", cgpu->dev_repr);
+}
+
+struct device_drv littlefury_drv = {
+	.dname = "littlefury",
+	.name = "LFY",
+	.drv_detect = littlefury_detect,
+	
+	.minerloop = minerloop_async,
+	.thread_init = littlefury_thread_init,
+	.job_prepare = littlefury_job_prepare,
+	.job_start = littlefury_job_start,
+	.poll = littlefury_poll,
+	.job_process_results = littlefury_job_process_results,
+	
+	.minerloop = hash_queued_work,
+	.thread_init = littlefury_thread_init,
+	.scanwork = bitfury_scanHash,
+	.thread_shutdown = littlefury_shutdown,
+};

+ 244 - 0
driver-metabank.c

@@ -0,0 +1,244 @@
+/*
+ * Copyright 2013 bitfury
+ * Copyright 2013 legkodymov
+ * Copyright 2013 Luke Dashjr
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "deviceapi.h"
+#include "driver-bitfury.h"
+#include "libbitfury.h"
+#include "spidevc.h"
+#include "tm_i2c.h"
+
+struct device_drv metabank_drv;
+
+static
+bool metabank_spi_txrx(struct spi_port *port)
+{
+	static int current_slot = -1;
+	struct cgpu_info * const proc = port->cgpu;
+	struct bitfury_device * const bitfury = proc->device_data;
+	
+	if (current_slot != bitfury->slot)
+	{
+		if (current_slot != -1)
+			tm_i2c_clear_oe(current_slot);
+		tm_i2c_set_oe(bitfury->slot);
+		current_slot = bitfury->slot;
+	}
+	
+	const bool rv = sys_spi_txrx(port);
+	return rv;
+}
+
+static
+int metabank_autodetect()
+{
+	RUNONCE(0);
+	
+	struct cgpu_info *cgpu = NULL, *proc1 = NULL, *prev_cgpu = NULL;
+	struct bitfury_device **devicelist, *bitfury;
+	struct spi_port *port;
+	int i, j;
+	int proc_count = 0;
+	bool slot_on[32];
+	struct bitfury_device dummy_bitfury;
+	struct cgpu_info dummy_cgpu;
+	
+	applog(LOG_INFO, "INFO: bitfury_detect");
+	spi_init();
+	if (!sys_spi)
+		return 0;
+	
+	if (tm_i2c_init() < 0) {
+		applog(LOG_DEBUG, "%s: I2C init error", metabank_drv.dname);
+		return 0;
+	}
+	
+	dummy_cgpu.device_data = &dummy_bitfury;
+	
+	for (i = 0; i < 32; i++) {
+		slot_on[i] = 0;
+	}
+	for (i = 0; i < 32; i++) {
+		int slot_detected = tm_i2c_detect(i) != -1;
+		slot_on[i] = slot_detected;
+		tm_i2c_clear_oe(i);
+		cgsleep_ms(1);
+	}
+
+	for (i = 0; i < 32; i++) {
+		if (slot_on[i]) {
+			int chip_n;
+			
+			port = malloc(sizeof(*port));
+			*port = *sys_spi;
+			port->cgpu = &dummy_cgpu;
+			port->txrx = metabank_spi_txrx;
+			dummy_bitfury.slot = i;
+			
+			chip_n = libbitfury_detectChips1(port);
+			if (chip_n)
+			{
+				applog(LOG_WARNING, "BITFURY slot %d: %d chips detected", i, chip_n);
+				
+				devicelist = malloc(sizeof(*devicelist) * chip_n);
+				for (j = 0; j < chip_n; ++j)
+				{
+					devicelist[j] = bitfury = malloc(sizeof(*bitfury));
+					*bitfury = (struct bitfury_device){
+						.spi = port,
+						.slot = i,
+						.fasync = j,
+					};
+				}
+				
+				cgpu = malloc(sizeof(*cgpu));
+				*cgpu = (struct cgpu_info){
+					.drv = &metabank_drv,
+					.procs = chip_n,
+					.device_data = devicelist,
+					.cutofftemp = 50,
+				};
+				add_cgpu_slave(cgpu, prev_cgpu);
+				
+				proc_count += chip_n;
+				if (!proc1)
+					proc1 = cgpu;
+				prev_cgpu = cgpu;
+			}
+			else
+				free(port);
+		}
+	}
+	
+	if (proc1)
+		proc1->threads = 1;
+	
+	return proc_count;
+}
+
+static void metabank_detect(void)
+{
+	noserial_detect_manual(&metabank_drv, metabank_autodetect);
+}
+
+static
+bool metabank_init(struct thr_info *thr)
+{
+	struct bitfury_device **devicelist;
+	struct cgpu_info *proc;
+	struct bitfury_device *bitfury;
+	
+	for (proc = thr->cgpu; proc; proc = proc->next_proc)
+	{
+		devicelist = proc->device_data;
+		bitfury = devicelist[proc->proc_id];
+		proc->device_data = bitfury;
+		bitfury->spi->cgpu = proc;
+		bitfury_init_chip(proc);
+		bitfury->osc6_bits = 54;
+		send_reinit(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
+		
+		if (proc->proc_id == proc->procs - 1)
+			free(devicelist);
+	}
+	
+	timer_set_now(&thr->tv_poll);
+	
+	return true;
+}
+
+static void metabank_shutdown(struct thr_info *thr)
+{
+	bitfury_shutdown(thr);
+	tm_i2c_close();
+}
+
+static bool metabank_get_stats(struct cgpu_info *cgpu)
+{
+	struct bitfury_device * const bitfury = cgpu->device_data;
+	float t;
+
+	t = tm_i2c_gettemp(bitfury->slot) * 0.1;
+
+	if (t < -27) //Sometimes tm_i2c_gettemp() returns strange result, ignoring it.
+		return false;
+
+	cgpu->temp = t;
+
+	return true;
+}
+
+static struct api_data *metabank_api_extra_device_detail(struct cgpu_info *cgpu)
+{
+	struct api_data *root = NULL;
+	struct bitfury_device * const bitfury = cgpu->device_data;
+	
+	root = bitfury_api_device_detail(cgpu);
+
+	root = api_add_uint(root, "Slot", &(bitfury->slot), false);
+
+	return root;
+}
+
+static struct api_data *metabank_api_extra_device_status(struct cgpu_info *cgpu)
+{
+	struct api_data *root = NULL;
+	float vc0, vc1;
+	struct bitfury_device * const bitfury = cgpu->device_data;
+	
+	root = bitfury_api_device_status(cgpu);
+
+	vc0 = tm_i2c_getcore0(bitfury->slot);
+	vc1 = tm_i2c_getcore1(bitfury->slot);
+
+	root = api_add_volts(root, "Slot VC0", &vc0, true);
+	root = api_add_volts(root, "Slot VC1", &vc1, true);
+
+	return root;
+}
+
+struct device_drv metabank_drv = {
+	.dname = "metabank",
+	.name = "MBF",
+	.drv_detect = metabank_detect,
+	.thread_init = metabank_init,
+	
+#if 0
+	.minerloop = hash_queued_work,
+	.thread_prepare = bitfury_prepare,
+	.scanwork = bitfury_scanHash,
+#endif
+	.minerloop = minerloop_async,
+	.job_prepare = bitfury_job_prepare,
+	.job_start = bitfury_noop_job_start,
+	.poll = bitfury_do_io,
+	.job_process_results = bitfury_job_process_results,
+	
+	.thread_shutdown = metabank_shutdown,
+	.get_api_extra_device_detail = metabank_api_extra_device_detail,
+	.get_api_extra_device_status = metabank_api_extra_device_status,
+	.get_stats = metabank_get_stats,
+	.set_device = bitfury_set_device,
+};

+ 615 - 0
libbitfury.c

@@ -0,0 +1,615 @@
+/*
+ * Copyright 2013 bitfury
+ * Copyright 2013 legkodymov
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "logging.h"
+#include "miner.h"
+#include "libbitfury.h"
+
+#include "spidevc.h"
+#include "sha2.h"
+
+#include <time.h>
+
+#define BITFURY_REFRESH_DELAY 100
+#define BITFURY_DETECT_TRIES 3000 / BITFURY_REFRESH_DELAY
+
+unsigned bitfury_decnonce(unsigned in);
+
+/* Configuration registers - control oscillators and such stuff. PROGRAMMED when magic number is matches, UNPROGRAMMED (default) otherwise */
+void config_reg(struct spi_port *port, int cfgreg, int ena)
+{
+	static const uint8_t enaconf[4] = { 0xc1, 0x6a, 0x59, 0xe3 };
+	static const uint8_t disconf[4] = { 0, 0, 0, 0 };
+	
+	if (ena) spi_emit_data(port, 0x7000+cfgreg*32, enaconf, 4);
+	else     spi_emit_data(port, 0x7000+cfgreg*32, disconf, 4);
+}
+
+#define FIRST_BASE 61
+#define SECOND_BASE 4
+const int8_t counters[16] = { 64, 64,
+	SECOND_BASE, SECOND_BASE+4, SECOND_BASE+2, SECOND_BASE+2+16, SECOND_BASE, SECOND_BASE+1,
+	(FIRST_BASE)%65,  (FIRST_BASE+1)%65,  (FIRST_BASE+3)%65, (FIRST_BASE+3+16)%65, (FIRST_BASE+4)%65, (FIRST_BASE+4+4)%65, (FIRST_BASE+3+3)%65, (FIRST_BASE+3+1+3)%65};
+
+//char counters[16] = { 64, 64,
+//	SECOND_BASE, SECOND_BASE+4, SECOND_BASE+2, SECOND_BASE+2+16, SECOND_BASE, SECOND_BASE+1,
+//	(FIRST_BASE)%65,  (FIRST_BASE+1)%65,  (FIRST_BASE+3)%65, (FIRST_BASE+3+16)%65, (FIRST_BASE+4)%65, (FIRST_BASE+4+4)%65, (FIRST_BASE+3+3)%65, (FIRST_BASE+3+1+3)%65};
+
+/* Oscillator setup variants (maybe more), values inside of chip ANDed to not allow by programming errors work it at higher speeds  */
+/* WARNING! no chip temperature control limits, etc. It may self-fry and make fried chips with great ease :-) So if trying to overclock */
+/* Do not place chip near flammable objects, provide adequate power protection and better wear eye protection ! */
+/* Thermal runaway in this case could produce nice flames of chippy fries */
+
+// Thermometer code from left to right - more ones ==> faster clock!
+
+#define rotrFixed(x,y) (((x) >> (y)) | ((x) << (32-(y))))
+#define s0(x) (rotrFixed(x,7)^rotrFixed(x,18)^(x>>3))
+#define s1(x) (rotrFixed(x,17)^rotrFixed(x,19)^(x>>10))
+#define Ch(x,y,z) (z^(x&(y^z)))
+#define Maj(x,y,z) (y^((x^y)&(y^z)))
+#define S0(x) (rotrFixed(x,2)^rotrFixed(x,13)^rotrFixed(x,22))
+#define S1(x) (rotrFixed(x,6)^rotrFixed(x,11)^rotrFixed(x,25))
+
+/* SHA256 CONSTANTS */
+static const unsigned SHA_K[64] = {
+        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+
+
+void ms3_compute(unsigned *p)
+{
+	unsigned a,b,c,d,e,f,g,h, ne, na,  i;
+
+	a = p[0]; b = p[1]; c = p[2]; d = p[3]; e = p[4]; f = p[5]; g = p[6]; h = p[7];
+
+	for (i = 0; i < 3; i++) {
+		ne = p[i+16] + SHA_K[i] + h + Ch(e,f,g) + S1(e) + d;
+		na = p[i+16] + SHA_K[i] + h + Ch(e,f,g) + S1(e) + S0(a) + Maj(a,b,c);
+		d = c; c = b; b = a; a = na;
+		h = g; g = f; f = e; e = ne;
+	}
+
+	p[15] = a; p[14] = b; p[13] = c; p[12] = d; p[11] = e; p[10] = f; p[9] = g; p[8] = h;
+}
+
+void send_conf(struct spi_port *port) {
+	int i;
+	for (i = 7; i <= 11; ++i)
+		config_reg(port, i, 0);
+	config_reg(port, 6, 0); /* disable OUTSLK */
+	config_reg(port, 4, 1); /* Enable slow oscillator */
+	for (i = 1; i <= 3; ++i)
+		config_reg(port, i, 0);
+	spi_emit_data(port, 0x0100, counters, 16); /* Program counters correctly for rounds processing, here baby should start consuming power */
+}
+
+void send_init(struct spi_port *port) {
+	/* Prepare internal buffers */
+	/* PREPARE BUFFERS (INITIAL PROGRAMMING) */
+	unsigned w[16];
+	unsigned atrvec[] = {
+		0xb0e72d8e, 0x1dc5b862, 0xe9e7c4a6, 0x3050f1f5, 0x8a1a6b7e, 0x7ec384e8, 0x42c1c3fc, 0x8ed158a1, /* MIDSTATE */
+		0,0,0,0,0,0,0,0,
+		0x8a0bb7b7, 0x33af304f, 0x0b290c1a, 0xf0c4e61f, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+	};
+
+	ms3_compute(&atrvec[0]);
+	memset(&w, 0, sizeof(w)); w[3] = 0xffffffff; w[4] = 0x80000000; w[15] = 0x00000280;
+	spi_emit_data(port, 0x1000, w, 16*4);
+	spi_emit_data(port, 0x1400, w,  8*4);
+	memset(w, 0, sizeof(w)); w[0] = 0x80000000; w[7] = 0x100;
+	spi_emit_data(port, 0x1900, &w[0],8*4); /* Prepare MS and W buffers! */
+	spi_emit_data(port, 0x3000, &atrvec[0], 19*4);
+}
+
+void set_freq(struct spi_port *port, int bits) {
+	uint64_t freq;
+	const uint8_t *
+	osc6 = (unsigned char *)&freq;
+	freq = (1ULL << bits) - 1ULL;
+
+	spi_emit_data(port, 0x6000, osc6, 8); /* Program internal on-die slow oscillator frequency */
+	config_reg(port, 4, 1); /* Enable slow oscillator */
+}
+
+void send_reinit(struct spi_port *port, int slot, int chip_n, int n) {
+	spi_clear_buf(port);
+	spi_emit_break(port);
+	spi_emit_fasync(port, chip_n);
+	set_freq(port, n);
+	send_conf(port);
+	send_init(port);
+	spi_txrx(port);
+}
+
+void send_shutdown(struct spi_port *port, int slot, int chip_n) {
+	spi_clear_buf(port);
+	spi_emit_break(port);
+	spi_emit_fasync(port, chip_n);
+	config_reg(port, 4, 0); /* Disable slow oscillator */
+	spi_txrx(port);
+}
+
+void send_freq(struct spi_port *port, int slot, int chip_n, int bits) {
+	spi_clear_buf(port);
+	spi_emit_break(port);
+	spi_emit_fasync(port, chip_n);
+	set_freq(port, bits);
+	spi_txrx(port);
+}
+
+unsigned int c_diff(unsigned ocounter, unsigned counter) {
+	return counter >  ocounter ? counter - ocounter : (0x003FFFFF - ocounter) + counter;
+}
+
+int get_counter(unsigned int *newbuf, unsigned int *oldbuf) {
+	int j;
+	for(j = 0; j < 16; j++) {
+		if (newbuf[j] != oldbuf[j]) {
+			unsigned counter = bitfury_decnonce(newbuf[j]);
+			if ((counter & 0xFFC00000) == 0xdf800000) {
+				counter -= 0xdf800000;
+				return counter;
+			}
+		}
+	}
+	return 0;
+}
+
+int get_diff(unsigned int *newbuf, unsigned int *oldbuf) {
+		int j;
+		unsigned counter = 0;
+		for(j = 0; j < 16; j++) {
+				if (newbuf[j] != oldbuf[j]) {
+						counter++;
+				}
+		}
+		return counter;
+}
+
+int detect_chip(struct spi_port *port, int chip_n) {
+	/* Test vectors to calculate (using address-translated loads) */
+	unsigned atrvec[] = {
+		0xb0e72d8e, 0x1dc5b862, 0xe9e7c4a6, 0x3050f1f5, 0x8a1a6b7e, 0x7ec384e8, 0x42c1c3fc, 0x8ed158a1, /* MIDSTATE */
+		0,0,0,0,0,0,0,0,
+		0x8a0bb7b7, 0x33af304f, 0x0b290c1a, 0xf0c4e61f, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+		
+		0x9c4dfdc0, 0xf055c9e1, 0xe60f079d, 0xeeada6da, 0xd459883d, 0xd8049a9d, 0xd49f9a96, 0x15972fed, /* MIDSTATE */
+		0,0,0,0,0,0,0,0,
+		0x048b2528, 0x7acb2d4f, 0x0b290c1a, 0xbe00084a, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+		
+		0x0317b3ea, 0x1d227d06, 0x3cca281e, 0xa6d0b9da, 0x1a359fe2, 0xa7287e27, 0x8b79c296, 0xc4d88274, /* MIDSTATE */
+		0,0,0,0,0,0,0,0,
+		0x328bcd4f, 0x75462d4f, 0x0b290c1a, 0x002c6dbc, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+		
+		0xac4e38b6, 0xba0e3b3b, 0x649ad6f8, 0xf72e4c02, 0x93be06fb, 0x366d1126, 0xf4aae554, 0x4ff19c5b, /* MIDSTATE */
+		0,0,0,0,0,0,0,0,
+		0x72698140, 0x3bd62b4f, 0x3fd40c1a, 0x801e43e9, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+		
+		0x9dbf91c9, 0x12e5066c, 0xf4184b87, 0x8060bc4d, 0x18f9c115, 0xf589d551, 0x0f7f18ae, 0x885aca59, /* MIDSTATE */
+		0,0,0,0,0,0,0,0,
+		0x6f3806c3, 0x41f82a4f, 0x3fd40c1a, 0x00334b39, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+	};
+	int i;
+	unsigned newbuf[17], oldbuf[17];
+	unsigned ocounter;
+	int odiff = 0;
+
+	memset(newbuf, 0, 17 * 4);
+	memset(oldbuf, 0, 17 * 4);
+
+	ms3_compute(&atrvec[0]);
+	ms3_compute(&atrvec[20]);
+	ms3_compute(&atrvec[40]);
+
+
+	spi_clear_buf(port);
+	spi_emit_break(port); /* First we want to break chain! Otherwise we'll get all of traffic bounced to output */
+	spi_emit_fasync(port, chip_n);
+	set_freq(port, 52);  //54 - 3F, 53 - 1F
+	send_conf(port);
+	send_init(port);
+	spi_txrx(port);
+
+	ocounter = 0;
+	for (i = 0; i < BITFURY_DETECT_TRIES; i++) {
+		int counter;
+
+		spi_clear_buf(port);
+		spi_emit_break(port);
+		spi_emit_fasync(port, chip_n);
+		spi_emit_data(port, 0x3000, &atrvec[0], 19*4);
+		spi_txrx(port);
+		memcpy(newbuf, spi_getrxbuf(port) + 4 + chip_n, 17*4);
+
+		counter = get_counter(newbuf, oldbuf);
+		if (ocounter) {
+			unsigned int cdiff = c_diff(ocounter, counter);
+
+			if (cdiff > 5000 && cdiff < 100000 && odiff > 5000 && odiff < 100000)
+				return 1;
+			odiff = cdiff;
+		}
+		ocounter = counter;
+		if (newbuf[16] != 0 && newbuf[16] != 0xFFFFFFFF) {
+			return 0;
+		}
+		cgsleep_ms(BITFURY_REFRESH_DELAY / 10);
+		memcpy(oldbuf, newbuf, 17 * 4);
+	}
+	return 0;
+}
+
+int libbitfury_detectChips1(struct spi_port *port) {
+	int n;
+	for (n = 0; detect_chip(port, n); ++n)
+	{}
+	return n;
+}
+
+// in  = 1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10  f  e  d  c  b  a  9  8  7  6  5  4  3  2  1  0
+unsigned bitfury_decnonce(unsigned in)
+{
+	unsigned out;
+
+	/* First part load */
+	out = (in & 0xFF) << 24; in >>= 8;
+
+	/* Byte reversal */
+	in = (((in & 0xaaaaaaaa) >> 1) | ((in & 0x55555555) << 1));
+	in = (((in & 0xcccccccc) >> 2) | ((in & 0x33333333) << 2));
+	in = (((in & 0xf0f0f0f0) >> 4) | ((in & 0x0f0f0f0f) << 4));
+
+	out |= (in >> 2)&0x3FFFFF;
+
+	/* Extraction */
+	if (in & 1) out |= (1 << 23);
+	if (in & 2) out |= (1 << 22);
+// out =  7  6  5  4  3  2  1  0  f  e 18 19 1a 1b 1c 1d 1e 1f 10 11 12 13 14 15 16 17  8  9  a  b  c  d
+
+	out -= 0x800004;
+	return out;
+}
+
+int rehash(const void *midstate, const uint32_t m7, const uint32_t ntime, const uint32_t nbits, uint32_t nnonce) {
+	unsigned char in[16];
+	unsigned int *in32 = (unsigned int *)in;
+	unsigned int *mid32 = (unsigned int *)midstate;
+	unsigned out32[8];
+	unsigned char *out = (unsigned char *) out32;
+#ifdef BITFURY_REHASH_DEBUG
+	static unsigned history[512];
+	static unsigned history_p;
+#endif
+	sha256_ctx ctx;
+
+
+	memset( &ctx, 0, sizeof( sha256_ctx ) );
+	memcpy(ctx.h, mid32, 8*4);
+	ctx.tot_len = 64;
+	ctx.len = 0;
+
+	nnonce = bswap_32(nnonce);
+	in32[0] = bswap_32(m7);
+	in32[1] = bswap_32(ntime);
+	in32[2] = bswap_32(nbits);
+	in32[3] = nnonce;
+
+	sha256_update(&ctx, in, 16);
+	sha256_final(&ctx, out);
+	sha256(out, 32, out);
+
+	if (out32[7] == 0) {
+#ifdef BITFURY_REHASH_DEBUG
+		char hex[65];
+		bin2hex(hex, out, 32);
+		applog(LOG_INFO, "! MS0: %08x, m7: %08x, ntime: %08x, nbits: %08x, nnonce: %08x", mid32[0], m7, ntime, nbits, nnonce);
+		applog(LOG_INFO, " out: %s", hex);
+		history[history_p] = nnonce;
+		history_p++; history_p &= 512 - 1;
+#endif
+		return 1;
+	}
+	return 0;
+}
+
+bool bitfury_fudge_nonce(const void *midstate, const uint32_t m7, const uint32_t ntime, const uint32_t nbits, uint32_t *nonce_p) {
+	static const uint32_t offsets[] = {0, 0xffc00000, 0xff800000, 0x02800000, 0x02C00000, 0x00400000};
+	uint32_t nonce;
+	int i;
+	
+	for (i = 0; i < 6; ++i)
+	{
+		nonce = *nonce_p + offsets[i];
+		if (rehash(midstate, m7, ntime, nbits, nonce))
+		{
+			*nonce_p = nonce;
+			return true;
+		}
+	}
+	return false;
+}
+
+void work_to_payload(struct bitfury_payload *p, struct work *w) {
+	unsigned char flipped_data[80];
+
+	memset(p, 0, sizeof(struct bitfury_payload));
+	swap32yes(flipped_data, w->data, 80 / 4);
+
+	memcpy(p->midstate, w->midstate, 32);
+	p->m7 = bswap_32(*(unsigned *)(flipped_data + 64));
+	p->ntime = bswap_32(*(unsigned *)(flipped_data + 68));
+	p->nbits = bswap_32(*(unsigned *)(flipped_data + 72));
+}
+
+void payload_to_atrvec(uint32_t *atrvec, struct bitfury_payload *p)
+{
+	/* Programming next value */
+	memcpy(atrvec, p, 20*4);
+	ms3_compute(atrvec);
+}
+
+void libbitfury_sendHashData1(int chip_id, struct bitfury_device *d, struct thr_info *thr)
+{
+	struct spi_port *port = d->spi;
+	unsigned *newbuf = d->newbuf;
+	unsigned *oldbuf = d->oldbuf;
+	struct bitfury_payload *p = &(d->payload);
+	struct bitfury_payload *op = &(d->opayload);
+	struct bitfury_payload *o2p = &(d->o2payload);
+	struct timeval d_time;
+	struct timeval time;
+	int smart = 0;
+	int chip = d->fasync;
+	int buf_diff;
+
+	timer_set_now(&time);
+
+	if (!d->second_run) {
+		d->predict2 = d->predict1 = time;
+		d->counter1 = d->counter2 = 0;
+		d->req2_done = 0;
+	};
+
+	timersub(&time, &d->predict1, &d_time);
+	if (d_time.tv_sec < 0 && (d->req2_done || !smart)) {
+		d->otimer1 = d->timer1;
+		d->timer1 = time;
+		d->ocounter1 = d->counter1;
+		/* Programming next value */
+		spi_clear_buf(port);
+		spi_emit_break(port);
+		spi_emit_fasync(port, chip);
+		spi_emit_data(port, 0x3000, &d->atrvec[0], 19*4);
+		if (smart) {
+			config_reg(port, 3, 0);
+		}
+		timer_set_now(&time);
+		timersub(&time, &d->predict1, &d_time);
+		spi_txrx(port);
+		memcpy(newbuf, spi_getrxbuf(port)+4 + chip, 17*4);
+		d->counter1 = get_counter(newbuf, oldbuf);
+		buf_diff = get_diff(newbuf, oldbuf);
+		if (buf_diff > 4 || (d->counter1 > 0 && d->counter1 < 0x00400000 / 2)) {
+			if (buf_diff > 4) {
+#ifdef BITFURY_SENDHASHDATA_DEBUG
+				applog(LOG_DEBUG, "AAA        chip_id: %d, buf_diff: %d, counter: %08x", chip_id, buf_diff, d->counter1);
+#endif
+				payload_to_atrvec(&d->atrvec[0], p);
+				spi_clear_buf(port);
+				spi_emit_break(port);
+				spi_emit_fasync(port, chip);
+				spi_emit_data(port, 0x3000, &d->atrvec[0], 19*4);
+				timer_set_now(&time);
+				timersub(&time, &d->predict1, &d_time);
+				spi_txrx(port);
+				memcpy(newbuf, spi_getrxbuf(port)+4 + chip, 17*4);
+				buf_diff = get_diff(newbuf, oldbuf);
+				d->counter1 = get_counter(newbuf, oldbuf);
+#ifdef BITFURY_SENDHASHDATA_DEBUG
+				applog(LOG_DEBUG, "AAA _222__ chip_id: %d, buf_diff: %d, counter: %08x", chip_id, buf_diff, d->counter1);
+#endif
+			}
+		}
+
+		d->job_switched = newbuf[16] != oldbuf[16];
+
+		int i;
+		int results_num = 0;
+		int found = 0;
+		unsigned * results = d->results;
+
+		d->old_nonce = 0;
+		d->future_nonce = 0;
+		for (i = 0; i < 16; i++) {
+			if (oldbuf[i] != newbuf[i] && op && o2p) {
+				uint32_t pn;  // possible nonce
+				if ((newbuf[i] & 0xFF) == 0xE0)
+					continue;
+				pn = bitfury_decnonce(newbuf[i]);
+				if (bitfury_fudge_nonce(op->midstate, op->m7, op->ntime, op->nbits, &pn))
+				{
+					int k;
+					int dup = 0;
+					for (k = 0; k < results_num; k++) {
+						if (results[k] == bswap_32(pn))
+							dup = 1;
+					}
+					if (!dup) {
+						results[results_num++] = bswap_32(pn);
+						found++;
+					}
+				}
+				else
+				if (bitfury_fudge_nonce(o2p->midstate, o2p->m7, o2p->ntime, o2p->nbits, &pn))
+				{
+					d->old_nonce = bswap_32(pn);
+					found++;
+				}
+				else
+				if (bitfury_fudge_nonce(p->midstate, p->m7, p->ntime, p->nbits, &pn))
+				{
+					d->future_nonce = bswap_32(pn);
+					found++;
+				}
+				if (!found) {
+					inc_hw_errors2(thr, NULL, &pn);
+					d->strange_counter++;
+				}
+			}
+		}
+		d->results_n = results_num;
+
+		if (smart) {
+			timersub(&d->timer2, &d->timer1, &d_time);
+		} else {
+			timersub(&d->otimer1, &d->timer1, &d_time);
+		}
+		d->counter1 = get_counter(newbuf, oldbuf);
+		if (d->counter2 || !smart) {
+			int shift;
+			int cycles;
+			int req1_cycles;
+			long long unsigned int period;
+			double ns;
+			unsigned full_cycles, half_cycles;
+			double full_delay, half_delay;
+			long long unsigned delta;
+			struct timeval t_delta;
+			double mhz;
+#ifdef BITFURY_SENDHASHDATA_DEBUG
+			int ccase;
+#endif
+
+			shift = 800000;
+			if (smart) {
+				cycles = d->counter1 < d->counter2 ? 0x00400000 - d->counter2 + d->counter1 : d->counter1 - d->counter2; // + 0x003FFFFF;
+			} else {
+				if (d->counter1 > (0x00400000 - shift * 2) && d->ocounter1 > (0x00400000 - shift)) {
+					cycles = 0x00400000 - d->ocounter1 + d->counter1; // + 0x003FFFFF;
+#ifdef BITFURY_SENDHASHDATA_DEBUG
+					ccase = 1;
+#endif
+				} else {
+					cycles = d->counter1 > d->ocounter1 ? d->counter1 - d->ocounter1 : 0x00400000 - d->ocounter1 + d->counter1;
+#ifdef BITFURY_SENDHASHDATA_DEBUG
+					ccase = 2;
+#endif
+				}
+			}
+			req1_cycles = 0x003FFFFF - d->counter1;
+			period = timeval_to_us(&d_time) * 1000ULL;
+			ns = (double)period / (double)(cycles);
+			mhz = 1.0 / ns * 65.0 * 1000.0;
+
+#ifdef BITFURY_SENDHASHDATA_DEBUG
+			if (d->counter1 > 0 && d->counter1 < 0x001FFFFF) {
+				applog(LOG_DEBUG, "//AAA chip_id %2d: %llu ms, req1_cycles: %08u,  counter1: %08d, ocounter1: %08d, counter2: %08d, cycles: %08d, ns: %.2f, mhz: %.2f ", chip_id, period / 1000000ULL, req1_cycles, d->counter1, d->ocounter1, d->counter2, cycles, ns, mhz);
+			}
+#endif
+			if (ns > 2000.0 || ns < 20) {
+#ifdef BITFURY_SENDHASHDATA_DEBUG
+				applog(LOG_DEBUG, "AAA %d!Stupid ns chip_id %2d: %llu ms, req1_cycles: %08u,  counter1: %08d, ocounter1: %08d, counter2: %08d, cycles: %08d, ns: %.2f, mhz: %.2f ", ccase, chip_id, period / 1000000ULL, req1_cycles, d->counter1, d->ocounter1, d->counter2, cycles, ns, mhz);
+#endif
+				ns = 200.0;
+			} else {
+				d->ns = ns;
+				d->mhz = mhz;
+			}
+
+			if (smart) {
+				half_cycles = req1_cycles + shift;
+				full_cycles = 0x003FFFFF - 2 * shift;
+			} else {
+				half_cycles = 0;
+				full_cycles = req1_cycles > shift ? req1_cycles - shift : req1_cycles + 0x00400000 - shift;
+			}
+			half_delay = (double)half_cycles * ns * (1 +0.92);
+			full_delay = (double)full_cycles * ns;
+			delta = (long long unsigned)(full_delay + half_delay);
+			t_delta = TIMEVAL_USECS(delta / 1000ULL);
+			timeradd(&time, &t_delta, &d->predict1);
+
+			if (smart) {
+				half_cycles = req1_cycles + shift;
+				full_cycles = 0;
+			} else {
+				full_cycles = req1_cycles + shift;
+			}
+			half_delay = (double)half_cycles * ns * (1 + 0.92);
+			full_delay = (double)full_cycles * ns;
+			delta = (long long unsigned)(full_delay + half_delay);
+
+			t_delta = TIMEVAL_USECS(delta / 1000ULL);
+			timeradd(&time, &t_delta, &d->predict2);
+			d->req2_done = 0; d->req1_done = 0;
+		}
+
+		if (d->job_switched) {
+			memcpy(o2p, op, sizeof(struct bitfury_payload));
+			memcpy(op, p, sizeof(struct bitfury_payload));
+			memcpy(oldbuf, newbuf, 17 * 4);
+		}
+	}
+
+	timer_set_now(&time);
+	timersub(&time, &d->predict2, &d_time);
+	if (d_time.tv_sec < 0 && !d->req2_done) {
+		if(smart) {
+			d->otimer2 = d->timer2;
+			d->timer2 = time;
+			spi_clear_buf(port);
+			spi_emit_break(port);
+			spi_emit_fasync(port, chip);
+			spi_emit_data(port, 0x3000, &d->atrvec[0], 19*4);
+			if (smart) {
+				config_reg(port, 3, 1);
+			}
+			spi_txrx(port);
+			memcpy(newbuf, spi_getrxbuf(port)+4 + chip, 17*4);
+			d->counter2 = get_counter(newbuf, oldbuf);
+
+			d->req2_done = 1;
+		} else {
+			d->req2_done = 1;
+		}
+	}
+	
+	d->second_run = true;
+}

+ 76 - 0
libbitfury.h

@@ -0,0 +1,76 @@
+#ifndef __LIBBITFURY_H__
+#define __LIBBITFURY_H__
+
+#include "miner.h"
+#include "spidevc.h"
+
+#define BITFURY_STAT_N 1024
+
+struct bitfury_payload {
+	unsigned char midstate[32];
+	unsigned int junk[8];
+	unsigned m7;
+	unsigned ntime;
+	unsigned nbits;
+	unsigned nnonce;
+};
+
+struct bitfury_device {
+	struct spi_port *spi;
+	unsigned char osc6_bits;
+	unsigned newbuf[17];
+	unsigned oldbuf[17];
+	bool oldjob;
+	int active;
+	struct work * work;
+	struct work * owork;
+	struct work * o2work;
+	int job_switched;
+	uint32_t atrvec[20];
+	struct bitfury_payload payload;
+	struct bitfury_payload opayload;
+	struct bitfury_payload o2payload;
+	unsigned int results[16];
+	int results_n;
+	time_t stat_ts[BITFURY_STAT_N];
+	unsigned int stat_counter;
+	unsigned int future_nonce;
+	unsigned int old_nonce;
+	struct timeval timer1;
+	struct timeval timer2;
+	struct timeval otimer1;
+	struct timeval otimer2;
+	struct timeval predict1;
+	struct timeval predict2;
+	unsigned int counter1, counter2;
+	unsigned int ocounter1, ocounter2;
+	int rate; //per msec
+	int osc_slow;
+	int osc_fast;
+	int req1_done, req2_done;
+	double mhz;
+	double ns;
+	unsigned slot;
+	unsigned fasync;
+	unsigned strange_counter;
+	bool second_run;
+	bool force_reinit;
+	int desync_counter;
+	int sample_hwe;
+	int sample_tot;
+	
+	time_t short_out_t;
+	time_t long_out_t;
+};
+
+extern void libbitfury_sendHashData1(int chip_id, struct bitfury_device *, struct thr_info *);
+void work_to_payload(struct bitfury_payload *p, struct work *w);
+extern void payload_to_atrvec(uint32_t *atrvec, struct bitfury_payload *);
+extern void send_reinit(struct spi_port *, int slot, int chip_n, int n);
+extern void send_shutdown(struct spi_port *, int slot, int chip_n);
+extern void send_freq(struct spi_port *, int slot, int chip_n, int bits);
+extern int libbitfury_detectChips1(struct spi_port *);
+extern unsigned bitfury_decnonce(unsigned);
+extern bool bitfury_fudge_nonce(const void *midstate, const uint32_t m7, const uint32_t ntime, const uint32_t nbits, uint32_t *nonce_p);
+
+#endif /* __LIBBITFURY_H__ */

+ 13 - 0
logging.h

@@ -12,6 +12,7 @@
 
 #include "config.h"
 
+#include <errno.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdarg.h>
@@ -28,6 +29,8 @@ enum {
 };
 #endif
 
+#include "util.h"
+
 /* debug flags */
 extern bool opt_debug;
 extern bool opt_debug_console;
@@ -58,6 +61,16 @@ extern void _applog(int prio, const char *str);
 	return rv;  \
 } while (0)
 
+#define appperror(prio, s)  do {  \
+	const char *_tmp43 = bfg_strerror(errno, BST_ERRNO);  \
+	if (s && s[0])  \
+		applog(prio, "%s: %s", s, _tmp43);  \
+	else  \
+		_applog(prio, _tmp43);  \
+} while (0)
+
+#define perror(s)  appperror(LOG_ERR, s)
+
 extern void _bfg_clean_up(void);
 
 #define quit(status, fmt, ...) do { \

+ 74 - 19
miner.c

@@ -64,6 +64,7 @@
 
 #include "compat.h"
 #include "deviceapi.h"
+#include "logging.h"
 #include "miner.h"
 #include "findnonce.h"
 #include "adl.h"
@@ -2938,8 +2939,12 @@ void get_statline3(char *buf, size_t bufsz, struct cgpu_info *cgpu, bool for_cur
 	int goodnonces = cgpu->diff1;
 	
 	if (!opt_show_procs)
-		for (struct cgpu_info *slave = cgpu; (slave = slave->next_proc); )
+	{
+		struct cgpu_info *slave = cgpu;
+		for (int i = 1; i < cgpu->procs; ++i)
 		{
+			slave = slave->next_proc;
+			
 			slave->utility = slave->accepted / dev_runtime * 60;
 			slave->utility_diff1 = slave->diff_accepted / dev_runtime * 60;
 			
@@ -2954,6 +2959,7 @@ void get_statline3(char *buf, size_t bufsz, struct cgpu_info *cgpu, bool for_cur
 			badnonces += slave->bad_nonces;
 			goodnonces += slave->diff1;
 		}
+	}
 	
 	double wtotal = (waccepted + wnotaccepted);
 	
@@ -2997,7 +3003,8 @@ void get_statline3(char *buf, size_t bufsz, struct cgpu_info *cgpu, bool for_cur
 			if (!opt_show_procs)
 			{
 				// Find the highest temperature of all processors
-				for (struct cgpu_info *proc = cgpu; proc; proc = proc->next_proc)
+				struct cgpu_info *proc = cgpu;
+				for (int i = 0; i < cgpu->procs; ++i, (proc = proc->next_proc))
 					if (proc->temp > temp)
 						temp = proc->temp;
 			}
@@ -3011,7 +3018,8 @@ void get_statline3(char *buf, size_t bufsz, struct cgpu_info *cgpu, bool for_cur
 		const char *cHrStatsOpt[] = {"\2DEAD \1", "\2SICK \1", "OFF  ", "\2REST \1", " \2ERR \1", "\2WAIT \1", cHr};
 		int cHrStatsI = (sizeof(cHrStatsOpt) / sizeof(*cHrStatsOpt)) - 1;
 		bool all_dead = true, all_off = true;
-		for (struct cgpu_info *proc = cgpu; proc; proc = proc->next_proc)
+		struct cgpu_info *proc = cgpu;
+		for (int i = 0; i < cgpu->procs; ++i, (proc = proc->next_proc))
 		{
 			switch (cHrStatsI) {
 				default:
@@ -8967,7 +8975,6 @@ void proc_enable(struct cgpu_info *cgpu)
 /* Makes sure the hashmeter keeps going even if mining threads stall, updates
  * the screen at regular intervals, and restarts threads if they appear to have
  * died. */
-#define WATCHDOG_INTERVAL		2
 #define WATCHDOG_SICK_TIME		60
 #define WATCHDOG_DEAD_TIME		600
 #define WATCHDOG_SICK_COUNT		(WATCHDOG_SICK_TIME/WATCHDOG_INTERVAL)
@@ -9058,6 +9065,16 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 
 		for (i = 0; i < total_devices; ++i) {
 			struct cgpu_info *cgpu = get_devices(i);
+			if (!cgpu->disable_watchdog)
+				bfg_watchdog(cgpu, &now);
+		}
+	}
+
+	return NULL;
+}
+
+void bfg_watchdog(struct cgpu_info * const cgpu, struct timeval * const tvp_now)
+{
 			struct thr_info *thr = cgpu->thr[0];
 			enum dev_enable *denable;
 			char *dev_str = cgpu->proc_repr;
@@ -9084,7 +9101,7 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 			
 			/* Thread is disabled */
 			if (*denable == DEV_DISABLED)
-				continue;
+				return;
 			else
 			if (*denable == DEV_RECOVER_ERR) {
 				if (opt_restart && timer_elapsed(&cgpu->tv_device_last_not_well, NULL) > cgpu->reinit_backoff) {
@@ -9094,7 +9111,7 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 						cgpu->reinit_backoff *= 2;
 					device_recovered(cgpu);
 				}
-				continue;
+				return;
 			}
 			else
 			if (*denable == DEV_RECOVER) {
@@ -9104,7 +9121,7 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 					device_recovered(cgpu);
 				}
 				dev_error_update(cgpu, REASON_DEV_THERMAL_CUTOFF);
-				continue;
+				return;
 			}
 			else
 			if (cgpu->temp > cgpu->cutofftemp)
@@ -9118,7 +9135,7 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 			}
 
 			if (thr->getwork) {
-				if (cgpu->status == LIFE_WELL && thr->getwork < now.tv_sec - opt_log_interval) {
+				if (cgpu->status == LIFE_WELL && thr->getwork < tvp_now->tv_sec - opt_log_interval) {
 					int thrid;
 					bool cgpu_idle = true;
 					thr->rolling = 0;
@@ -9130,21 +9147,21 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 						cgpu->status = LIFE_WAIT;
 					}
 				}
-				continue;
+				return;
 			}
 			else if (cgpu->status == LIFE_WAIT)
 				cgpu->status = LIFE_WELL;
 
 #ifdef WANT_CPUMINE
 			if (!strcmp(cgpu->drv->dname, "cpu"))
-				continue;
+				return;
 #endif
-			if (cgpu->status != LIFE_WELL && (now.tv_sec - thr->last.tv_sec < WATCHDOG_SICK_TIME)) {
+			if (cgpu->status != LIFE_WELL && (tvp_now->tv_sec - thr->last.tv_sec < WATCHDOG_SICK_TIME)) {
 				if (likely(cgpu->status != LIFE_INIT && cgpu->status != LIFE_INIT2))
 				applog(LOG_ERR, "%s: Recovered, declaring WELL!", dev_str);
 				cgpu->status = LIFE_WELL;
 				cgpu->device_last_well = time(NULL);
-			} else if (cgpu->status == LIFE_WELL && (now.tv_sec - thr->last.tv_sec > WATCHDOG_SICK_TIME)) {
+			} else if (cgpu->status == LIFE_WELL && (tvp_now->tv_sec - thr->last.tv_sec > WATCHDOG_SICK_TIME)) {
 				thr->rolling = cgpu->rolling = 0;
 				cgpu->status = LIFE_SICK;
 				applog(LOG_ERR, "%s: Idle for more than 60 seconds, declaring SICK!", dev_str);
@@ -9163,14 +9180,14 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 					applog(LOG_ERR, "%s: Attempting to restart", dev_str);
 					reinit_device(cgpu);
 				}
-			} else if (cgpu->status == LIFE_SICK && (now.tv_sec - thr->last.tv_sec > WATCHDOG_DEAD_TIME)) {
+			} else if (cgpu->status == LIFE_SICK && (tvp_now->tv_sec - thr->last.tv_sec > WATCHDOG_DEAD_TIME)) {
 				cgpu->status = LIFE_DEAD;
 				applog(LOG_ERR, "%s: Not responded for more than 10 minutes, declaring DEAD!", dev_str);
 				cgtime(&thr->sick);
 
 				dev_error(cgpu, REASON_DEV_DEAD_IDLE_600);
 				run_cmd(cmd_dead);
-			} else if (now.tv_sec - thr->sick.tv_sec > 60 &&
+			} else if (tvp_now->tv_sec - thr->sick.tv_sec > 60 &&
 				   (cgpu->status == LIFE_SICK || cgpu->status == LIFE_DEAD)) {
 				/* Attempt to restart a GPU that's sick or dead once every minute */
 				cgtime(&thr->sick);
@@ -9182,10 +9199,6 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 				if (opt_restart)
 					reinit_device(cgpu);
 			}
-		}
-	}
-
-	return NULL;
 }
 
 static void log_print_status(struct cgpu_info *cgpu)
@@ -9284,7 +9297,7 @@ void print_summary(void)
 	for (i = 0; i < total_devices; ++i) {
 		struct cgpu_info *cgpu = get_devices(i);
 
-		if ((!cgpu->proc_id) && cgpu->next_proc)
+		if ((!cgpu->proc_id) && cgpu->procs > 1)
 		{
 			// Device summary line
 			opt_show_procs = false;
@@ -9615,6 +9628,10 @@ struct device_drv cpu_drv = {
 extern struct device_drv bitforce_drv;
 #endif
 
+#ifdef USE_BIGPIC
+extern struct device_drv bigpic_drv;
+#endif
+
 #ifdef USE_ICARUS
 extern struct device_drv cairnsmore_drv;
 extern struct device_drv erupter_drv;
@@ -9625,6 +9642,10 @@ extern struct device_drv icarus_drv;
 extern struct device_drv avalon_drv;
 #endif
 
+#ifdef USE_LITTLEFURY
+extern struct device_drv littlefury_drv;
+#endif
+
 #ifdef USE_MODMINER
 extern struct device_drv modminer_drv;
 #endif
@@ -9637,6 +9658,17 @@ extern struct device_drv x6500_api;
 extern struct device_drv ztex_drv;
 #endif
 
+#ifdef USE_BITFURY
+extern struct device_drv bitfury_drv;
+#endif
+
+#ifdef USE_METABANK
+extern struct device_drv metabank_drv;
+#endif
+
+#ifdef USE_BFSB
+extern struct device_drv bfsb_drv;
+#endif
 
 static int cgminer_id_count = 0;
 static int device_line_id_count;
@@ -9720,6 +9752,11 @@ void drv_detect_all()
 		bitforce_drv.drv_detect();
 #endif
 
+#ifdef USE_BIGPIC
+	if (!opt_scrypt)
+		bigpic_drv.drv_detect();
+#endif
+
 #ifdef USE_MODMINER
 	if (!opt_scrypt)
 		modminer_drv.drv_detect();
@@ -9735,6 +9772,24 @@ void drv_detect_all()
 		ztex_drv.drv_detect();
 #endif
 
+#ifdef USE_BITFURY
+	if (!opt_scrypt)
+	{
+		bitfury_drv.drv_detect();
+#ifdef USE_METABANK
+		metabank_drv.drv_detect();
+#endif
+#ifdef USE_BFSB
+		bfsb_drv.drv_detect();
+#endif
+	}
+#endif
+
+#ifdef USE_LITTLEFURY
+	if (!opt_scrypt)
+		littlefury_drv.drv_detect();
+#endif
+
 	/* Detect avalon last since it will try to claim the device regardless
 	 * as detection is unreliable. */
 #ifdef USE_AVALON

+ 10 - 0
miner.h

@@ -112,6 +112,10 @@ static inline int fsync (int fd)
   #include "libztex.h"
 #endif
 
+#ifdef USE_BITFURY
+  #include "libbitfury.h"
+#endif
+
 #ifdef HAVE_BYTESWAP_H
 #include <byteswap.h>
 #endif
@@ -568,6 +572,7 @@ struct cgpu_info {
 	struct work *queued_work;
 	unsigned int queued_count;
 
+	bool disable_watchdog;
 	bool shutdown;
 };
 
@@ -608,6 +613,7 @@ struct thr_info {
 	uint64_t hashes_done;
 	struct timeval tv_hashes_done;
 	struct timeval tv_lastupdate;
+	struct timeval _tv_last_hashes_done_call;
 
 	bool	pause;
 	time_t	getwork;
@@ -625,6 +631,7 @@ struct thr_info {
 	struct timeval tv_results_jobstart;
 	struct timeval tv_jobstart;
 	struct timeval tv_poll;
+	struct timeval tv_watchdog;
 	notifier_t notifier;
 	bool starting_next_work;
 	uint32_t _max_nonce;
@@ -727,6 +734,9 @@ static inline void swab256(void *dest_p, const void *src_p)
 
 #define flip32(dest_p, src_p) swap32yes(dest_p, src_p, 32 / 4)
 
+#define WATCHDOG_INTERVAL  2
+extern void bfg_watchdog(struct cgpu_info *, struct timeval *tvp_now);
+
 extern void _quit(int status);
 
 static inline void mutex_lock(pthread_mutex_t *lock)

+ 1 - 0
ocl.c

@@ -35,6 +35,7 @@
 
 #include "deviceapi.h"
 #include "findnonce.h"
+#include "logging.h"
 #include "ocl.h"
 
 /* Platform API */

+ 293 - 0
spidevc.c

@@ -0,0 +1,293 @@
+/*
+ * Copyright 2013 bitfury
+ * Copyright 2013 Luke Dashjr
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#ifdef HAVE_LINUX_SPI_SPIDEV_H
+#define HAVE_LINUX_SPI
+#endif
+
+#include "spidevc.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+
+#ifdef HAVE_LINUX_SPI
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <linux/spi/spidev.h>
+#include <time.h>
+#include <unistd.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+#include <sys/stat.h>
+#endif
+
+#include "logging.h"
+
+#ifdef HAVE_LINUX_SPI
+bool sys_spi_txrx(struct spi_port *port);
+static volatile unsigned *gpio;
+#endif
+
+struct spi_port *sys_spi;
+
+void spi_init(void)
+{
+#ifdef HAVE_LINUX_SPI
+	int fd;
+	fd = open("/dev/mem",O_RDWR|O_SYNC);
+	if (fd < 0)
+	{
+		perror("/dev/mem trouble");
+		return;
+	}
+	gpio = mmap(0,4096,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0x20200000);
+	if (gpio == MAP_FAILED)
+	{
+		perror("gpio mmap trouble");
+		return;
+	}
+	close(fd);
+	
+	sys_spi = malloc(sizeof(*sys_spi));
+	*sys_spi = (struct spi_port){
+		.txrx = sys_spi_txrx,
+	};
+#endif
+}
+
+#ifdef HAVE_LINUX_SPI
+
+#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
+#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
+#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
+
+#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
+#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
+
+// Bit-banging reset, to reset more chips in chain - toggle for longer period... Each 3 reset cycles reset first chip in chain
+static
+int spi_reset(int a)
+{
+	int i,j;
+	int len = 8;
+	INP_GPIO(10); OUT_GPIO(10);
+	INP_GPIO(11); OUT_GPIO(11);
+	GPIO_SET = 1 << 11; // Set SCK
+	for (i = 0; i < 32; i++) { // On standard settings this unoptimized code produces 1 Mhz freq.
+		GPIO_SET = 1 << 10;
+		for (j = 0; j < len; j++) {
+			a *= a;
+		}
+		GPIO_CLR = 1 << 10;
+		for (j = 0; j < len; j++) {
+			a *= a;
+		}
+	}
+	GPIO_CLR = 1 << 10;
+	GPIO_CLR = 1 << 11;
+	INP_GPIO(10);
+	SET_GPIO_ALT(10,0);
+	INP_GPIO(11);
+	SET_GPIO_ALT(11,0);
+	INP_GPIO(9);
+	SET_GPIO_ALT(9,0);
+
+	return a;
+}
+
+#define BAILOUT(s)  do{  \
+	perror(s);  \
+	close(fd);  \
+	return false;  \
+}while(0)
+
+bool sys_spi_txrx(struct spi_port *port)
+{
+	const void *wrbuf = spi_gettxbuf(port);
+	void *rdbuf = spi_getrxbuf(port);
+	size_t bufsz = spi_getbufsz(port);
+	int fd;
+	int mode, bits, speed, rv, i, j;
+	struct spi_ioc_transfer tr[16];
+
+	memset(&tr,0,sizeof(tr));
+	mode = 0; bits = 8; speed = 4000000;
+	if (port->speed)
+		speed = port->speed;
+
+	spi_reset(1234);
+	fd = open("/dev/spidev0.0", O_RDWR);
+	if (fd < 0) {
+		perror("Unable to open SPI device");
+		return false;
+	}
+	if (ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0)
+		BAILOUT("Unable to set WR MODE");
+	if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0)
+		BAILOUT("Unable to set RD MODE");
+	if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0)
+		BAILOUT("Unable to set WR_BITS_PER_WORD");
+	if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0)
+		BAILOUT("Unable to set RD_BITS_PER_WORD");
+	if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0)
+		BAILOUT("Unable to set WR_MAX_SPEED_HZ");
+	if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0)
+		BAILOUT("Unable to set RD_MAX_SPEED_HZ");
+
+	rv = 0;
+	while (bufsz >= 4096) {
+                tr[rv].tx_buf = (uintptr_t) wrbuf;
+                tr[rv].rx_buf = (uintptr_t) rdbuf;
+                tr[rv].len = 4096;
+                tr[rv].delay_usecs = 1;
+                tr[rv].speed_hz = speed;
+                tr[rv].bits_per_word = bits;
+                bufsz -= 4096;
+                wrbuf += 4096; rdbuf += 4096; rv ++;
+        }
+        if (bufsz > 0) {
+                tr[rv].tx_buf = (uintptr_t) wrbuf;
+                tr[rv].rx_buf = (uintptr_t) rdbuf;
+                tr[rv].len = (unsigned)bufsz;
+                tr[rv].delay_usecs = 1;
+                tr[rv].speed_hz = speed;
+                tr[rv].bits_per_word = bits;
+                rv ++;
+        }
+
+        i = rv;
+        for (j = 0; j < i; j++) {
+                rv = (int)ioctl(fd, SPI_IOC_MESSAGE(1), (intptr_t)&tr[j]);
+		if (rv < 0)
+			BAILOUT("WTF!");
+        }
+
+	close(fd);
+	spi_reset(4321);
+
+	return true;
+}
+
+#endif
+
+static
+void *spi_emit_buf_reverse(struct spi_port *port, const void *p, size_t sz)
+{
+	const unsigned char *str = p;
+	void * const rv = &port->spibuf_rx[port->spibufsz];
+	if (port->spibufsz + sz >= SPIMAXSZ)
+		return NULL;
+	for (size_t i = 0; i < sz; ++i)
+	{
+		// Reverse bit order in each byte!
+		unsigned char p = str[i];
+		p = ((p & 0xaa)>>1) | ((p & 0x55) << 1);
+		p = ((p & 0xcc)>>2) | ((p & 0x33) << 2);
+		p = ((p & 0xf0)>>4) | ((p & 0x0f) << 4);
+		port->spibuf[port->spibufsz++] = p;
+	}
+	return rv;
+}
+
+static
+void spi_emit_buf(struct spi_port *port, void *str, size_t sz)
+{
+	if (port->spibufsz + sz >= SPIMAXSZ)
+		return;
+	memcpy(&port->spibuf[port->spibufsz], str, sz);
+	port->spibufsz += sz;
+}
+
+/* TODO: in production, emit just bit-sequences! Eliminate padding to byte! */
+void spi_emit_break(struct spi_port *port)
+{
+	spi_emit_buf(port, "\x4", 1);
+}
+
+void spi_emit_fsync(struct spi_port *port)
+{
+	spi_emit_buf(port, "\x6", 1);
+}
+
+void spi_emit_fasync(struct spi_port *port, int n)
+{
+	int i;
+	for (i = 0; i < n; i++) {
+		spi_emit_buf(port, "\x5", 1);
+	}
+}
+
+void spi_emit_nop(struct spi_port *port, int n) {
+	int i;
+	for (i = 0; i < n; n++) {
+		spi_emit_buf(port, "\x0", 1);
+	}
+}
+
+void *spi_emit_data(struct spi_port *port, uint16_t addr, const void *buf, size_t len)
+{
+	unsigned char otmp[3];
+	if (len < 4 || len > 128)
+		return NULL;  /* This cannot be programmed in single frame! */
+	len /= 4; /* Strip */
+	otmp[0] = (len - 1) | 0xE0;
+	otmp[1] = (addr >> 8)&0xFF; otmp[2] = addr & 0xFF;
+	spi_emit_buf(port, otmp, 3);
+	return spi_emit_buf_reverse(port, buf, len*4);
+}
+
+#ifdef USE_BFSB
+void spi_bfsb_select_bank(int bank)
+{
+	static int last_bank = -2;
+	if (bank == last_bank)
+		return;
+	const int banks[4]={18,23,24,25}; // GPIO connected to OE of level shifters
+	int i;
+	for(i=0;i<4;i++)
+	{
+		INP_GPIO(banks[i]);
+		OUT_GPIO(banks[i]);
+		if(i==bank)
+		{
+			GPIO_SET = 1 << banks[i]; // enable bank
+		} 
+		else
+		{
+			GPIO_CLR = 1 << banks[i];// disable bank
+		}
+	}
+	last_bank = bank;
+}
+#endif

+ 77 - 0
spidevc.h

@@ -0,0 +1,77 @@
+#ifndef SPIDEVC_H
+#define SPIDEVC_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#define SPIMAXSZ (256*1024)
+
+/* Initialize SPI using this function */
+void spi_init(void);
+
+struct spi_port {
+	/* TX-RX single frame */
+	bool (*txrx)(struct spi_port *port);
+	
+	char spibuf[SPIMAXSZ], spibuf_rx[SPIMAXSZ];
+	size_t spibufsz;
+	
+	struct cgpu_info *cgpu;
+	const char *repr;
+	int logprio;
+	int speed;
+};
+
+extern struct spi_port *sys_spi;
+
+
+/* SPI BUFFER OPS */
+static inline
+void spi_clear_buf(struct spi_port *port)
+{
+	port->spibufsz = 0;
+}
+
+static inline
+void *spi_getrxbuf(struct spi_port *port)
+{
+	return port->spibuf_rx;
+}
+
+static inline
+void *spi_gettxbuf(struct spi_port *port)
+{
+	return port->spibuf;
+}
+
+static inline
+size_t spi_getbufsz(struct spi_port *port)
+{
+	return port->spibufsz;
+}
+
+
+extern void spi_emit_break(struct spi_port *port); /* BREAK CONNECTIONS AFTER RESET */
+extern void spi_emit_fsync(struct spi_port *port); /* FEED-THROUGH TO NEXT CHIP SYNCHRONOUSLY (WITH FLIP-FLOP) */
+extern void spi_emit_fasync(struct spi_port *port, int n); /* FEED-THROUGH TO NEXT CHIP ASYNCHRONOUSLY (WITHOUT FLIP-FLOP INTERMEDIATE) */
+extern void spi_emit_nop(struct spi_port *port, int n);
+
+/* TRANSMIT PROGRAMMING SEQUENCE (AND ALSO READ-BACK) */
+/* addr is the destination address in bits (16-bit - 0 to 0xFFFF valid ones)
+   buf is buffer to be transmitted, it will go at position spi_getbufsz()+3
+   len is length in _bytes_, should be 4 to 128 and be multiple of 4, as smallest
+   transmission quantum is 32 bits */
+extern void *spi_emit_data(struct spi_port *port, uint16_t addr, const void *buf, size_t len);
+
+static inline
+bool spi_txrx(struct spi_port *port)
+{
+	return port->txrx(port);
+}
+
+extern bool sys_spi_txrx(struct spi_port *);
+
+void spi_bfsb_select_bank(int bank);
+
+#endif

+ 112 - 0
tm_i2c.c

@@ -0,0 +1,112 @@
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#include "logging.h"
+#include "tm_i2c.h"
+
+static int tm_i2c_fd;
+
+float tm_i2c_Data2Temp(unsigned int ans) {
+	float t = ans;
+	return (t / 1023.0 * 3.3 * 2-2.73) * 100.0;
+}
+
+float tm_i2c_Data2Core(unsigned int ans) {
+	float t = ans;
+	return t / 1023.0 * 3.3;
+}
+
+int tm_i2c_init() {
+	if ((tm_i2c_fd = open("/dev/i2c-1", O_RDWR)) < 0)
+		return 1;
+	else
+		return 0;
+}
+
+void tm_i2c_close() {
+	close(tm_i2c_fd);
+}
+
+unsigned int tm_i2c_req(int fd, unsigned char addr, unsigned char cmd, unsigned int data) {
+	int i;
+	unsigned char buf[16];
+	struct i2c_msg msg;
+	tm_struct *tm = (tm_struct *) buf;
+	struct i2c_rdwr_ioctl_data msg_rdwr;
+	unsigned int ret;
+
+	//applog(LOG_DEBUG, "REQ from %02X cmd: %02X", addr, cmd);
+
+	tm->cmd = cmd;
+	tm->data_lsb = data & 0xFF;
+	tm->data_msb = (data & 0xFF00) >> 8;
+
+	/* Write CMD */
+	msg.addr = addr;
+	msg.flags = 0;
+	msg.len = 3;
+	msg.buf = buf;
+	msg_rdwr.msgs = &msg;
+	msg_rdwr.nmsgs = 1;
+	if ((i = ioctl(fd, I2C_RDWR, &msg_rdwr)) < 0) {
+//		perror("ioctl error");
+		return -1;
+	}
+
+	/* Read result */
+	msg.addr = addr;
+	msg.flags = I2C_M_RD;
+	msg.len = 3;
+	msg.buf = buf;
+	msg_rdwr.msgs = &msg;
+	msg_rdwr.nmsgs = 1;
+	if ((i = ioctl(fd, I2C_RDWR, &msg_rdwr)) < 0) {
+//		perror("ioctl error");
+		return -1;
+	}
+
+	//hexdump(buf, 10);
+	ret = (tm->data_msb << 8) + tm->data_lsb;
+	if (tm->cmd == cmd) return ret;
+	return 0;
+}
+
+int tm_i2c_detect(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_GET_CORE0, 0);
+}
+
+float tm_i2c_getcore0(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return tm_i2c_Data2Core(tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_GET_CORE0, 0));
+}
+
+float tm_i2c_getcore1(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return tm_i2c_Data2Core(tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_GET_CORE1, 0));
+}
+
+float tm_i2c_gettemp(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return tm_i2c_Data2Temp(tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_GET_TEMP, 0));
+}
+
+void tm_i2c_set_oe(unsigned char slot) {
+	if (slot < 0 || slot > 31) return;
+	tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_SET_OE, 0);
+}
+
+void tm_i2c_clear_oe(unsigned char slot) {
+	if (slot < 0 || slot > 31) return;
+	tm_i2c_req(tm_i2c_fd, (TM_ADDR >> 1) + slot, TM_SET_OE, 1);
+}
+
+unsigned char tm_i2c_slot2addr(unsigned char slot) {
+	if (slot < 0 || slot > 31) return 0;
+	return ((TM_ADDR >> 1) + slot);
+}
+

+ 43 - 0
tm_i2c.h

@@ -0,0 +1,43 @@
+/* - Version 1.0 - */
+
+#define TM_ADDR         0xC0
+
+#define TM_GET_TEMP     0x10
+#define TM_GET_CORE0    0x11
+#define TM_GET_CORE1    0x12
+
+#define TM_SET_OE       0x20
+#define TM_SET_MODE     0x21
+#define TM_SET_RED      0x22
+#define TM_SET_GREEN    0x23
+
+#define TM_GET_PORTB    0x30
+#define TM_SET_PORTB    0x31
+#define TM_GET_PINB     0x32
+#define TM_GET_PORTD    0x33
+#define TM_SET_PORTD    0x34
+#define TM_GET_PIND     0x35
+#define TM_GET_ADC      0x36
+
+#define TM_MODE_AUTO    0
+#define TM_MODE_MANUAL  1
+
+typedef struct {
+	unsigned char cmd;
+	unsigned char data_lsb;
+	unsigned char data_msb;
+} tm_struct;
+
+int tm_i2c_init();
+void tm_i2c_close();
+unsigned int tm_i2c_req(int fd, unsigned char addr, unsigned char cmd, unsigned int data);
+float tm_i2c_Data2Temp(unsigned int ans);
+float tm_i2c_Data2Core(unsigned int ans);
+float tm_i2c_gettemp(unsigned char slot);
+float tm_i2c_getcore0(unsigned char slot);
+float tm_i2c_getcore1(unsigned char slot);
+void tm_i2c_set_oe(unsigned char slot);
+void tm_i2c_clear_oe(unsigned char slot);
+int tm_i2c_detect(unsigned char slot);
+unsigned char tm_i2c_slot2addr(unsigned char slot);
+

+ 7 - 1
util.h

@@ -315,6 +315,12 @@ extern void (*timer_set_now)(struct timeval *);
 	}  \
 )
 
+static inline
+long timeval_to_us(const struct timeval *tvp)
+{
+	return ((long)tvp->tv_sec * 1000000) + tvp->tv_usec;
+}
+
 #define timer_set_delay(tvp_timer, tvp_now, usecs)  do {  \
 	struct timeval tv_add = TIMEVAL_USECS(usecs);  \
 	timeradd(&tv_add, tvp_now, tvp_timer);  \
@@ -341,7 +347,7 @@ long timer_elapsed_us(const struct timeval *tvp_timer, const struct timeval *tvp
 	struct timeval tv;
 	const struct timeval *_tvp_now = _bfg_nullisnow(tvp_now, &tv);
 	timersub(_tvp_now, tvp_timer, &tv);
-	return ((long)tv.tv_sec * 1000000) + tv.tv_usec;
+	return timeval_to_us(&tv);
 }
 
 static inline