Browse Source

Merge remote-tracking branch 'luke-jr/bfgminer' into bfgminer

John 10 years ago
parent
commit
ec2805e151
32 changed files with 3471 additions and 146 deletions
  1. 4 0
      .travis.yml
  2. 1 0
      AUTHORS
  3. 10 2
      Makefile.am
  4. 115 0
      NEWS
  5. 3 0
      README
  6. 89 16
      README.ASIC
  7. 14 0
      README.RPC
  8. 27 2
      api.c
  9. 12 2
      configure.ac
  10. 12 0
      debian/changelog
  11. 1 1
      debian/control
  12. 42 9
      deviceapi.c
  13. 10 11
      deviceapi.h
  14. 30 0
      driver-aan.c
  15. 4 0
      driver-aan.h
  16. 540 0
      driver-alchemist.c
  17. 79 14
      driver-antminer.c
  18. 42 0
      driver-avalon.c
  19. 2 18
      driver-avalonmm.c
  20. 34 0
      driver-bitforce.c
  21. 1873 0
      driver-bitmain.c
  22. 251 0
      driver-bitmain.h
  23. 23 0
      driver-hashfast.c
  24. 1 0
      driver-icarus.h
  25. 6 0
      driver-jingtian.c
  26. 25 9
      lowl-vcom.c
  27. 1 1
      m4/bundled_lib.m4
  28. 137 59
      miner.c
  29. 6 0
      miner.h
  30. 1 1
      openwrt/bfgminer/Makefile
  31. 73 1
      util.c
  32. 3 0
      util.h

+ 4 - 0
.travis.yml

@@ -68,8 +68,12 @@ matrix:
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-opencl --enable-keccak --enable-scrypt'
     - compiler: ": OpenCL w/o ADL or sensors"
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-opencl --enable-keccak --enable-scrypt --disable-adl'
+    - compiler: ": Only alchemist"
+      env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-scrypt --enable-alchemist'
     - compiler: ": Only bitforce"
       env: myCC='clang' UBUNTU_DEPS='linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-bitforce'
+    - compiler: ": Only bitmain"
+      env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-bitmain'
     - compiler: ": Only icarus"
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-icarus'
     - compiler: ": Only dualminer"

+ 1 - 0
AUTHORS

@@ -1,6 +1,7 @@
 CURRENT MAINTAINERS:
 
 Luke Dashjr <luke-jr+bfgminer@utopios.org> 1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh
+John Stefanopoulos <jstefanop@mac.com>
 Nate Woolls <nwoolls@gmail.com> 1JnZoFeCVYJgaKbKwDUxSkTZWWpBmwWTgV
 Pelle Nilsson <per.nilsson@xelmo.com>
 Vitalii Demianets <vitalii@orsoc.se>

+ 10 - 2
Makefile.am

@@ -92,8 +92,8 @@ TEST_EXTENSIONS = .sh
 
 .PHONY: update-version
 update-version:
-	./gen-version.sh >version.h.new
-	cmp version.h version.h.new && rm version.h.new || mv version.h.new version.h
+	( cd $(top_srcdir) && $(top_srcdir)/gen-version.sh ) >version.h.new
+	cmp $(top_srcdir)/version.h version.h.new && rm version.h.new || mv version.h.new $(top_srcdir)/version.h
 version.h: update-version
 bfgminer_SOURCES += version.c version.h
 BUILT_SOURCES = version.h
@@ -257,10 +257,18 @@ if HAS_ASIC
 dist_doc_DATA += README.ASIC
 endif
 
+if USE_ALCHEMIST
+bfgminer_SOURCES += driver-alchemist.c
+endif
+
 if USE_BITFORCE
 bfgminer_SOURCES += driver-bitforce.c
 endif
 
+if USE_BITMAIN
+bfgminer_SOURCES += driver-bitmain.c driver-bitmain.h
+endif
+
 if USE_BIGPIC
 bfgminer_SOURCES += driver-bigpic.c driver-bigpic.h
 endif

+ 115 - 0
NEWS

@@ -1,3 +1,118 @@
+BFGMiner Version 5.4.0 - October 23, 2015
+
+- AUTHORS: Move jstefanop to current maintainers
+- Disable alchemist by default, add Travis build, and document configure option
+in README
+- alchemist: New scrypt ASIC driver
+- hashfast: Support setting clock speed from TUI Manage
+- avalon: Support setting clock speed from TUI Manage
+- antminer: Support setting clock speed from TUI Manage (hidden for non-BM1382/4
+devices)
+- jingtian: Allow changing clock speed from TUI
+- Debuglog for retrodiff being disabled
+- Disable retrodiff when it was not explicitly enabled, and the pool doesn't
+seem to like it
+- Bugfix: Only adjust work_difficulty on retrodiff submissions, so we can still
+detect them on rejection
+- (Re-)enable retrodiff by default for stratum pools, since some servers
+implement mining.set_difficulty wrong in this way
+- New pool option "retrodiff"
+- If a share passes difficulty check for the updated pool target,   record that
+target for correct accounting of diff_stale.
+- DevAPI: Remove unused temporary variable from driver iteration
+- README.ASIC: Expand Antminer S5 section to S1-S5 for completeness, since in
+theory they should work
+- bitmain: Make reg_data optional for S4 and S5, calculating it from clock
+- Document Bitmain Antminer S5 support
+- bitmain: Remove poll_prio_threshold and just ensure we poll at a regular
+interval to avoid nonce buffer overruns
+- bitmain: Remove dead per-device constants
+- bitmain: Only have one set of actual maximums
+- bitmain: Migrate BITMAIN_MAX_NONCE_NUM to runtime packet_max_nonce
+- bitmain: Migrate BITMAIN_MAX_WORK_QUEUE_NUM/bitmain_work_poll_prio to runtime
+poll_prio_threshold
+- bitmain: Migrate BITMAIN_MAX_WORK_NUM to runtime packet_max_work
+- bitmain: Dummy model parameter
+- bitmain: Remove baud/flush, as the fake VCOM kernel driver ignores (and
+complains about) both
+- bitmain: Poll after queuing work, once enough is queued
+- bitmain: Sleep a little between polling
+- bitmain: Flush queues for work restarts
+- bitmain: Queue multiple works at a time
+- bitmain: Remove more dead code
+- bitmain: Prune old work eventually
+- Bugfix: bitmain: Properly count work-search failures as HW errors
+- bitmain: Refactor to work with minerloop_queue (leaks work memory)
+- bitmain: Avoid busy-looping on network devices
+- bitmain: Support for talking to a device over the network
+- bitmain: Use the hottest reading for device temperature
+- Bugfix: bitmain: Actually use baud setting
+- bitmain: Remove more dead code
+- bitmain: Handle stale results normally
+- bitmain: Simplify num2bit
+- bitmain: Initial set-device based configuration
+- bitmain: Use lowl-vcom abstractions
+- Update copyrights
+- Bugfix: bitmain: Type-safe printf-format usage
+- Travis: Test bitmain-only build
+- Build bitmain driver
+- bitmain: Hardcode configuration for now
+- bitmain: Rework nonce_diff handling
+- bitmain: Update headers
+- bitmain: Deal with unused variable warnings sanely
+- bitmain: Explicitly de-const device_path for freeing
+- Bugfix: bitmain: Correct type of cgpu->temp reference
+- Bugfix: bitmain: Use uint8_t consistently for binary data
+- Bugfix: bitmain: Clear opt_bitmain_dev string properly
+- bitmain: Remove non-existent bitmain_detect parameter
+- bitmain: Cleanup unnecessary code
+- bitmain: Use uthash to find queued work
+- bitmain: Implement inc_dev_status within record_temp_fan
+- bitmain: Remove non-applicable limits
+- bitmain: Remove obsolete get_statline_before function
+- bitmain: Move g_miner_version to bitmain_info struct
+- bitmain: Remove direct USB code
+- bitmain: Update driver registration
+- bitmain: Update symbol names
+- bitmain: Remove dead code
+- bitmain: Replace custom hexdump with normal bin2hex
+- bitmain: Get network difficulty from first work task
+- bitmain: No-op htole8
+- bitmain: Simulate cgminer work_block somewhat
+- bitmain: Update bin2hex usage for malloc-free version
+- bitmain: Copy low-level code from Bitmain cgminer usbutils
+- Copy working driver-bitmain.c from Bitmain's cgminer at commit
+4ecf89341657ea7efecdf588586ca3f068ab17ab
+- Add api_add_percent to miner.h
+- Bugfix: DevAPI: Update includes from uthash to utlist and support older
+versions of uthash
+- Bugfix: RPC: Need to include utlist.h for config file list
+- Bugfix: antminer: Avoid NULL dereference for non-BM1382/4 devices
+- README.ASIC: Update documentation for BM1382/4 clock calculation support
+- antminer: Support for setting BM1382/4 clock by frequency MHz
+- Bugfix: Keep JSON from getaccountaddress around long enough for debug messages
+- Bugfix: Run gen-version.sh from source directory
+- Fix to enable building into directory out of source tree
+- Bugfix: Clean up JSON from getaccountaddress
+- Bugfix: Do not use hash tables for driver lists, since they require unique
+keys
+- Pool option #cksuggest to use CKPool-compatible mining.suggest_difficulty
+- RPC: Add "Rotate Period" to config
+- RPC: Extend setconfig to change strategy
+- Allow setting strategy by name
+- bitforce: Enable changing voltage from the Manage TUI
+- avalonmm: Use proc_set_device_tui_wrapper instead of avalonmm_tui_wrapper
+- DevAPI: Add generic proc_set_device_tui_wrapper
+- bitforce: Add "voltage" setting to send V?X commands
+- Bugfix: compac: Set dname so assignments match
+- README.RPC: Add missing setconfig|stratum-port documentation
+- README.RPC: Add missing setconfig|http-port documentation
+- Bugfix: lowl-vcom: Check for tcgetattr/tcsetattr/tcflush failure
+- configure: List compac driver in output
+- Travis: Workaround Travis bug
+- configure: Use AC_PROG_SED to find sed
+
+
 BFGMiner Version 5.3.0 - September 5, 2015
 
 - README.ASIC: Compac docs

+ 3 - 0
README

@@ -142,6 +142,7 @@ BFGMiner driver configuration options:
 	--enable-broad-udevrules
 	                        Include udev rules for ambiguous devices which may
 	                        not be miners
+	--enable-alchemist      Compile support for AlcheMist (default disabled)
 	--disable-avalon        Compile support for Avalon (default enabled)
 	--disable-avalonmm      Compile support for Avalon2/3 (default enabled)
 	--enable-bfsb           Compile support for BFSB (default disabled)
@@ -151,6 +152,8 @@ BFGMiner driver configuration options:
 	                        enabled)
 	--disable-bitforce      Compile support for BitForce (default enabled)
 	--disable-bitfury       Compile support for Bitfury (default enabled)
+	--enable-bitmain        Compile support for Bitmain Antminer S* series
+	                        (default disabled)
 	--disable-cointerra     Compile support for CoinTerra (default enabled)
 	--enable-cpumining      Compile support for CPU mining (default disabled)
 	--disable-drillbit      Compile support for DrillBit (default enabled)

+ 89 - 16
README.ASIC

@@ -2,8 +2,88 @@ SUPPORTED DEVICES
 
 Currently supported ASIC devices include Avalon, Bitfountain's Block Erupter
 series (both USB and blades), a large variety of Bitfury-based miners,
-Butterfly Labs' SC range of devices, HashBuster boards, GekkoScience's Compac
-USB stick, Klondike modules, and KnCMiner's Mercury, Jupiter and Saturn.
+Bitmain's Antminer S5 and U1-3, Butterfly Labs' SC range of devices, HashBuster
+boards, GekkoScience's Compac USB stick, Klondike modules, and KnCMiner's
+Mercury, Jupiter and Saturn.
+
+
+ANTMINER S1-S5
+--------------
+
+BFGMiner must be compiled for and run on the embedded controller. When
+configuring, use the --enable-bitmain option to build the 'bitmain' driver used
+to interface with this hardware. None of the device attributes are autodetected
+at this time, so you must also tell BFGMiner this at runtime with a series of
+--set options. For example:
+
+-S bitmain:auto --set btm:model=S5 --set btm:layout=32:8 --set btm:timeout=3
+--set btm:clock=350 --set btm:reg_data=0d82 --set btm:voltage=x0725
+
+Note that reg_data is optional for S4 and S5 and will be calculated from clock
+if not provided.
+
+The meaning of each of these options are not documented individually at this
+time, but can be determined from the stock cgminer's options. You want to look
+at the "bitmain-options" from the command line, and the "bitmain-freq" and
+"bitmain-voltage" in the /config/cgminer.conf file.
+In this case, they were:
+
+NOTE: These are NOT valid BFGMiner options!
+    --bitmain-options 115200:32:8:7:200:0782:0725
+                             |    | |   |    ^^^^ voltage
+                             |    | |   ^^^^ reg_data
+                             |    | ^^^ clock
+                             |    ^ timeout
+                             ^^^^ layout
+    "bitmain-freq" : "3:350:0d82",
+                      | |   ^^^^ reg_data
+                      | ^^^ clock
+                      ^ timeout
+    "bitmain-voltage" : "0725"
+                         ^^^^ voltage
+
+Notice how there are duplicate settings for timeout, clock, reg_data, and
+voltage. You can probably use either one, but the 350 MHz clock performs
+better than the 200 MHz clock. You shouldn't mix and match the
+timeout/clock/reg_data combinations, however!
+
+Additionally, since the controllers are underpowered for these devices, you may
+need to experiment with a good queue setting to control how much work BFGMiner
+tries to pre-prepare for it. A reasonable starting place is:
+
+--queue 8192
+
+
+ALCHEMIST
+---------
+This driver requires the latest FPGA firmware flashed on the blades (stock
+firmware has major bug and won't run properly with this driver). For
+instructions, please visit: https://litecointalk.org/?topic=27370
+The driver has been designed to run each of the 8 blades inside an AlcheMist
+256 as a separate miner. To detect all the blades you need to manually probe it
+with the following serial ports:
+
+-S ALC:all -S ALC:/dev/ttyO1 -S ALC:/dev/ttyO2 -S ALC:/dev/ttyO3
+-S ALC:/dev/ttyO4
+
+(the four ttyUSB ports are auto detected by all)
+
+The driver supports custom frequency settings in the range of 200-400 MHz in 16
+MHz increments (driver will default to 352 MHz if these conditions are not met).
+Frequency is set with the following --set option:
+
+--set ALC:clock=336
+
+You can also set the frequency per board by specifying the tty port:
+
+--set ALC@/dev/ttyO3:clock=352
+
+Driver also supports running single blades off a Raspberry Pi. Make sure you
+have configured GPIO pin 25 correctly (see below) and scan via
+-S ALC:/dev/ttyAMA0
+
+echo 25 > /sys/class/gpio/export
+echo out > /sys/class/gpio/gpio25/direction
 
 
 ANTMINER U3
@@ -12,21 +92,16 @@ ANTMINER U3
 The U3 does not support autodetection, so you will want to use --scan-serial to
 manually probe it. For example, to scan all devices, you can use:
 
--S antminer:all
+-S antminer:all --set antminer:chip=BM1382
 
 Additionally, for optimal performance you will need to set voltage, clock, and
-timing. Neither voltage nor clock for the U3 are documented by the manufacturer,
-thus must be provided as hexadecimal configuration codes. Timing is provided in
-the number of nanoseconds each hash takes at the given configuration. A
+timing. Voltage format for the U3 is not documented by the manufacturer, thus
+must be provided as hexadecimal configuration codes. Timing is provided in the
+number of nanoseconds each hash takes at the given configuration. A
 known-working configuration is:
 
---set antminer:voltage=x800 --set antminer:clock=x1286 --set antminer:timing=0.022421
-
-Some valid values for clock setting are:
-    x0783 for 100 MHz, x0983 for 125 MHz, x0b83 for 150 MHz, x0d83 for 175 MHz,
-    x0782 for 200 MHz, x0882 for 225 MHz, x0982 for 250 MHz, x0a82 for 275 MHz,
-    x0b82 for 300 MHz, x0c82 for 325 MHz, x0d82 for 350 MHz, x0e82 for 375 MHz,
-    and x08f2 for 400 MHz
+--set antminer:voltage=x800 --set antminer:clock=237.5
+--set antminer:timing=0.022421
 
 
 AVALON 1
@@ -187,9 +262,7 @@ COMPAC
 These USB sticks are based on Bitmain's BM1384 chip, and use the antminer
 driver. You can set the clock frequency with
 
---set compac:clock=x0782
-
-The same values for Antminer U3 (above) are valid for the BM1384.
+--set compac:clock=200
 
 
 HEX*FURY

+ 14 - 0
README.RPC

@@ -156,6 +156,7 @@ The list of requests - a (*) means it requires privileged access - and replies:
                               ADL=X, <- Y or N if ADL is compiled in the code
                               ADL in use=X, <- Y or N if any GPU has ADL
                               Strategy=Name, <- the current pool strategy
+                              Rotate Period=N, <- rotate strategy period
                               Log Interval=N, <- log interval (--log N)
                               Device Code=GPU ICA , <- spaced list of compiled
                                                        device drivers
@@ -358,6 +359,10 @@ The list of requests - a (*) means it requires privileged access - and replies:
                               queue, scantime, expiry (integer in the range
                                                        0 to 9999)
                               coinbase-sig (string)
+                              http-port (valid port number)
+                              strategy (name of valid strategy, and optional
+                                        number of minutes if rotate)
+                              stratum-port (valid port number)
 
  pgaset|N,opt[,val] (*)
                none           This is equivalent to PROCSET on the first
@@ -449,6 +454,14 @@ https://www.npmjs.org/package/miner-rpc
 Feature Changelog for external applications using the API:
 
 
+API V3.4 (BFGMiner v5.4.0)
+
+Modified API commands:
+ 'config' - add 'Rotate Period'
+ 'setconfig' - add 'strategy'
+
+---------
+
 API V3.3 (BFGMiner v5.0.0)
 
 Modified API command:
@@ -544,6 +557,7 @@ Modified API commands:
  'pgadisable' - disable all processors for a numbered full device
  'pgaidentify' - choose first processor of numbered full device
  'pgaset' - choose first processor of numbered full device
+ 'setconfig' - add 'stratum-port' number
 
 Added API commands:
  'procs'

+ 27 - 2
api.c

@@ -27,6 +27,7 @@
 #include <sys/types.h>
 
 #include <uthash.h>
+#include <utlist.h>
 
 #include "compat.h"
 #include "deviceapi.h"
@@ -311,6 +312,8 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_INVNEG 121
 #define MSG_SETQUOTA 122
 
+#define MSG_INVSTRATEGY 0x102
+
 #define USE_ALTMSG 0x4000
 
 enum code_severity {
@@ -462,6 +465,7 @@ struct CODES {
  { SEVERITY_ERR,   MSG_UNKCON,	PARAM_STR,	"Unknown config '%s'" },
  { SEVERITY_ERR,   MSG_INVNUM,	PARAM_BOTH,	"Invalid number (%d) for '%s' range is 0-9999" },
  { SEVERITY_ERR,   MSG_INVNEG,	PARAM_BOTH,	"Invalid negative number (%d) for '%s'" },
+ { SEVERITY_ERR,   MSG_INVSTRATEGY,	PARAM_STR,	"Invalid strategy for '%s'" },
  { SEVERITY_SUCC,  MSG_SETQUOTA,PARAM_SET,	"Set pool '%s' to quota %d'" },
  { SEVERITY_ERR,   MSG_CONPAR,	PARAM_NONE,	"Missing config parameters 'name,N'" },
  { SEVERITY_ERR,   MSG_CONVAL,	PARAM_STR,	"Missing config value N for '%s,N'" },
@@ -1282,7 +1286,7 @@ static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __
 	struct api_data *root = NULL;
 	char buf[TMPBUFSIZ];
 	bool io_open;
-	struct driver_registration *reg, *regtmp;
+	struct driver_registration *reg;
 	int pgacount = 0;
 	char *adlinuse = (char *)NO;
 	int i;
@@ -1312,6 +1316,8 @@ static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __
 	root = api_add_const(root, "ADL", (char *)adl, false);
 	root = api_add_string(root, "ADL in use", adlinuse, false);
 	root = api_add_const(root, "Strategy", strategies[pool_strategy].s, false);
+	if (pool_strategy == POOL_ROTATE)
+		root = api_add_int(root, "Rotate Period", &opt_rotate_period, false);
 	root = api_add_int(root, "Log Interval", &opt_log_interval, false);
 	
 	strcpy(buf, ""
@@ -1323,7 +1329,7 @@ static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __
 #endif
 	);
 
-	BFG_FOREACH_DRIVER_BY_DNAME(reg, regtmp)
+	BFG_FOREACH_DRIVER_BY_DNAME(reg)
 	{
 		const struct device_drv * const drv = reg->drv;
 		tailsprintf(buf, sizeof(buf), " %s", drv->name);
@@ -3224,7 +3230,26 @@ static void setconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char
 		message(io_data, MSG_SETCONFIG, 1, param, isjson);
 		return;
 	}
+	else
 #endif
+	if (strcasecmp(param, "strategy") == 0) {
+		char * const strategy_name = comma;
+		comma = strchr(strategy_name, ',');
+		if (comma) {
+			*(comma++) = '\0';
+		}
+		value = bfg_strategy_parse(strategy_name);
+		if (value < 0) {
+			message(io_data, MSG_INVSTRATEGY, 0, param, isjson);
+			return;
+		}
+		if (!bfg_strategy_change(value, comma)) {
+			message(io_data, MSG_INVNUM, atoi(comma), param, isjson);
+			return;
+		}
+		message(io_data, MSG_SETCONFIG, value, param, isjson);
+		return;
+	}
 
 	value = atoi(comma);
 	if (value < 0 || value > 9999) {

+ 12 - 2
configure.ac

@@ -14,7 +14,7 @@ dnl * any later version.  See COPYING for more details.
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [5])
-m4_define([v_min], [3])
+m4_define([v_min], [4])
 m4_define([v_mic], [0])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_ver], [v_maj.v_min.v_mic])
@@ -553,6 +553,11 @@ else
 	adl="no"
 fi
 
+BFG_DRIVER(,AlcheMist,scrypt,no,[
+	need_lowl_vcom=yes
+	has_asic=yes
+])
+
 BFG_DRIVER(,BitForce,SHA256d,auto,[
 	driverlist="$driverlist bitforce:pci/need_lowl_pci"
 	if test "x$lowl_pci" = "xyes"; then
@@ -568,6 +573,11 @@ BFG_DRIVER(,BitForce,SHA256d,auto,[
 	have_udevrules=true
 ])
 
+BFG_DRIVER(bitmain,Bitmain Antminer S* series,SHA256d,no,[
+	need_lowl_vcom=yes
+	has_asic=yes
+])
+
 BFG_DRIVER(,Icarus,SHA256d,auto,[
 	need_dynclock=yes
 	need_lowl_vcom=yes
@@ -575,7 +585,7 @@ BFG_DRIVER(,Icarus,SHA256d,auto,[
 	has_asic=yes
 	have_udevrules=true
 ])
-driverlist="$driverlist cairnsmore/USE_ICARUS erupter/USE_ICARUS antminer/USE_ICARUS"
+driverlist="$driverlist cairnsmore/USE_ICARUS erupter/USE_ICARUS antminer/USE_ICARUS compac/USE_ICARUS"
 
 BFG_DRIVER(,DualMiner,Icarus,auto,[
 	need_gc3355=yes

+ 12 - 0
debian/changelog

@@ -1,3 +1,15 @@
+bfgminer (5.4.0-0precise1) precise; urgency=low
+
+  * RPC: Ability to change pool management strategy.
+  * Pool option #cksuggest to use CKPool-compatible mining.suggest_difficulty stratum extension.
+  * alchemist: New scrypt ASIC driver, written and maintained by jstefanop (requires custom FPGA reprogramming).
+  * antminer, avalon, compac, hashfast, and jingtian: Support for setting clock frequency from the TUI's device management interface.
+  * antminer & compac: Support for setting clock by frequency MHz.
+  * bitforce: Ability to change voltages from RPC and TUI.
+  * bitmain: New driver for Bitmain Antminer S-series units (up to S5).
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Fri, 23 Oct 2015 03:38:05 -0000
+
 bfgminer (5.3.0-0precise1) precise; urgency=low
 
   * compac: Support for the GekkoScience Compac BM1384 USB stick miner

+ 1 - 1
debian/control

@@ -2,7 +2,7 @@ Source: bfgminer
 Priority: optional
 Section: misc
 Maintainer: Luke Dashjr <luke_bfgminer@dashjr.org>
-Standards-Version: 5.3.0
+Standards-Version: 5.4.0
 Build-Depends: build-essential, debhelper, autoconf, automake, libtool, libssl-dev, yasm, pkg-config, libudev-dev, libcurl4-openssl-dev, wget, unzip, libjansson-dev, libncurses5-dev, libudev-dev, libusb-1.0-0-dev, git, quilt, uthash-dev, libsensors4-dev
 
 Package: bfgminer

+ 42 - 9
deviceapi.c

@@ -26,6 +26,8 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <utlist.h>
+
 #include "compat.h"
 #include "deviceapi.h"
 #include "logging.h"
@@ -41,21 +43,17 @@ struct driver_registration *_bfg_drvreg2;
 
 void _bfg_register_driver(const struct device_drv *drv)
 {
-	static struct driver_registration *initlist;
 	struct driver_registration *ndr;
 	
 	if (!drv)
 	{
-		// Move initlist to hashtables
-		LL_FOREACH(initlist, ndr)
+		// NOTE: Not sorted at this point (dname and priority may be unassigned until drv_init!)
+		LL_FOREACH2(_bfg_drvreg1, ndr, next_dname)
 		{
 			drv = ndr->drv;
 			if (drv->drv_init)
 				drv->drv_init();
-			HASH_ADD_KEYPTR(hh , _bfg_drvreg1, drv->dname, strlen(drv->dname), ndr);
-			HASH_ADD_KEYPTR(hh2, _bfg_drvreg2, drv->name , strlen(drv->name ), ndr);
 		}
-		initlist = NULL;
 		return;
 	}
 	
@@ -63,7 +61,8 @@ void _bfg_register_driver(const struct device_drv *drv)
 	*ndr = (struct driver_registration){
 		.drv = drv,
 	};
-	LL_PREPEND(initlist, ndr);
+	LL_PREPEND2(_bfg_drvreg1, ndr, next_dname);
+	LL_PREPEND2(_bfg_drvreg2, ndr, next_prio);
 }
 
 static
@@ -81,8 +80,17 @@ int sort_drv_by_priority(struct driver_registration * const a, struct driver_reg
 void bfg_devapi_init()
 {
 	_bfg_register_driver(NULL);
-	HASH_SRT(hh , _bfg_drvreg1, sort_drv_by_dname   );
-	HASH_SRT(hh2, _bfg_drvreg2, sort_drv_by_priority);
+#ifdef LL_SORT2
+	LL_SORT2(_bfg_drvreg1, sort_drv_by_dname, next_dname);
+	LL_SORT2(_bfg_drvreg2, sort_drv_by_priority, next_prio);
+#else
+	#define next next_dname
+	LL_SORT(_bfg_drvreg1, sort_drv_by_dname);
+	#undef next
+	#define next next_prio
+	LL_SORT(_bfg_drvreg2, sort_drv_by_priority);
+	#undef next
+#endif
 }
 
 
@@ -997,6 +1005,31 @@ const char *proc_set_device(struct cgpu_info * const proc, char * const optname,
 	return rv;
 }
 
+#ifdef HAVE_CURSES
+const char *proc_set_device_tui_wrapper(struct cgpu_info * const proc, char * const optname, const bfg_set_device_func_t func, const char * const prompt, const char * const success_msg)
+{
+	static char replybuf[0x2001];
+	char * const cvar = curses_input(prompt);
+	if (!cvar)
+		return "Cancelled\n";
+	
+	enum bfg_set_device_replytype success;
+	const char * const reply = func(proc, optname, cvar, replybuf, &success);
+	free(cvar);
+	
+	if (reply)
+	{
+		if (reply != replybuf)
+			snprintf(replybuf, sizeof(replybuf), "%s\n", reply);
+		else
+			tailsprintf(replybuf, sizeof(replybuf), "\n");
+		return replybuf;
+	}
+	
+	return success_msg ?: "Successful\n";
+}
+#endif
+
 #ifdef NEED_BFG_LOWL_VCOM
 bool _serial_detect_all(struct lowlevel_device_info * const info, void * const userp)
 {

+ 10 - 11
deviceapi.h

@@ -5,7 +5,7 @@
 #include <stdint.h>
 #include <sys/time.h>
 
-#include <uthash.h>
+#include <utlist.h>
 
 #include "miner.h"
 
@@ -13,8 +13,8 @@ struct driver_registration;
 struct driver_registration {
 	const struct device_drv *drv;
 	
-	UT_hash_handle hh;   // hash & order by dname
-	UT_hash_handle hh2;  // hash by name, order by priority
+	struct driver_registration *next_dname;
+	struct driver_registration *next_prio;
 	struct driver_registration *next;  // DO NOT USE
 };
 
@@ -22,14 +22,10 @@ extern struct driver_registration *_bfg_drvreg1;
 extern struct driver_registration *_bfg_drvreg2;
 extern void bfg_devapi_init();
 
-#define BFG_FIND_DRV_BY_DNAME(reg, name, namelen)  \
-	HASH_FIND(hh , _bfg_drvreg1, name, namelen, reg)
-#define BFG_FIND_DRV_BY_NAME(reg, name, namelen)  \
-	HASH_FIND(hh2, _bfg_drvreg2, name, namelen, reg)
-#define BFG_FOREACH_DRIVER_BY_DNAME(reg, tmp)  \
-	HASH_ITER(hh , _bfg_drvreg1, reg, tmp)
-#define BFG_FOREACH_DRIVER_BY_PRIORITY(reg, tmp)  \
-	HASH_ITER(hh2, _bfg_drvreg2, reg, tmp)
+#define BFG_FOREACH_DRIVER_BY_DNAME(reg)  \
+	LL_FOREACH2(_bfg_drvreg1, reg, next_dname)
+#define BFG_FOREACH_DRIVER_BY_PRIORITY(reg)  \
+	LL_FOREACH2(_bfg_drvreg2, reg, next_prio)
 
 extern void _bfg_register_driver(const struct device_drv *);
 #define BFG_REGISTER_DRIVER(drv)                \
@@ -95,6 +91,9 @@ struct bfg_set_device_definition {
 	const char *description;
 };
 extern const char *proc_set_device(struct cgpu_info *proc, char *optname, char *newvalue, char *replybuf, enum bfg_set_device_replytype *out_success);
+#ifdef HAVE_CURSES
+extern const char *proc_set_device_tui_wrapper(struct cgpu_info *proc, char *optname, bfg_set_device_func_t, const char *prompt, const char *success_msg);
+#endif
 
 typedef bool(*detectone_func_t)(const char*);
 typedef int(*autoscan_func_t)();

+ 30 - 0
driver-aan.c

@@ -643,3 +643,33 @@ const struct bfg_set_device_definition aan_set_device_funcs[] = {
 	{"diff", aan_set_diff, "desired nonce difficulty"},
 	{NULL},
 };
+
+#ifdef HAVE_CURSES
+void aan_wlogprint_status(struct cgpu_info * const proc)
+{
+	struct thr_info * const thr = proc->thr[0];
+	struct aan_chip_data * const chip = thr->cgpu_data;
+	
+	const double mhz = aan_pll2freq(chip->current_pllreg);
+	wlogprint("Clock speed: %lu\n", (unsigned long)mhz);
+}
+
+void aan_tui_wlogprint_choices(struct cgpu_info * const proc)
+{
+	wlogprint("[C]lock speed ");
+}
+
+const char *aan_tui_handle_choice(struct cgpu_info * const proc, const int input)
+{
+	switch (input)
+	{
+		case 'c': case 'C':
+		{
+			char prompt[0x80];
+			snprintf(prompt, sizeof(prompt), "Set clock speed (%u-%lu)", 1, (unsigned long)AAN_MAX_FREQ);
+			return proc_set_device_tui_wrapper(proc, NULL, aan_set_clock, prompt, NULL);
+		}
+	}
+	return NULL;
+}
+#endif

+ 4 - 0
driver-aan.h

@@ -47,4 +47,8 @@ extern const struct bfg_set_device_definition aan_set_device_funcs[];
 
 extern struct api_data *aan_api_device_status(struct cgpu_info *);
 
+extern void aan_wlogprint_status(struct cgpu_info *proc);
+extern void aan_tui_wlogprint_choices(struct cgpu_info *proc);
+extern const char *aan_tui_handle_choice(struct cgpu_info *proc, int input);
+
 #endif

+ 540 - 0
driver-alchemist.c

@@ -0,0 +1,540 @@
+/*
+ * Copyright 2015 John Stefanopoulos
+ * Copyright 2014-2015 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.
+ */
+
+// THIS DRIVER REQUIRES THE LATEST FIRMWARE FOR AlCHEMINERS DEVELOPED BY JSTEFANOP
+// IT WILL NOT WORK WITH THE STOCK FACTORY FIRMWARE ON THE BOARDS
+// PLEASE CONTACT JSTEFANOP AT MAC DOT COM OR JSTEFANOP ON LITECOINTALK DOT ORG FOR MORE INFO
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#include "deviceapi.h"
+#include "logging.h"
+#include "lowlevel.h"
+#include "lowl-vcom.h"
+#include "util.h"
+
+static const uint8_t alchemist_max_chips = 0x20;
+#define ALCHEMIST_DEFAULT_FREQUENCY  352
+#define ALCHEMIST_MIN_CLOCK          200
+#define ALCHEMIST_MAX_CLOCK          400
+// Number of seconds full board of 1728 cores @ 352mhz takes to scan full range
+#define ALCHEMIST_HASH_SPEED         134.0
+#define ALCHEMIST_MAX_NONCE          0xffffffff
+#define ALCHEMIST_READ_SIZE            9
+#define alchemist_max_clusters_per_chip  6
+#define alchemist_max_cores_per_cluster  9
+static const uint8_t alchemist_g_head[] = {
+	0xd4, 0x59, 0x2d, 0x01, 0x1d, 0x01, 0x8e, 0xa7, 0x4e, 0xbb, 0x17, 0xb8, 0x06, 0x6b, 0x2a, 0x75,
+	0x83, 0x99, 0xd5, 0xf1, 0x9b, 0x5c, 0x60, 0x73, 0xd0, 0x9b, 0x50, 0x0d, 0x92, 0x59, 0x82, 0xad,
+	0xc4, 0xb3, 0xed, 0xd3, 0x52, 0xef, 0xe1, 0x46, 0x67, 0xa8, 0xca, 0x9f, 0x27, 0x9f, 0x63, 0x30,
+	0xcc, 0xbb, 0xb9, 0x10, 0x3b, 0x9e, 0x3a, 0x53, 0x50, 0x76, 0x50, 0x52, 0x08, 0x1d, 0xdb, 0xae,
+	0x89, 0x8f, 0x1e, 0xf6, 0xb8, 0xc6, 0x4f, 0x3b, 0xce, 0xf7, 0x15, 0xf6,    0,    0,    0,    1,
+	   0,    0,    0,    1, 0x8e, 0xa7,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+	   0,    0,    0,    0,    0,    0,    0
+};
+
+BFG_REGISTER_DRIVER(alchemist_drv)
+
+static const struct bfg_set_device_definition alchemist_set_device_funcs_probe[];
+
+struct alchemist_chip {
+	uint8_t chipid;
+	uint8_t global_reg[8];
+	uint16_t chip_mask[alchemist_max_clusters_per_chip];
+	uint32_t clst_offset[alchemist_max_clusters_per_chip];
+	unsigned active_cores;
+	unsigned freq;
+};
+
+static
+void alchemist_chip_init(struct alchemist_chip * const chip, const uint8_t chipid)
+{
+	*chip = (struct alchemist_chip){
+		.chipid = chipid,
+		.global_reg = {0, 4, 0x40, 0, 0, 0, 0, 1},
+		.chip_mask = {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000},
+		.clst_offset = {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+		.active_cores = 1728,
+		.freq = ALCHEMIST_DEFAULT_FREQUENCY,
+	};
+}
+
+static
+void alchemist_reset_board(const char * const devpath)
+{
+	char gpio[8];
+	int fd;
+	char buf[50];
+	
+	// TODO: allow custom reset pin through --set for non-stock controller
+	if (strcmp(devpath, "/dev/ttyO1") == 0)
+		strcpy(gpio, "gpio117");
+	else if (strcmp(devpath, "/dev/ttyO2") == 0)
+		strcpy(gpio, "gpio110");
+	else if (strcmp(devpath, "/dev/ttyO3") == 0)
+		strcpy(gpio, "gpio111");
+	else if (strcmp(devpath, "/dev/ttyO4") == 0)
+		strcpy(gpio, "gpio112");
+	else if (strcmp(devpath, "/dev/ttyUSB0") == 0)
+		strcpy(gpio, "gpio113");
+	else if (strcmp(devpath, "/dev/ttyUSB1") == 0)
+		strcpy(gpio, "gpio114");
+	else if (strcmp(devpath, "/dev/ttyUSB2") == 0)
+		strcpy(gpio, "gpio115");
+	else if (strcmp(devpath, "/dev/ttyUSB3") == 0)
+		strcpy(gpio, "gpio116");
+	else if (strcmp(devpath, "/dev/ttyAMA0") == 0)
+		strcpy(gpio, "gpio25");
+	else
+		return;
+	
+	sprintf(buf, "/sys/class/gpio/%s/value", gpio);
+	
+	fd = open(buf, O_WRONLY);
+	
+	if (write(fd, "0", 1) != 1)
+		applog(LOG_DEBUG, "%s: %s %s", alchemist_drv.dname, "GPIO write error", devpath);
+	cgsleep_ms(100);
+	if (write(fd, "1", 1) != 1)
+		applog(LOG_DEBUG, "%s: %s %s", alchemist_drv.dname, "GPIO write error", devpath);
+	
+	close(fd);
+}
+
+static
+void alchemist_set_diag_mode(struct alchemist_chip * const chip, bool diag_enable)
+{
+	if (diag_enable)
+		chip->global_reg[1] |= 1;
+	else
+		chip->global_reg[1] &= ~1;
+}
+
+static
+bool alchemist_write_global_reg(const int fd, const struct alchemist_chip * const chip)
+{
+	uint8_t buf[113];
+	memset(&buf, 0, 102);
+	memcpy(&buf[102], &chip->global_reg[0], 8);
+	buf[110] = 0;
+	buf[111] = 0xff;
+	buf[112] = chip->chipid;
+	
+	//char output[(sizeof(chip->global_reg) * 2) + 1];
+	//bin2hex(output, chip->global_reg, sizeof(chip->global_reg));
+	//applog(LOG_DEBUG, "GLOBAL REG %s", output);
+	
+	if (write(fd, buf, sizeof(buf)) != sizeof(buf))
+		return false;
+	return true;
+}
+
+static
+bool alchemist_write_cluster_reg(const int fd, const struct alchemist_chip * const chip, const uint16_t cores_active, const uint32_t offset, const uint8_t clstid)
+{
+	uint8_t buf[113];
+	memset(&buf, 0, 104);
+	pk_u16be(buf, 104, cores_active);
+	pk_u32be(buf, 106, offset);
+	buf[110] = clstid;
+	buf[111] = 0xfe;
+	buf[112] = chip->chipid;
+	//applog(LOG_DEBUG, " %u: %u: %u : %u", buf[106], buf[107], buf[108], buf[109]);
+	if (write(fd, buf, sizeof(buf)) != sizeof(buf))
+		return false;
+	return true;
+}
+
+
+static
+bool alchemist_init_pll(const int fd, struct alchemist_chip * const chip)
+{
+	unsigned freq = chip->freq;
+	uint8_t divider = (freq - 16)/16;
+	
+	divider <<= 1;
+	
+	uint8_t bytes1 = 0x60 | ((divider & 0xf0) >> 4);
+	uint8_t bytes2 = 0x20 | ((divider & 0xf0) >> 4);
+	uint8_t bytes3 = 0x00 | ((divider & 0x0f) << 4);
+	
+	pk_u16be(chip->global_reg, 2, 0x4000);
+	chip->global_reg[1] |= 0xc;
+	if (!alchemist_write_global_reg(fd, chip))
+		return false;
+	
+	chip->global_reg[2] = bytes1;
+	chip->global_reg[3] = bytes3;
+	cgsleep_ms(20);
+	if (!alchemist_write_global_reg(fd, chip))
+		return false;
+	
+	chip->global_reg[2] = bytes2;
+	chip->global_reg[1] &= ~8;
+	cgsleep_ms(20);
+	if (!alchemist_write_global_reg(fd, chip))
+		return false;
+	
+	chip->global_reg[1] &= ~4;
+	cgsleep_ms(20);
+	if (!alchemist_write_global_reg(fd, chip))
+		return false;
+	
+	return true;
+}
+
+static
+bool alchemist_send_golden(const int fd, const struct alchemist_chip * const chip, const bool diag, const void * const data, const void * const target_p)
+{
+	uint8_t buf[113];
+	const uint8_t * const target = target_p;
+	
+	memcpy(buf, data, 80);
+	if (target && !target[0x1f])
+		memcpy(&buf[80], target, 0x20);
+	else
+	{
+		memset(&buf[80], 0xff, 0x1f);
+		buf[111] = 0;
+	}
+	buf[112] = chip->chipid;
+	if (diag)
+		buf[112] |= 0x80;
+	if (write(fd, buf, sizeof(buf)) != sizeof(buf))
+		return false;
+	return true;
+}
+
+static
+bool alchemist_send_work(const struct thr_info * const thr, struct work * const work)
+{
+	struct cgpu_info *device = thr->cgpu;
+	uint8_t buf[113];
+	uint8_t cmd[113];
+	const uint8_t * const target = work->target;
+	
+	unsigned char swpdata[80];
+	
+	buf[0] = 0xff;
+	
+	memset(&buf[1], 0, 0x18);
+	memcpy(&buf[25], &target[24], 0x8);
+	//pk_u64be(buf, 25, 0x0000feff01000000);
+	
+	swap32tobe(swpdata, work->data, 80/4);
+	memcpy(&buf[33], swpdata, 80);
+	
+	for (int i = 0; i<113; i++) {
+		cmd[i] = buf[112 - i];
+	}
+	
+	//char output[(sizeof(cmd) * 2) + 1];
+	//bin2hex(output, cmd, sizeof(cmd));
+	//applog(LOG_DEBUG, "OUTPUT %s", output);
+	
+	if (write(device->device_fd, cmd, sizeof(cmd)) != sizeof(cmd))
+		return false;
+	
+	work->blk.nonce = ALCHEMIST_MAX_NONCE;
+	
+	return true;
+}
+
+static
+bool alchemist_detect_one(const char * const devpath)
+{
+	struct alchemist_chip *chips = NULL;
+	const int fd = serial_open(devpath, 115200, 1, true);
+	if (fd < 0)
+		return_via_applog(err, , LOG_DEBUG, "%s: %s %s", alchemist_drv.dname, "Failed to open", devpath);
+	
+	applog(LOG_DEBUG, "%s: %s %s", alchemist_drv.dname, "Successfully opened", devpath);
+	
+	alchemist_reset_board(devpath);
+	
+	// Init chips, setup PLL, and scan for good cores
+	chips = malloc(alchemist_max_chips * sizeof(*chips));
+	
+	struct alchemist_chip * const dummy_chip = &chips[0];
+	alchemist_chip_init(dummy_chip, 0);
+	
+	// pick up any user-defined settings passed in via --set
+	drv_set_defaults(&alchemist_drv, alchemist_set_device_funcs_probe, dummy_chip, devpath, detectone_meta_info.serial, 1);
+	
+	unsigned freq = dummy_chip->freq;
+	
+	unsigned total_cores = 0;
+	{
+		uint8_t buf[9];
+		for (unsigned i = 0; i < alchemist_max_chips; ++i)
+		{
+			struct alchemist_chip * const chip = &chips[i];
+			alchemist_chip_init(chip, i);
+			chip->freq = freq;
+			alchemist_set_diag_mode(chip, true);
+			if (!alchemist_init_pll(fd, chip))
+				return_via_applog(err, , LOG_DEBUG, "%s: Failed to (%s) %s", alchemist_drv.dname, "init PLL", devpath);
+			if (!alchemist_send_golden(fd, chip, true, alchemist_g_head, NULL))
+				return_via_applog(err, , LOG_DEBUG, "%s: Failed to (%s) %s", alchemist_drv.dname, "send scan job", devpath);
+			
+			while (serial_read(fd, buf, 9) == 9)
+			{
+				const uint8_t chipid = buf[8];
+				if (chipid >= alchemist_max_chips)
+					applog(LOG_DEBUG, "%s: Bad %s id (%u) during scan of %s chip %u", alchemist_drv.dname, "chip", chipid, devpath, i);
+				const uint8_t clsid = buf[7];
+				if (clsid >= alchemist_max_clusters_per_chip)
+					applog(LOG_DEBUG, "%s: Bad %s id (%u) during scan of %s chip %u", alchemist_drv.dname, "cluster", clsid, devpath, i);
+				const uint8_t coreid = buf[6];
+				if (coreid >= alchemist_max_cores_per_cluster)
+					applog(LOG_DEBUG, "%s: Bad %s id (%u) during scan of %s chip %u", alchemist_drv.dname, "core", coreid, devpath, i);
+				
+				if (buf[0] != 0xd9 || buf[1] != 0xeb || buf[2] != 0x86 || buf[3] != 0x63) {
+					//chips[i].chip_good[clsid][coreid] = false;
+					applog(LOG_DEBUG, "%s: Bad %s at core (%u) during scan of %s chip %u cluster %u", alchemist_drv.dname, "nonce", coreid, devpath, i, clsid);
+				} else {
+					++total_cores;
+					chips[i].chip_mask[clsid] |= (1 << coreid);
+				}
+			}
+		}
+	}
+	
+	applog(LOG_DEBUG, "%s: Identified %d cores on %s", alchemist_drv.dname, total_cores, devpath);
+	if (!total_cores)
+		goto err;
+	
+	alchemist_reset_board(devpath);
+	
+	// config nonce ranges per cluster based on core responses
+	unsigned mutiple = ALCHEMIST_MAX_NONCE / total_cores;
+	uint32_t n_offset = 0x00000000;
+	
+	for (unsigned i = 0; i < alchemist_max_chips; ++i)
+	{
+		struct alchemist_chip * const chip = &chips[i];
+		
+		chips[i].active_cores = total_cores;
+		
+		alchemist_set_diag_mode(chip, false);
+		if (!alchemist_init_pll(fd, chip))
+			return_via_applog(err, , LOG_DEBUG, "%s: Failed to (%s) %s", alchemist_drv.dname, "init PLL", devpath);
+		
+		cgsleep_ms(10);
+		
+		for (unsigned x = 0; x < alchemist_max_clusters_per_chip; ++x) {
+			unsigned gc = 0;
+			
+			uint16_t core_mask = chips[i].chip_mask[x];
+			chips[i].clst_offset[x] = n_offset;
+			
+			//applog(LOG_DEBUG, "OFFSET %u CHIP %u CLUSTER %u", n_offset, i, x);
+			
+			if (!alchemist_write_cluster_reg(fd, chip, core_mask, n_offset, x))
+				return_via_applog(err, , LOG_DEBUG, "%s: Failed to (%s) %s", alchemist_drv.dname, "send config register", devpath);
+			
+			for (unsigned z = 0; z < 15; ++z) {
+				if (core_mask & 0x0001)
+					gc += 1;
+				core_mask >>= 1;
+			}
+			
+			n_offset += mutiple * gc;
+		}
+	}
+	
+	if (serial_claim_v(devpath, &alchemist_drv))
+		goto err;
+	
+	//serial_close(fd);
+	struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
+	*cgpu = (struct cgpu_info){
+		.drv = &alchemist_drv,
+		.device_path = strdup(devpath),
+		.deven = DEV_ENABLED,
+		.procs = 1,
+		.threads = 1,
+		.device_data = chips,
+	};
+	// NOTE: Xcode's clang has a bug where it cannot find fields inside anonymous unions (more details in fpgautils)
+	cgpu->device_fd = fd;
+	
+	return add_cgpu(cgpu);
+
+err:
+	if (fd >= 0)
+		serial_close(fd);
+	free(chips);
+	return false;
+}
+
+/*
+ * scanhash mining loop
+ */
+
+static
+void alchemist_submit_nonce(struct thr_info * const thr, const uint8_t buf[9], struct work * const work)
+{
+	struct cgpu_info *device = thr->cgpu;
+	struct alchemist_chip *chips = device->device_data;
+	
+	uint32_t nonce = *(uint32_t *)buf;
+	nonce = bswap_32(nonce);
+	
+	submit_nonce(thr, work, nonce);
+	
+	// hashrate calc
+	
+	const uint8_t chipid = buf[8];
+	const uint8_t clstid = buf[7];
+	uint32_t range = chips[chipid].clst_offset[clstid];
+	uint32_t mutiple = ALCHEMIST_MAX_NONCE / chips[chipid].active_cores;
+	
+	double diff_mutiple = .5/work->work_difficulty;
+	
+	for (unsigned x = 0; x < alchemist_max_cores_per_cluster; ++x) {
+		if (nonce > range && nonce < (range + mutiple)) {
+			uint64_t hashes = (nonce - range) * chips[chipid].active_cores * diff_mutiple;
+			
+			if (hashes > ALCHEMIST_MAX_NONCE)
+				hashes = 1;
+			
+			hashes_done2(thr, hashes, NULL);
+		}
+		
+		range += mutiple;
+	}
+}
+
+// send work to the device
+static
+int64_t alchemist_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
+{
+	struct cgpu_info *device = thr->cgpu;
+	int fd = device->device_fd;
+	struct alchemist_chip *chips = device->device_data;
+	struct timeval start_tv, nonce_range_tv;
+	
+	// amount of time it takes this device to scan a nonce range:
+	uint32_t nonce_full_range_sec = ALCHEMIST_HASH_SPEED * 352.0 / ALCHEMIST_DEFAULT_FREQUENCY * 1728.0 / chips[0].active_cores;
+	// timer to break out of scanning should we close in on an entire nonce range
+	// should break out before the range is scanned, so we are doing 95% of the range
+	uint64_t nonce_near_range_usec = (nonce_full_range_sec * 1000000. * 0.95);
+	timer_set_delay_from_now(&nonce_range_tv, nonce_near_range_usec);
+	
+	// start the job
+	timer_set_now(&start_tv);
+	
+	if (!alchemist_send_work(thr, work)) {
+		applog(LOG_DEBUG, "Failed to start job");
+		dev_error(device, REASON_DEV_COMMS_ERROR);
+	}
+	
+	uint8_t buf[9];
+	int read = 0;
+	bool range_nearly_scanned = false;
+	
+	while (!thr->work_restart                                              // true when new work is available (miner.c)
+	    && ((read = serial_read(fd, buf, 9)) >= 0)                         // only check for failure - allow 0 bytes
+	    && !(range_nearly_scanned = timer_passed(&nonce_range_tv, NULL)))  // true when we've nearly scanned a nonce range
+	{
+		if (read == 0)
+			continue;
+		
+		if (read == 9) {
+			alchemist_submit_nonce(thr, buf, work);
+		}
+		else
+			applog(LOG_ERR, "%"PRIpreprv": Unrecognized response", device->proc_repr);
+	}
+	
+	if (read == -1)
+	{
+		applog(LOG_ERR, "%s: Failed to read result", device->dev_repr);
+		dev_error(device, REASON_DEV_COMMS_ERROR);
+	}
+	
+	return 0;
+}
+
+/*
+ * setup & shutdown
+ */
+
+static
+bool alchemist_lowl_probe(const struct lowlevel_device_info * const info)
+{
+	return vcom_lowl_probe_wrapper(info, alchemist_detect_one);
+}
+
+static
+void alchemist_thread_shutdown(struct thr_info *thr)
+{
+	struct cgpu_info *device = thr->cgpu;
+	
+	alchemist_reset_board(device->device_path);
+	
+	serial_close(device->device_fd);
+}
+
+/*
+ * specify settings / options via RPC or command line
+ */
+
+// support for --set
+// must be set before probing the device
+
+// for setting clock and chips during probe / detect
+
+static
+const char *alchemist_set_clock(struct cgpu_info * const device, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	struct alchemist_chip * const chip = device->device_data;
+	int val = atoi(setting);
+	
+	if (val < ALCHEMIST_MIN_CLOCK || val > ALCHEMIST_MAX_CLOCK || (val%16)) {
+		sprintf(replybuf, "invalid clock: '%s' valid range %d-%d and a mutiple of 16",
+		        setting, ALCHEMIST_MIN_CLOCK, ALCHEMIST_MAX_CLOCK);
+		return replybuf;
+	} else
+		chip->freq = val;
+	
+	return NULL;
+}
+
+static
+const struct bfg_set_device_definition alchemist_set_device_funcs_probe[] = {
+	{ "clock", alchemist_set_clock, NULL },
+	{ NULL },
+};
+
+struct device_drv alchemist_drv = {
+	.dname = "alchemist",
+	.name = "ALC",
+	.drv_min_nonce_diff = common_scrypt_min_nonce_diff,
+	// detect device
+	.lowl_probe = alchemist_lowl_probe,
+	// specify mining type - scanhash
+	.minerloop = minerloop_scanhash,
+	
+	// scanhash mining hooks
+	.scanhash = alchemist_scanhash,
+	
+	// teardown device
+	.thread_shutdown = alchemist_thread_shutdown,
+};

+ 79 - 14
driver-antminer.c

@@ -42,6 +42,22 @@ BFG_REGISTER_DRIVER(compac_drv)
 static
 const struct bfg_set_device_definition antminer_set_device_funcs[];
 
+static const char *bm1382_chips[] = {
+	"BM1382",
+	"BM1384",
+	NULL
+};
+
+static bool antminer_chip_has_bm1382_freq_register(const char * const prodstr)
+{
+	for (const char **chipname = bm1382_chips; *chipname; ++chipname) {
+		if (strstr(prodstr, *chipname)) {
+			return true;
+		}
+	}
+	return false;
+}
+
 static
 bool antminer_detect_one_with_drv(const char * const devpath, struct device_drv * const drv)
 {
@@ -56,6 +72,8 @@ bool antminer_detect_one_with_drv(const char * const devpath, struct device_drv
 		.do_icarus_timing = true,
 		.read_size = 5,
 		.reopen_mode = IRM_NEVER,
+		
+		.has_bm1382_freq_register = antminer_chip_has_bm1382_freq_register(detectone_meta_info.product),
 	};
 	
 	struct cgpu_info * const dev = icarus_detect_custom(devpath, drv, info);
@@ -138,26 +156,35 @@ char *antminer_get_clock(struct cgpu_info *cgpu, char *replybuf)
 static
 const char *antminer_set_clock(struct cgpu_info * const cgpu, const char * const optname, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const out_success)
 {
+	struct ICARUS_INFO * const info = cgpu->device_data;
+	
 	if (!setting || !*setting)
 		return "missing clock setting";
 	
-	// For now we only allow hex values that use BITMAINtech's lookup table
-	// This means values should be prefixed with an x so that later we can
-	// accept and distinguish decimal values
-	if (setting[0] != 'x')
+	uint8_t reg_data[2];
+	
+	if (setting[0] == 'x')
 	{
-		sprintf(replybuf, "invalid clock: '%s' data must be prefixed with an x", setting);
-		return replybuf;
+		// remove leading character
+		const char * const hex_setting = &setting[1];
+		
+		if (!hex2bin(reg_data, hex_setting, sizeof(reg_data)))
+		{
+			sprintf(replybuf, "invalid clock: '%s' data must be a hexadecimal value", hex_setting);
+			return replybuf;
+		}
 	}
-	
-	//remove leading character
-	const char * const hex_setting = &setting[1];
-
-	uint8_t reg_data[4] = {0};
-	
-	if (!hex2bin(reg_data, hex_setting, strlen(hex_setting) / 2))
+	else
+	if (info->has_bm1382_freq_register)
 	{
-		sprintf(replybuf, "invalid clock: '%s' data must be a hexadecimal value", hex_setting);
+		const double mhz = atof(setting);
+		if (!bm1382_freq_to_reg_data(reg_data, mhz)) {
+			return "invalid clock";
+		}
+	}
+	else
+	{
+		sprintf(replybuf, "invalid clock: '%s' data must be prefixed with an x", setting);
 		return replybuf;
 	}
 	
@@ -234,6 +261,16 @@ invalid_voltage:
 	return NULL;
 }
 
+static
+const char *antminer_set_chip(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct ICARUS_INFO * const info = proc->device_data;
+	
+	info->has_bm1382_freq_register = antminer_chip_has_bm1382_freq_register(newvalue);
+	
+	return NULL;
+}
+
 static
 void antminer_flash_led(const struct cgpu_info *antminer)
 {
@@ -265,6 +302,7 @@ bool antminer_identify(struct cgpu_info *antminer)
 
 static
 const struct bfg_set_device_definition antminer_set_device_funcs[] = {
+	{"chip", antminer_set_chip, "chip unit is based on (BM1380, BM1382, etc)"},
 	{"baud"         , icarus_set_baud         , "serial baud rate"},
 	{"work_division", icarus_set_work_division, "number of pieces work is split into"},
 	{"reopen"       , icarus_set_reopen       , "how often to reopen device: never, timeout, cycle, (or now for a one-shot reopen)"},
@@ -274,6 +312,28 @@ const struct bfg_set_device_definition antminer_set_device_funcs[] = {
 	{NULL},
 };
 
+#ifdef HAVE_CURSES
+static
+void antminer_tui_wlogprint_choices(struct cgpu_info * const proc)
+{
+	struct ICARUS_INFO * const info = proc->device_data;
+	
+	if (info->has_bm1382_freq_register)
+		wlogprint("[C]lock speed ");
+}
+
+static
+const char *antminer_tui_handle_choice(struct cgpu_info * const proc, const int input)
+{
+	switch (input)
+	{
+		case 'c': case 'C':
+			return proc_set_device_tui_wrapper(proc, NULL, antminer_set_clock, "Set clock speed", NULL);
+	}
+	return NULL;
+}
+#endif
+
 static
 bool compac_lowl_match(const struct lowlevel_device_info * const info)
 {
@@ -300,9 +360,14 @@ void antminer_drv_init()
 	antminer_drv.lowl_match = antminer_lowl_match;
 	antminer_drv.lowl_probe = antminer_lowl_probe;
 	antminer_drv.identify_device = antminer_identify;
+#ifdef HAVE_CURSES
+	antminer_drv.proc_tui_wlogprint_choices = antminer_tui_wlogprint_choices;
+	antminer_drv.proc_tui_handle_choice = antminer_tui_handle_choice;
+#endif
 	++antminer_drv.probe_priority;
 	
 	compac_drv = antminer_drv;
+	compac_drv.dname = "compac";
 	compac_drv.name = "CBM";
 	compac_drv.lowl_match = compac_lowl_match;
 	compac_drv.lowl_probe = compac_lowl_probe;

+ 42 - 0
driver-avalon.c

@@ -494,6 +494,42 @@ const struct bfg_set_device_definition avalon_set_device_funcs[] = {
 	{NULL},
 };
 
+#ifdef HAVE_CURSES
+static
+void avalon_wlogprint_status(struct cgpu_info * const proc)
+{
+	struct avalon_info *info = proc->device_data;
+	
+	if (((info->temp0?1:0) + (info->temp1?1:0) + (info->temp2?1:0)) > 1)
+	{
+		wlogprint("Temperatures:");
+		if (info->temp0)  wlogprint(" %uC", (unsigned)info->temp0);
+		if (info->temp1)  wlogprint(" %uC", (unsigned)info->temp1);
+		if (info->temp2)  wlogprint(" %uC", (unsigned)info->temp2);
+	}
+	wlogprint("\n");
+	
+	wlogprint("Clock speed: %d\n", info->frequency);
+}
+
+static
+void avalon_tui_wlogprint_choices(struct cgpu_info * const proc)
+{
+	wlogprint("[C]lock speed ");
+}
+
+static
+const char *avalon_tui_handle_choice(struct cgpu_info * const proc, const int input)
+{
+	switch (input)
+	{
+		case 'c': case 'C':
+			return proc_set_device_tui_wrapper(proc, NULL, avalon_set_clock, "Set clock speed (256, 270, 282, 300, 325, 350, or 375)", NULL);
+	}
+	return NULL;
+}
+#endif
+
 /* Non blocking clearing of anything in the buffer */
 static void avalon_clear_readbuf(int fd)
 {
@@ -1006,4 +1042,10 @@ struct device_drv avalon_drv = {
 	.get_api_stats = avalon_api_stats,
 	.reinit_device = avalon_init,
 	.thread_shutdown = avalon_shutdown,
+	
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = avalon_wlogprint_status,
+	.proc_tui_wlogprint_choices = avalon_tui_wlogprint_choices,
+	.proc_tui_handle_choice = avalon_tui_handle_choice,
+#endif
 };

+ 2 - 18
driver-avalonmm.c

@@ -895,24 +895,8 @@ void avalonmm_tui_wlogprint_choices(struct cgpu_info * const proc)
 	wlogprint("[V]oltage ");
 }
 
-static
-const char *avalonmm_tui_wrapper(struct cgpu_info * const proc, bfg_set_device_func_t func, const char * const prompt)
-{
-	static char replybuf[0x20];
-	char * const cvar = curses_input(prompt);
-	if (!cvar)
-		return "Cancelled\n";
-	
-	const char *reply = func(proc, NULL, cvar, NULL, NULL);
-	free(cvar);
-	if (reply)
-	{
-		snprintf(replybuf, sizeof(replybuf), "%s\n", reply);
-		return replybuf;
-	}
-	
-	return "Successful\n";
-}
+#define avalonmm_tui_wrapper(proc, func, prompt) \
+	proc_set_device_tui_wrapper(proc, NULL, func, prompt, NULL)
 
 static
 const char *avalonmm_tui_handle_choice(struct cgpu_info * const proc, const int input)

+ 34 - 0
driver-bitforce.c

@@ -12,6 +12,7 @@
 
 #include <ctype.h>
 #include <limits.h>
+#include <math.h>
 #include <pthread.h>
 #include <stdbool.h>
 #include <stdint.h>
@@ -1810,6 +1811,35 @@ static bool bitforce_thread_init(struct thr_info *thr)
 	return true;
 }
 
+static
+const char *bitforce_set_voltage(struct cgpu_info *proc, const char *optname, const char *newvalue, char *replybuf, enum bfg_set_device_replytype *out_success)
+{
+	pthread_mutex_t *mutexp = &proc->device->device_mutex;
+	char cmd[3] = "VFX";
+	
+	const unsigned mV = round(atof(newvalue) * 1000);
+	static const unsigned n[] = {750, 730, 720, 700, 680, 670, 662, 650, 643, 630, 620, 600, 580, 560, 550, 540};
+	for (int i = 0; ; ++i)
+	{
+		if (i >= 0x10)
+			return "Voltage must be from 0.54 to 0.75";
+		if (mV >= n[i])
+		{
+			cmd[1] -= i;
+			break;
+		}
+	}
+	
+	mutex_lock(mutexp);
+	bitforce_cmd1b(proc, replybuf, 8000, cmd, 3);
+	mutex_unlock(mutexp);
+	
+	if (!strncasecmp(replybuf, "OK", 2))
+		return NULL;
+	
+	return replybuf;
+}
+
 #ifdef HAVE_CURSES
 static
 void bitforce_tui_wlogprint_choices(struct cgpu_info *cgpu)
@@ -1817,6 +1847,7 @@ void bitforce_tui_wlogprint_choices(struct cgpu_info *cgpu)
 	struct bitforce_data *data = cgpu->device_data;
 	if (data->supports_fanspeed)
 		wlogprint("[F]an control ");
+	wlogprint("[V]oltage ");
 }
 
 static
@@ -1851,6 +1882,8 @@ const char *bitforce_tui_handle_choice(struct cgpu_info *cgpu, int input)
 			mutex_unlock(mutexp);
 			return replybuf;
 		}
+		case 'v': case 'V':
+			return proc_set_device_tui_wrapper(cgpu, NULL, bitforce_set_voltage, "Set voltage (0.54-0.75 V)", "Requested voltage change");
 	}
 	return NULL;
 }
@@ -1978,6 +2011,7 @@ const char *bitforce_rpc_send_cmd1(struct cgpu_info * const proc, const char * c
 
 static const struct bfg_set_device_definition bitforce_set_device_funcs[] = {
 	{"fanmode", bitforce_set_fanmode, "range 0-5 (low to fast) or 9 (auto)"},
+	{"voltage", bitforce_set_voltage, "range 0.54-0.75 V"},
 	{"_cmd1", bitforce_rpc_send_cmd1, NULL},
 	{NULL},
 };

+ 1873 - 0
driver-bitmain.c

@@ -0,0 +1,1873 @@
+/*
+ * Copyright 2012-2014 Lingchao Xu
+ * Copyright 2015 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 <ctype.h>
+#include <limits.h>
+#include <math.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <unistd.h>
+#ifndef WIN32
+  #include <sys/select.h>
+  #include <termios.h>
+  #include <sys/stat.h>
+  #include <fcntl.h>
+  #ifndef O_CLOEXEC
+    #define O_CLOEXEC 0
+  #endif
+#else
+  #include "compat.h"
+  #include <windows.h>
+  #include <io.h>
+#endif
+
+#include <curl/curl.h>
+#include <uthash.h>
+
+#include "deviceapi.h"
+#include "miner.h"
+#include "driver-bitmain.h"
+#include "lowl-vcom.h"
+#include "util.h"
+
+const bool opt_bitmain_hwerror = true;
+const unsigned bitmain_poll_interval_us = 10000;
+
+BFG_REGISTER_DRIVER(bitmain_drv)
+static const struct bfg_set_device_definition bitmain_set_device_funcs_init[];
+
+#define htole8(x) (x)
+
+#define BITMAIN_USING_CURL  -2
+
+static
+struct cgpu_info *btm_alloc_cgpu(struct device_drv *drv, int threads)
+{
+	struct cgpu_info *cgpu = calloc(1, sizeof(*cgpu));
+
+	if (unlikely(!cgpu))
+		quit(1, "Failed to calloc cgpu for %s in usb_alloc_cgpu", drv->dname);
+
+	cgpu->drv = drv;
+	cgpu->deven = DEV_ENABLED;
+	cgpu->threads = threads;
+
+	cgpu->device_fd = -1;
+
+	struct bitmain_info *info = malloc(sizeof(*info));
+	if (unlikely(!info))
+		quit(1, "Failed to calloc bitmain_info data");
+	cgpu->device_data = info;
+	
+	*info = (struct bitmain_info){
+		.chain_num = BITMAIN_DEFAULT_CHAIN_NUM,
+		.asic_num = BITMAIN_DEFAULT_ASIC_NUM,
+		.timeout = BITMAIN_DEFAULT_TIMEOUT,
+		.frequency = BITMAIN_DEFAULT_FREQUENCY,
+		.voltage[0] = BITMAIN_DEFAULT_VOLTAGE0,
+		.voltage[1] = BITMAIN_DEFAULT_VOLTAGE1,
+		
+		.packet_max_nonce = BITMAIN_MAX_PACKET_MAX_NONCE,
+		
+		.diff = 255,
+		.lowest_goal_diff = 255,
+		.work_restart = true,
+	};
+	sprintf(info->frequency_t, "%d", BITMAIN_DEFAULT_FREQUENCY),
+	strcpy(info->voltage_t, BITMAIN_DEFAULT_VOLTAGE_T);
+	
+	return cgpu;
+}
+
+static curl_socket_t bitmain_grab_socket_opensocket_cb(void *clientp, __maybe_unused curlsocktype purpose, struct curl_sockaddr *addr)
+{
+	struct bitmain_info * const info = clientp;
+	curl_socket_t sck = bfg_socket(addr->family, addr->socktype, addr->protocol);
+	info->curl_sock = sck;
+	return sck;
+}
+
+static
+bool btm_init(struct cgpu_info *cgpu, const char * devpath)
+{
+	applog(LOG_DEBUG, "btm_init cgpu->device_fd=%d", cgpu->device_fd);
+	int fd = -1;
+	if(cgpu->device_fd >= 0) {
+		return false;
+	}
+	struct bitmain_info *info = cgpu->device_data;
+	if (!strncmp(devpath, "ip:", 3)) {
+		CURL *curl = curl_easy_init();
+		if (!curl)
+			applogr(false, LOG_ERR, "%s: curl_easy_init failed", cgpu->drv->dname);
+		
+		// CURLINFO_LASTSOCKET is broken on Win64 (which has a wider SOCKET type than curl_easy_getinfo returns), so we use this hack for now
+		info->curl_sock = -1;
+		curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, bitmain_grab_socket_opensocket_cb);
+		curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, info);
+		
+		curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
+		curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 5);
+		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
+		curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
+		curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1);
+		curl_easy_setopt(curl, CURLOPT_URL, &devpath[3]);
+		if (curl_easy_perform(curl)) {
+			curl_easy_cleanup(curl);
+			applogr(false, LOG_ERR, "%s: curl_easy_perform failed for %s", cgpu->drv->dname, &devpath[3]);
+		}
+		cgpu->device_path = strdup(devpath);
+		cgpu->device_fd = BITMAIN_USING_CURL;
+		info->device_curl = curl;
+		return true;
+	}
+	fd = serial_open(devpath, 0, 1, false);
+	if(fd == -1) {
+		applog(LOG_DEBUG, "%s open %s error %d",
+				cgpu->drv->dname, devpath, errno);
+		return false;
+	}
+	cgpu->device_path = strdup(devpath);
+	cgpu->device_fd = fd;
+	applog(LOG_DEBUG, "btm_init open device fd = %d", cgpu->device_fd);
+	return true;
+}
+
+static
+void btm_uninit(struct cgpu_info *cgpu)
+{
+	struct bitmain_info * const info = cgpu->device_data;
+	
+	applog(LOG_DEBUG, "BTM uninit %s%i", cgpu->drv->name, cgpu->device_fd);
+
+	// May have happened already during a failed initialisation
+	//  if release_cgpu() was called due to a USB NODEV(err)
+	if (cgpu->device_fd >= 0) {
+		serial_close(cgpu->device_fd);
+		cgpu->device_fd = -1;
+	}
+	if (info->device_curl) {
+		curl_easy_cleanup(info->device_curl);
+		info->device_curl = NULL;
+	}
+	if(cgpu->device_path) {
+		free((char*)cgpu->device_path);
+		cgpu->device_path = NULL;
+	}
+}
+
+bool bitmain_curl_all(const bool is_recv, const int fd, CURL * const curl, void *p, size_t remsz)
+{
+	CURLcode (* const func)(CURL *, void *, size_t, size_t *) = is_recv ? (void*)curl_easy_recv : (void*)curl_easy_send;
+	CURLcode r;
+	size_t sz;
+	while (remsz) {
+		fd_set otherfds, thisfds;
+		FD_ZERO(&otherfds);
+		FD_ZERO(&thisfds);
+		FD_SET(fd, &thisfds);
+		select(fd + 1, is_recv ? &thisfds : &otherfds, is_recv ? &otherfds : &thisfds, &thisfds, NULL);
+		r = func(curl, p, remsz, &sz);
+		switch (r) {
+			case CURLE_OK:
+				remsz -= sz;
+				p += sz;
+				break;
+			case CURLE_AGAIN:
+				break;
+			default:
+				return false;
+		}
+	}
+	return true;
+}
+
+static
+int btm_read(struct cgpu_info * const cgpu, void * const buf, const size_t bufsize)
+{
+	int err = 0;
+	//applog(LOG_DEBUG, "btm_read ----- %d -----", bufsize);
+	if (unlikely(cgpu->device_fd == BITMAIN_USING_CURL)) {
+		struct bitmain_info * const info = cgpu->device_data;
+		uint8_t headbuf[5];
+		headbuf[0] = 0;
+		pk_u32be(headbuf, 1, bufsize);
+		if (!bitmain_curl_all(false, info->curl_sock, info->device_curl, headbuf, sizeof(headbuf)))
+			return -1;
+		if (!bitmain_curl_all( true, info->curl_sock, info->device_curl, headbuf, 4))
+			return -1;
+		if (headbuf[0] == 0xff && headbuf[1] == 0xff && headbuf[2] == 0xff && headbuf[3] == 0xff)
+			return -1;
+		size_t sz = upk_u32be(headbuf, 0);
+		if (!bitmain_curl_all( true, info->curl_sock, info->device_curl, buf, sz))
+			return -1;
+		return sz;
+	}
+	err = read(cgpu->device_fd, buf, bufsize);
+	return err;
+}
+
+static
+int btm_write(struct cgpu_info * const cgpu, void * const buf, const size_t bufsize)
+{
+	int err = 0;
+	//applog(LOG_DEBUG, "btm_write ----- %d -----", bufsize);
+	if (unlikely(cgpu->device_fd == BITMAIN_USING_CURL)) {
+		struct bitmain_info * const info = cgpu->device_data;
+		uint8_t headbuf[5];
+		headbuf[0] = 1;
+		pk_u32be(headbuf, 1, bufsize);
+		if (!bitmain_curl_all(false, info->curl_sock, info->device_curl, headbuf, sizeof(headbuf)))
+			return -1;
+		if (!bitmain_curl_all(false, info->curl_sock, info->device_curl, buf, bufsize))
+			return -1;
+		if (!bitmain_curl_all( true, info->curl_sock, info->device_curl, headbuf, 4))
+			return -1;
+		if (headbuf[0] == 0xff && headbuf[1] == 0xff && headbuf[2] == 0xff && headbuf[3] == 0xff)
+			return -1;
+		return upk_u32be(headbuf, 0);
+	}
+	err = write(cgpu->device_fd, buf, bufsize);
+	return err;
+}
+
+#ifdef WIN32
+#define BITMAIN_TEST
+#endif
+
+#define BITMAIN_TEST_PRINT_WORK 0
+#ifdef BITMAIN_TEST
+#define BITMAIN_TEST_NUM 19
+#define BITMAIN_TEST_USENUM 1
+int g_test_index = 0;
+const char btm_work_test_data[BITMAIN_TEST_NUM][256] = {
+		"00000002ddc1ce5579dbec17f17fbb8f31ae218a814b2a0c1900f0d90000000100000000b58aa6ca86546b07a5a46698f736c7ca9c0eedc756d8f28ac33c20cc24d792675276f879190afc85b6888022000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b190000000000000000eb2d45233c5b02de50ddcb9049ba16040e0ba00e9750a474eec75891571d925b52dfda4a190266667145b02f000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b19000000000000000090c7d3743e0b0562e4f56d3dd35cece3c5e8275d0abb21bf7e503cb72bd7ed3b52dfda4a190266667bbb58d7000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b1900000000000000006e0561da06022bfbb42c5ecd74a46bfd91934f201b777e9155cc6c3674724ec652dfda4a19026666a0cd827b000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b1900000000000000000312f42ce4964cc23f2d8c039f106f25ddd58e10a1faed21b3bba4b0e621807b52dfda4a1902666629c9497d000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b19000000000000000033093a6540dbe8f7f3d19e3d2af05585ac58dafad890fa9a942e977334a23d6e52dfda4a190266665ae95079000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b190000000000000000bd7893057d06e69705bddf9a89c7bac6b40c5b32f15e2295fc8c5edf491ea24952dfda4a190266664b89b4d3000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b19000000000000000075e66f533e53837d14236a793ee4e493985642bc39e016b9e63adf14a584a2aa52dfda4a19026666ab5d638d000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b190000000000000000d936f90c5db5f0fe1d017344443854fbf9e40a07a9b7e74fedc8661c23162bff52dfda4a19026666338e79cb000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b190000000000000000d2c1a7d279a4355b017bc0a4b0a9425707786729f21ee18add3fda4252a31a4152dfda4a190266669bc90806000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b190000000000000000ad36d19f33d04ca779942843890bc3b083cec83a4b60b6c45cf7d21fc187746552dfda4a1902666675d81ab7000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b19000000000000000093b809cf82b76082eacb55bc35b79f31882ed0976fd102ef54783cd24341319b52dfda4a1902666642ab4e42000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b1900000000000000007411ff315430a7bbf41de8a685d457e82d5177c05640d6a4436a40f39e99667852dfda4a190266662affa4b5000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b1900000000000000001ad0db5b9e1e2b57c8d3654c160f5a51067521eab7e340a270639d97f00a3fa252dfda4a1902666601a47bb6000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b19000000000000000022e055c442c46bbe16df68603a26891f6e4cf85b90102b39fd7cadb602b4e34552dfda4a1902666695d33cea000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b1900000000000000009c8baf5a8a1e16de2d6ae949d5fec3ed751f10dcd4c99810f2ce08040fb9e31d52dfda4a19026666fe78849d000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b190000000000000000e5655532b414887f35eb4652bc7b11ebac12891f65bc08cbe0ce5b277b9e795152dfda4a19026666fcc0d1d1000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b190000000000000000f272c5508704e2b62dd1c30ea970372c40bf00f9203f9bf69d456b4a7fbfffe352dfda4a19026666c03d4399000000800000000000000000000000000000000000000000000000000000000000000000",
+		"0000000256ccc4c8aeae2b1e41490bc352893605f284e4be043f7b190000000000000000fca3b4531ba627ad9b0e23cdd84c888952c23810df196e9c6db0bcecba6a830952dfda4a19026666c14009cb000000800000000000000000000000000000000000000000000000000000000000000000"
+};
+const char btm_work_test_midstate[BITMAIN_TEST_NUM][256] = {
+		"2d8738e7f5bcf76dcb8316fec772e20e240cd58c88d47f2d3f5a6a9547ed0a35",
+		"d31b6ce09c0bfc2af6f3fe3a03475ebefa5aa191fa70a327a354b2c22f9692f1",
+		"84a8c8224b80d36caeb42eff2a100f634e1ff873e83fd02ef1306a34abef9dbe",
+		"059882159439b9b32968c79a93c5521e769dbea9d840f56c2a17b9ad87e530b8",
+		"17fa435d05012574f8f1da26994cc87b6cb9660b5e82072dc6a0881cec150a0d",
+		"92a28cc5ec4ba6a2688471dfe2032b5fe97c805ca286c503e447d6749796c6af",
+		"1677a03516d6e9509ac37e273d2482da9af6e077abe8392cdca6a30e916a7ae9",
+		"50bbe09f1b8ac18c97aeb745d5d2c3b5d669b6ac7803e646f65ac7b763a392d1",
+		"e46a0022ebdc303a7fb1a0ebfa82b523946c312e745e5b8a116b17ae6b4ce981",
+		"8f2f61e7f5b4d76d854e6d266acfff4d40347548216838ccc4ef3b9e43d3c9ea",
+		"0a450588ae99f75d676a08d0326e1ea874a3497f696722c78a80c7b6ee961ea6",
+		"3c4c0fc2cf040b806c51b46de9ec0dcc678a7cc5cf3eff11c6c03de3bc7818cc",
+		"f6c7c785ab5daddb8f98e5f854f2cb41879fcaf47289eb2b4196fefc1b28316f",
+		"005312351ccb0d0794779f5023e4335b5cad221accf0dfa3da7b881266fa9f5a",
+		"7b26d189c6bba7add54143179aadbba7ccaeff6887bd8d5bec9597d5716126e6",
+		"a4718f4c801e7ddf913a9474eb71774993525684ffea1915f767ab16e05e6889",
+		"6b6226a8c18919d0e55684638d33a6892a00d22492cc2f5906ca7a4ac21c74a7",
+		"383114dccd1cb824b869158aa2984d157fcb02f46234ceca65943e919329e697",
+		"d4d478df3016852b27cb1ae9e1e98d98617f8d0943bf9dc1217f47f817236222"
+};
+#endif
+
+bool opt_bitmain_checkall = false;
+bool opt_bitmain_nobeeper = false;
+bool opt_bitmain_notempoverctrl = false;
+bool opt_bitmain_homemode = false;
+bool opt_bitmain_auto;
+
+// --------------------------------------------------------------
+//      CRC16 check table
+// --------------------------------------------------------------
+static
+const uint8_t chCRCHTalbe[] =                                 // CRC high byte table
+{
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
+ 0x00, 0xC1, 0x81, 0x40
+};
+
+static
+const uint8_t chCRCLTalbe[] =                                 // CRC low byte table
+{
+ 0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
+ 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
+ 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
+ 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
+ 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
+ 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
+ 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
+ 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
+ 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
+ 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
+ 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
+ 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
+ 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
+ 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
+ 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
+ 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
+ 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
+ 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
+ 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
+ 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
+ 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
+ 0x41, 0x81, 0x80, 0x40
+};
+
+static uint16_t CRC16(const uint8_t* p_data, uint16_t w_len)
+{
+	uint8_t chCRCHi = 0xFF; // CRC high byte initialize
+	uint8_t chCRCLo = 0xFF; // CRC low byte initialize
+	uint16_t wIndex = 0;    // CRC cycling index
+
+	while (w_len--) {
+		wIndex = chCRCLo ^ *p_data++;
+		chCRCLo = chCRCHi ^ chCRCHTalbe[wIndex];
+		chCRCHi = chCRCLTalbe[wIndex];
+	}
+	return ((chCRCHi << 8) | chCRCLo);
+}
+
+static uint32_t num2bit(int num) {
+	return 1L << (31 - num);
+}
+
+static int bitmain_set_txconfig(struct bitmain_txconfig_token *bm,
+			    uint8_t reset, uint8_t fan_eft, uint8_t timeout_eft, uint8_t frequency_eft,
+			    uint8_t voltage_eft, uint8_t chain_check_time_eft, uint8_t chip_config_eft, uint8_t hw_error_eft,
+			    uint8_t beeper_ctrl, uint8_t temp_over_ctrl,uint8_t fan_home_mode,
+			    uint8_t chain_num, uint8_t asic_num, uint8_t fan_pwm_data, uint8_t timeout_data,
+			    uint16_t frequency, uint8_t * voltage, uint8_t chain_check_time,
+			    uint8_t chip_address, uint8_t reg_address, uint8_t * reg_data)
+{
+	uint16_t crc = 0;
+	int datalen = 0;
+	uint8_t version = 0;
+	uint8_t * sendbuf = (uint8_t *)bm;
+	if (unlikely(!bm)) {
+		applog(LOG_WARNING, "bitmain_set_txconfig bitmain_txconfig_token is null");
+		return -1;
+	}
+
+	if (unlikely(timeout_data <= 0 || asic_num <= 0 || chain_num <= 0)) {
+		applog(LOG_WARNING, "bitmain_set_txconfig parameter invalid timeout_data(%d) asic_num(%d) chain_num(%d)",
+				timeout_data, asic_num, chain_num);
+		return -1;
+	}
+
+	datalen = sizeof(struct bitmain_txconfig_token);
+	memset(bm, 0, datalen);
+
+	bm->token_type = BITMAIN_TOKEN_TYPE_TXCONFIG;
+	bm->version = version;
+	bm->length = datalen-4;
+	bm->length = htole16(bm->length);
+
+	bm->reset = reset;
+	bm->fan_eft = fan_eft;
+	bm->timeout_eft = timeout_eft;
+	bm->frequency_eft = frequency_eft;
+	bm->voltage_eft = voltage_eft;
+	bm->chain_check_time_eft = chain_check_time_eft;
+	bm->chip_config_eft = chip_config_eft;
+	bm->hw_error_eft = hw_error_eft;
+	bm->beeper_ctrl = beeper_ctrl;
+	bm->temp_over_ctrl = temp_over_ctrl;
+	bm->fan_home_mode = fan_home_mode;
+
+	sendbuf[4] = htole8(sendbuf[4]);
+	sendbuf[5] = htole8(sendbuf[5]);
+
+	bm->chain_num = chain_num;
+	bm->asic_num = asic_num;
+	bm->fan_pwm_data = fan_pwm_data;
+	bm->timeout_data = timeout_data;
+
+	bm->frequency = htole16(frequency);
+	memcpy(bm->voltage, voltage, 2);
+	bm->chain_check_time = chain_check_time;
+
+	memcpy(bm->reg_data, reg_data, 4);
+	bm->chip_address = chip_address;
+	bm->reg_address = reg_address;
+
+	crc = CRC16((uint8_t *)bm, datalen-2);
+	bm->crc = htole16(crc);
+
+	applog(LOG_ERR, "BTM TxConfigToken:v(%d) reset(%d) fan_e(%d) tout_e(%d) fq_e(%d) vt_e(%d) chainc_e(%d) chipc_e(%d) hw_e(%d) b_c(%d) t_c(%d) f_m(%d) mnum(%d) anum(%d) fanpwmdata(%d) toutdata(%d) freq(%d) volt(%02x%02x) chainctime(%d) regdata(%02x%02x%02x%02x) chipaddr(%02x) regaddr(%02x) crc(%04x)",
+					version, reset, fan_eft, timeout_eft, frequency_eft, voltage_eft,
+					chain_check_time_eft, chip_config_eft, hw_error_eft, beeper_ctrl, temp_over_ctrl,fan_home_mode,chain_num, asic_num,
+					fan_pwm_data, timeout_data, frequency, voltage[0], voltage[1],
+					chain_check_time, reg_data[0], reg_data[1], reg_data[2], reg_data[3], chip_address, reg_address, crc);
+
+	return datalen;
+}
+
+static int bitmain_set_rxstatus(struct bitmain_rxstatus_token *bm,
+		uint8_t chip_status_eft, uint8_t detect_get, uint8_t chip_address, uint8_t reg_address)
+{
+	uint16_t crc = 0;
+	uint8_t version = 0;
+	int datalen = 0;
+	uint8_t * sendbuf = (uint8_t *)bm;
+
+	if (unlikely(!bm)) {
+		applog(LOG_WARNING, "bitmain_set_rxstatus bitmain_rxstatus_token is null");
+		return -1;
+	}
+
+	datalen = sizeof(struct bitmain_rxstatus_token);
+	memset(bm, 0, datalen);
+
+	bm->token_type = BITMAIN_TOKEN_TYPE_RXSTATUS;
+	bm->version = version;
+	bm->length = datalen-4;
+	bm->length = htole16(bm->length);
+
+	bm->chip_status_eft = chip_status_eft;
+	bm->detect_get = detect_get;
+
+	sendbuf[4] = htole8(sendbuf[4]);
+
+	bm->chip_address = chip_address;
+	bm->reg_address = reg_address;
+
+	crc = CRC16((uint8_t *)bm, datalen-2);
+	bm->crc = htole16(crc);
+
+	applog(LOG_ERR, "BitMain RxStatus Token: v(%d) chip_status_eft(%d) detect_get(%d) chip_address(%02x) reg_address(%02x) crc(%04x)",
+				version, chip_status_eft, detect_get, chip_address, reg_address, crc);
+
+	return datalen;
+}
+
+static int bitmain_parse_rxstatus(const uint8_t * data, int datalen, struct bitmain_rxstatus_data *bm)
+{
+	uint16_t crc = 0;
+	uint8_t version = 0;
+	int i = 0, j = 0;
+	int asic_num = 0;
+	int dataindex = 0;
+	uint8_t tmp = 0x01;
+	if (unlikely(!bm)) {
+		applog(LOG_WARNING, "bitmain_parse_rxstatus bitmain_rxstatus_data is null");
+		return -1;
+	}
+	if (unlikely(!data || datalen <= 0)) {
+		applog(LOG_WARNING, "bitmain_parse_rxstatus parameter invalid data is null or datalen(%d) error", datalen);
+		return -1;
+	}
+	memset(bm, 0, sizeof(struct bitmain_rxstatus_data));
+	memcpy(bm, data, 28);
+	if (bm->data_type != BITMAIN_DATA_TYPE_RXSTATUS) {
+		applog(LOG_ERR, "bitmain_parse_rxstatus datatype(%02x) error", bm->data_type);
+		return -1;
+	}
+	if (bm->version != version) {
+		applog(LOG_ERR, "bitmain_parse_rxstatus version(%02x) error", bm->version);
+		return -1;
+	}
+	bm->length = htole16(bm->length);
+	if (bm->length+4 != datalen) {
+		applog(LOG_ERR, "bitmain_parse_rxstatus length(%d) datalen(%d) error", bm->length, datalen);
+		return -1;
+	}
+	crc = CRC16(data, datalen-2);
+	memcpy(&(bm->crc), data+datalen-2, 2);
+	bm->crc = htole16(bm->crc);
+	if(crc != bm->crc) {
+		applog(LOG_ERR, "bitmain_parse_rxstatus check crc(%d) != bm crc(%d) datalen(%d)", crc, bm->crc, datalen);
+		return -1;
+	}
+	bm->fifo_space = htole16(bm->fifo_space);
+	bm->fan_exist = htole16(bm->fan_exist);
+	bm->temp_exist = htole32(bm->temp_exist);
+	bm->nonce_error = htole32(bm->nonce_error);
+	if(bm->chain_num > BITMAIN_MAX_CHAIN_NUM) {
+		applog(LOG_ERR, "bitmain_parse_rxstatus chain_num=%d error", bm->chain_num);
+		return -1;
+	}
+	dataindex = 28;
+	if(bm->chain_num > 0) {
+		memcpy(bm->chain_asic_num, data+datalen-2-bm->chain_num-bm->temp_num-bm->fan_num, bm->chain_num);
+	}
+	for(i = 0; i < bm->chain_num; i++) {
+		asic_num = bm->chain_asic_num[i];
+		if(asic_num <= 0) {
+			asic_num = 1;
+		} else {
+			if(asic_num % 32 == 0) {
+				asic_num = asic_num / 32;
+			} else {
+				asic_num = asic_num / 32 + 1;
+			}
+		}
+		memcpy((uint8_t *)bm->chain_asic_exist+i*32, data+dataindex, asic_num*4);
+		dataindex += asic_num*4;
+	}
+	for(i = 0; i < bm->chain_num; i++) {
+		asic_num = bm->chain_asic_num[i];
+		if(asic_num <= 0) {
+			asic_num = 1;
+		} else {
+			if(asic_num % 32 == 0) {
+				asic_num = asic_num / 32;
+			} else {
+				asic_num = asic_num / 32 + 1;
+			}
+		}
+		memcpy((uint8_t *)bm->chain_asic_status+i*32, data+dataindex, asic_num*4);
+		dataindex += asic_num*4;
+	}
+	dataindex += bm->chain_num;
+	if(dataindex + bm->temp_num + bm->fan_num + 2 != datalen) {
+		applog(LOG_ERR, "bitmain_parse_rxstatus dataindex(%d) chain_num(%d) temp_num(%d) fan_num(%d) not match datalen(%d)",
+				dataindex, bm->chain_num, bm->temp_num, bm->fan_num, datalen);
+		return -1;
+	}
+	for(i = 0; i < bm->chain_num; i++) {
+		//bm->chain_asic_status[i] = swab32(bm->chain_asic_status[i]);
+		for(j = 0; j < 8; j++) {
+			bm->chain_asic_exist[i*8+j] = htole32(bm->chain_asic_exist[i*8+j]);
+			bm->chain_asic_status[i*8+j] = htole32(bm->chain_asic_status[i*8+j]);
+		}
+	}
+	if(bm->temp_num > 0) {
+		memcpy(bm->temp, data+dataindex, bm->temp_num);
+		dataindex += bm->temp_num;
+	}
+	if(bm->fan_num > 0) {
+		memcpy(bm->fan, data+dataindex, bm->fan_num);
+		dataindex += bm->fan_num;
+	}
+	if(!opt_bitmain_checkall){
+		if(tmp != htole8(tmp)){
+			applog(LOG_ERR, "BitMain RxStatus   byte4 0x%02x chip_value_eft %d reserved %d get_blk_num %d ",*((uint8_t* )bm +4),bm->chip_value_eft,bm->reserved1,bm->get_blk_num);
+			memcpy(&tmp,data+4,1);
+			bm->chip_value_eft = tmp >>7;
+			bm->get_blk_num = tmp >> 4;
+			bm->reserved1 = ((tmp << 4) & 0xff) >> 5;
+		}	
+		found_blocks = bm->get_blk_num;	
+		applog(LOG_ERR, "BitMain RxStatus tmp :0x%02x  byte4 0x%02x chip_value_eft %d reserved %d get_blk_num %d ",tmp,*((uint8_t* )bm +4),bm->chip_value_eft,bm->reserved1,bm->get_blk_num);
+	}
+	applog(LOG_DEBUG, "BitMain RxStatusData: chipv_e(%d) chainnum(%d) fifos(%d) v1(%d) v2(%d) v3(%d) v4(%d) fann(%d) tempn(%d) fanet(%04x) tempet(%08x) ne(%d) regvalue(%d) crc(%04x)",
+			bm->chip_value_eft, bm->chain_num, bm->fifo_space, bm->hw_version[0], bm->hw_version[1], bm->hw_version[2], bm->hw_version[3], bm->fan_num, bm->temp_num, bm->fan_exist, bm->temp_exist, bm->nonce_error, bm->reg_value, bm->crc);
+	applog(LOG_DEBUG, "BitMain RxStatus Data chain info:");
+	for(i = 0; i < bm->chain_num; i++) {
+		applog(LOG_DEBUG, "BitMain RxStatus Data chain(%d) asic num=%d asic_exist=%08x asic_status=%08x", i+1, bm->chain_asic_num[i], bm->chain_asic_exist[i*8], bm->chain_asic_status[i*8]);
+	}
+	applog(LOG_DEBUG, "BitMain RxStatus Data temp info:");
+	for(i = 0; i < bm->temp_num; i++) {
+		applog(LOG_DEBUG, "BitMain RxStatus Data temp(%d) temp=%d", i+1, bm->temp[i]);
+	}
+	applog(LOG_DEBUG, "BitMain RxStatus Data fan info:");
+	for(i = 0; i < bm->fan_num; i++) {
+		applog(LOG_DEBUG, "BitMain RxStatus Data fan(%d) fan=%d", i+1, bm->fan[i]);
+	}
+	return 0;
+}
+
+static int bitmain_parse_rxnonce(const uint8_t * data, int datalen, struct bitmain_rxnonce_data *bm, int * nonce_num)
+{
+	int i = 0;
+	uint16_t crc = 0;
+	uint8_t version = 0;
+	int curnoncenum = 0;
+	if (unlikely(!bm)) {
+		applog(LOG_ERR, "bitmain_parse_rxnonce bitmain_rxstatus_data null");
+		return -1;
+	}
+	if (unlikely(!data || datalen <= 0)) {
+		applog(LOG_ERR, "bitmain_parse_rxnonce data null or datalen(%d) error", datalen);
+		return -1;
+	}
+	memcpy(bm, data, sizeof(struct bitmain_rxnonce_data));
+	if (bm->data_type != BITMAIN_DATA_TYPE_RXNONCE) {
+		applog(LOG_ERR, "bitmain_parse_rxnonce datatype(%02x) error", bm->data_type);
+		return -1;
+	}
+	if (bm->version != version) {
+		applog(LOG_ERR, "bitmain_parse_rxnonce version(%02x) error", bm->version);
+		return -1;
+	}
+	bm->length = htole16(bm->length);
+	if (bm->length+4 != datalen) {
+		applog(LOG_ERR, "bitmain_parse_rxnonce length(%d) error", bm->length);
+		return -1;
+	}
+	crc = CRC16(data, datalen-2);
+	memcpy(&(bm->crc), data+datalen-2, 2);
+	bm->crc = htole16(bm->crc);
+	if(crc != bm->crc) {
+		applog(LOG_ERR, "bitmain_parse_rxnonce check crc(%d) != bm crc(%d) datalen(%d)", crc, bm->crc, datalen);
+		return -1;
+	}
+	bm->fifo_space = htole16(bm->fifo_space);
+	bm->diff = htole16(bm->diff);
+	bm->total_nonce_num = htole64(bm->total_nonce_num);
+	curnoncenum = (datalen-14)/8;
+	applog(LOG_DEBUG, "BitMain RxNonce Data: nonce_num(%d) fifo_space(%d) diff(%d) tnn(%"PRIu64")", curnoncenum, bm->fifo_space, bm->diff, bm->total_nonce_num);
+	for(i = 0; i < curnoncenum; i++) {
+		bm->nonces[i].work_id = htole32(bm->nonces[i].work_id);
+		bm->nonces[i].nonce = htole32(bm->nonces[i].nonce);
+
+		applog(LOG_DEBUG, "BitMain RxNonce Data %d: work_id(%d) nonce(%08x)(%d)",
+				i, bm->nonces[i].work_id, bm->nonces[i].nonce, bm->nonces[i].nonce);
+	}
+	*nonce_num = curnoncenum;
+	return 0;
+}
+
+static int bitmain_read(struct cgpu_info *bitmain, unsigned char *buf,
+		       size_t bufsize, int timeout)
+{
+	int err = 0;
+	size_t total = 0;
+
+	if(bitmain == NULL || buf == NULL || bufsize <= 0) {
+		applog(LOG_WARNING, "bitmain_read parameter error bufsize(%llu)", (unsigned long long)bufsize);
+		return -1;
+	}
+	{
+		err = btm_read(bitmain, buf, bufsize);
+		total = err;
+	}
+	return total;
+}
+
+static int bitmain_write(struct cgpu_info *bitmain, char *buf, ssize_t len)
+{
+	int err;
+	{
+		int havelen = 0;
+		while(havelen < len) {
+			err = btm_write(bitmain, buf+havelen, len-havelen);
+			if(err < 0) {
+				applog(LOG_DEBUG, "%s%i: btm_write got err %d", bitmain->drv->name,
+						bitmain->device_id, err);
+				applog(LOG_WARNING, "usb_write error on bitmain_write");
+				return BTM_SEND_ERROR;
+			} else {
+				havelen += err;
+			}
+		}
+	}
+	return BTM_SEND_OK;
+}
+
+static int bitmain_send_data(const uint8_t * data, int datalen, struct cgpu_info *bitmain)
+{
+	int ret;
+
+	if(datalen <= 0) {
+		return 0;
+	}
+
+	//struct bitmain_info *info = bitmain->device_data;
+	//int delay;
+	//delay = datalen * 10 * 1000000;
+	//delay = delay / info->baud;
+	//delay += 4000;
+
+	if(opt_debug) {
+		char hex[(datalen * 2) + 1];
+		bin2hex(hex, data, datalen);
+		applog(LOG_DEBUG, "BitMain: Sent(%d): %s", datalen, hex);
+	}
+
+	//cgtimer_t ts_start;
+	//cgsleep_prepare_r(&ts_start);
+	//applog(LOG_DEBUG, "----bitmain_send_data  start");
+	ret = bitmain_write(bitmain, (char *)data, datalen);
+	applog(LOG_DEBUG, "----bitmain_send_data  stop ret=%d datalen=%d", ret, datalen);
+	//cgsleep_us_r(&ts_start, delay);
+
+	//applog(LOG_DEBUG, "BitMain: Sent: Buffer delay: %dus", delay);
+
+	return ret;
+}
+
+static void bitmain_inc_nvw(struct bitmain_info *info, struct thr_info *thr)
+{
+	applog(LOG_INFO, "%s%d: No matching work - HW error",
+	       thr->cgpu->drv->name, thr->cgpu->device_id);
+
+	inc_hw_errors_only(thr);
+	info->no_matching_work++;
+}
+
+static inline void record_temp_fan(struct bitmain_info *info, struct bitmain_rxstatus_data *bm, float *temp)
+{
+	int i = 0;
+	int maxfan = 0, maxtemp = 0;
+	int temp_avg = 0;
+
+	info->fan_num = bm->fan_num;
+	for(i = 0; i < bm->fan_num; i++) {
+		info->fan[i] = bm->fan[i] * BITMAIN_FAN_FACTOR;
+
+		if(info->fan[i] > maxfan)
+			maxfan = info->fan[i];
+	}
+	info->temp_num = bm->temp_num;
+	for(i = 0; i < bm->temp_num; i++) {
+		info->temp[i] = bm->temp[i];
+		/*
+		if(bm->temp[i] & 0x80) {
+			bm->temp[i] &= 0x7f;
+			info->temp[i] = 0 - ((~bm->temp[i] & 0x7f) + 1);
+		}*/
+		temp_avg += info->temp[i];
+
+		if(info->temp[i] > info->temp_max) {
+			info->temp_max = info->temp[i];
+		}
+		if(info->temp[i] > maxtemp)
+			maxtemp = info->temp[i];
+	}
+
+	if(bm->temp_num > 0) {
+		temp_avg /= bm->temp_num;
+		info->temp_avg = temp_avg;
+	}
+
+	*temp = maxtemp;
+}
+
+static void bitmain_update_temps(struct cgpu_info *bitmain, struct bitmain_info *info,
+				struct bitmain_rxstatus_data *bm)
+{
+	char tmp[64] = {0};
+	char msg[10240] = {0};
+	int i = 0;
+	record_temp_fan(info, bm, &(bitmain->temp));
+
+	strcpy(msg, "BitMain: ");
+	for(i = 0; i < bm->fan_num; i++) {
+		if(i != 0) {
+			strcat(msg, ", ");
+		}
+		sprintf(tmp, "Fan%d: %d/m", i+1, info->fan[i]);
+		strcat(msg, tmp);
+	}
+	strcat(msg, "\t");
+	for(i = 0; i < bm->temp_num; i++) {
+		if(i != 0) {
+			strcat(msg, ", ");
+		}
+		sprintf(tmp, "Temp%d: %dC", i+1, info->temp[i]);
+		strcat(msg, tmp);
+	}
+	sprintf(tmp, ", TempMAX: %dC", info->temp_max);
+	strcat(msg, tmp);
+	applog(LOG_INFO, "%s", msg);
+	info->temp_history_index++;
+	info->temp_sum += bitmain->temp;
+	applog(LOG_DEBUG, "BitMain: temp_index: %d, temp_count: %d, temp_old: %d",
+		info->temp_history_index, info->temp_history_count, info->temp_old);
+	if (info->temp_history_index == info->temp_history_count) {
+		info->temp_history_index = 0;
+		info->temp_sum = 0;
+	}
+}
+
+static void bitmain_set_fifo_space(struct cgpu_info * const dev, const int fifo_space)
+{
+	struct thr_info * const master_thr = dev->thr[0];
+	struct bitmain_info * const info = dev->device_data;
+	
+	if (unlikely(fifo_space > info->max_fifo_space))
+		info->max_fifo_space = fifo_space;
+	
+	info->fifo_space = fifo_space;
+	master_thr->queue_full = !fifo_space;
+}
+
+static void bitmain_parse_results(struct cgpu_info *bitmain, struct bitmain_info *info,
+				 struct thr_info *thr, uint8_t *buf, int *offset)
+{
+	int i, j, n, m, r, errordiff, spare = BITMAIN_READ_SIZE;
+	uint32_t checkbit = 0x00000000;
+	bool found = false;
+	struct work *work = NULL;
+	struct bitmain_packet_head packethead;
+	int asicnum = 0;
+	int mod = 0,tmp = 0;
+
+	for (i = 0; i <= spare; i++) {
+		if(buf[i] == 0xa1) {
+			struct bitmain_rxstatus_data rxstatusdata;
+			applog(LOG_DEBUG, "bitmain_parse_results RxStatus Data");
+			if(*offset < 4) {
+				return;
+			}
+			memcpy(&packethead, buf+i, sizeof(struct bitmain_packet_head));
+			packethead.length = htole16(packethead.length);
+			if(packethead.length > 1130) {
+				applog(LOG_ERR, "bitmain_parse_results bitmain_parse_rxstatus datalen=%d error", packethead.length+4);
+				continue;
+			}
+			if(*offset < packethead.length + 4) {
+				return;
+			}
+			if(bitmain_parse_rxstatus(buf+i, packethead.length+4, &rxstatusdata) != 0) {
+				applog(LOG_ERR, "bitmain_parse_results bitmain_parse_rxstatus error len=%d", packethead.length+4);
+			} else {
+				mutex_lock(&info->qlock);
+				info->chain_num = rxstatusdata.chain_num;
+				bitmain_set_fifo_space(bitmain, rxstatusdata.fifo_space);
+				info->hw_version[0] = rxstatusdata.hw_version[0];
+				info->hw_version[1] = rxstatusdata.hw_version[1];
+				info->hw_version[2] = rxstatusdata.hw_version[2];
+				info->hw_version[3] = rxstatusdata.hw_version[3];
+				info->nonce_error = rxstatusdata.nonce_error;
+				errordiff = info->nonce_error-info->last_nonce_error;
+				//sprintf(g_miner_version, "%d.%d.%d.%d", info->hw_version[0], info->hw_version[1], info->hw_version[2], info->hw_version[3]);
+				applog(LOG_ERR, "bitmain_parse_results v=%d chain=%d fifo=%d hwv1=%d hwv2=%d hwv3=%d hwv4=%d nerr=%d-%d freq=%d chain info:",
+						rxstatusdata.version, info->chain_num, info->fifo_space, info->hw_version[0], info->hw_version[1], info->hw_version[2], info->hw_version[3],
+						info->last_nonce_error, info->nonce_error, info->frequency);
+				memcpy(info->chain_asic_exist, rxstatusdata.chain_asic_exist, BITMAIN_MAX_CHAIN_NUM*32);
+				memcpy(info->chain_asic_status, rxstatusdata.chain_asic_status, BITMAIN_MAX_CHAIN_NUM*32);
+				for(n = 0; n < rxstatusdata.chain_num; n++) {
+					info->chain_asic_num[n] = rxstatusdata.chain_asic_num[n];
+					memset(info->chain_asic_status_t[n], 0, 320);
+					j = 0;
+
+					mod = 0;
+					if(info->chain_asic_num[n] <= 0) {
+						asicnum = 0;
+					} else {
+						mod = info->chain_asic_num[n] % 32;
+						if(mod == 0) {
+							asicnum = info->chain_asic_num[n] / 32;
+						} else {
+							asicnum = info->chain_asic_num[n] / 32 + 1;
+						}
+					}
+					if(asicnum > 0) {
+							for(m = asicnum-1; m >= 0; m--) {
+							tmp = mod ? (32-mod): 0;
+							for(r = tmp;r < 32;r++){
+								if((r-tmp)%8 == 0 && (r-tmp) !=0){
+											info->chain_asic_status_t[n][j] = ' ';
+											j++;
+										}
+										checkbit = num2bit(r);
+										if(rxstatusdata.chain_asic_exist[n*8+m] & checkbit) {
+											if(rxstatusdata.chain_asic_status[n*8+m] & checkbit) {
+												info->chain_asic_status_t[n][j] = 'o';
+											} else {
+												info->chain_asic_status_t[n][j] = 'x';
+											}
+										} else {
+											info->chain_asic_status_t[n][j] = '-';
+										}
+										j++;
+									}
+									info->chain_asic_status_t[n][j] = ' ';
+									j++;
+								mod = 0;
+						}
+					}
+					applog(LOG_DEBUG, "bitmain_parse_results chain(%d) asic_num=%d asic_exist=%08x%08x%08x%08x%08x%08x%08x%08x asic_status=%08x%08x%08x%08x%08x%08x%08x%08x",
+						n, info->chain_asic_num[n],
+						info->chain_asic_exist[n*8+0], info->chain_asic_exist[n*8+1], info->chain_asic_exist[n*8+2], info->chain_asic_exist[n*8+3], info->chain_asic_exist[n*8+4], info->chain_asic_exist[n*8+5], info->chain_asic_exist[n*8+6], info->chain_asic_exist[n*8+7],
+						info->chain_asic_status[n*8+0], info->chain_asic_status[n*8+1], info->chain_asic_status[n*8+2], info->chain_asic_status[n*8+3], info->chain_asic_status[n*8+4], info->chain_asic_status[n*8+5], info->chain_asic_status[n*8+6], info->chain_asic_status[n*8+7]);
+					applog(LOG_ERR, "bitmain_parse_results chain(%d) asic_num=%d asic_status=%s", n, info->chain_asic_num[n], info->chain_asic_status_t[n]);
+				}
+				mutex_unlock(&info->qlock);
+
+				if(errordiff > 0) {
+					for(j = 0; j < errordiff; j++) {
+						bitmain_inc_nvw(info, thr);
+					}
+					mutex_lock(&info->qlock);
+					info->last_nonce_error += errordiff;
+					mutex_unlock(&info->qlock);
+				}
+				bitmain_update_temps(bitmain, info, &rxstatusdata);
+			}
+
+			found = true;
+			spare = packethead.length + 4 + i;
+			if(spare > *offset) {
+				applog(LOG_ERR, "bitmain_parse_rxresults space(%d) > offset(%d)", spare, *offset);
+				spare = *offset;
+			}
+			break;
+		} else if(buf[i] == 0xa2) {
+			struct bitmain_rxnonce_data rxnoncedata;
+			int nonce_num = 0;
+			applog(LOG_DEBUG, "bitmain_parse_results RxNonce Data");
+			if(*offset < 4) {
+				return;
+			}
+			memcpy(&packethead, buf+i, sizeof(struct bitmain_packet_head));
+			packethead.length = htole16(packethead.length);
+			if(packethead.length > 1038) {
+				applog(LOG_ERR, "bitmain_parse_results bitmain_parse_rxnonce datalen=%d error", packethead.length+4);
+				continue;
+			}
+			if(*offset < packethead.length + 4) {
+				return;
+			}
+			if(bitmain_parse_rxnonce(buf+i, packethead.length+4, &rxnoncedata, &nonce_num) != 0) {
+				applog(LOG_ERR, "bitmain_parse_results bitmain_parse_rxnonce error len=%d", packethead.length+4);
+			} else {
+				const float nonce_diff = 1 << rxnoncedata.diff;
+				for(j = 0; j < nonce_num; j++) {
+					const work_device_id_t work_id = rxnoncedata.nonces[j].work_id;
+					HASH_FIND(hh, thr->work_list, &work_id, sizeof(work_id), work);
+					if(work) {
+						if(BITMAIN_TEST_PRINT_WORK) {
+							applog(LOG_ERR, "bitmain_parse_results nonce find work(%d-%d)(%08x)", work->id, rxnoncedata.nonces[j].work_id, rxnoncedata.nonces[j].nonce);
+
+							char ob_hex[(32 * 2) + 1];
+							
+							bin2hex(ob_hex, work->midstate, 32);
+							applog(LOG_ERR, "work %d midstate: %s", work->id, ob_hex);
+
+							bin2hex(ob_hex, &work->data[64], 12);
+							applog(LOG_ERR, "work %d data2: %s", work->id, ob_hex);
+						}
+
+						{
+							const uint32_t nonce = rxnoncedata.nonces[j].nonce;
+							applog(LOG_DEBUG, "BitMain: submit nonce = %08lx", (unsigned long)nonce);
+							work->nonce_diff = nonce_diff;
+							if (submit_nonce(thr, work, nonce)) {
+								mutex_lock(&info->qlock);
+								hashes_done2(thr, 0x100000000 * work->nonce_diff, NULL);
+								mutex_unlock(&info->qlock);
+						 	} else {
+						 		applog(LOG_ERR, "BitMain: bitmain_decode_nonce error work(%d)", rxnoncedata.nonces[j].work_id);
+						 	}
+						}
+					} else {
+						bitmain_inc_nvw(info, thr);
+						applog(LOG_ERR, "BitMain: Nonce not find work(%d)", rxnoncedata.nonces[j].work_id);
+					}
+				}
+				mutex_lock(&info->qlock);
+				bitmain_set_fifo_space(bitmain, rxnoncedata.fifo_space);
+				mutex_unlock(&info->qlock);
+				applog(LOG_DEBUG, "bitmain_parse_rxnonce fifo space=%d", info->fifo_space);
+
+#ifndef WIN32
+				if(nonce_num < info->packet_max_nonce)
+					cgsleep_ms(5);
+#endif
+			}
+
+ 			found = true;
+ 			spare = packethead.length + 4 + i;
+ 			if(spare > *offset) {
+ 				applog(LOG_ERR, "bitmain_parse_rxnonce space(%d) > offset(%d)", spare, *offset);
+ 				spare = *offset;
+ 			}
+ 			break;
+		} else {
+			applog(LOG_ERR, "bitmain_parse_results data type error=%02x", buf[i]);
+		}
+	}
+	if (!found) {
+		spare = *offset - BITMAIN_READ_SIZE;
+		/* We are buffering and haven't accumulated one more corrupt
+		 * work result. */
+		if (spare < (int)BITMAIN_READ_SIZE)
+			return;
+		bitmain_inc_nvw(info, thr);
+	}
+
+	*offset -= spare;
+	memmove(buf, buf + spare, *offset);
+}
+
+static void bitmain_running_reset(struct cgpu_info *bitmain, struct bitmain_info *info)
+{
+	info->reset = false;
+}
+
+static void bitmain_prune_old_work(struct cgpu_info * const dev)
+{
+	struct thr_info * const master_thr = dev->thr[0];
+	struct bitmain_info * const info = dev->device_data;
+	
+	const size_t retain_work_items = info->max_fifo_space * 2;
+	const size_t queued_work_items = HASH_COUNT(master_thr->work_list);
+	if (queued_work_items > retain_work_items) {
+		size_t remove_work_items = queued_work_items - retain_work_items;
+		while (remove_work_items--) {
+			// Deletes the first item insertion-order
+			struct work * const work = master_thr->work_list;
+			HASH_DEL(master_thr->work_list, work);
+			free_work(work);
+		}
+	}
+}
+
+static void bitmain_poll(struct thr_info * const thr)
+{
+	struct cgpu_info *bitmain = thr->cgpu;
+	struct bitmain_info *info = bitmain->device_data;
+	int offset = info->readbuf_offset, ret = 0;
+	const int rsize = BITMAIN_FTDI_READSIZE;
+	uint8_t * const readbuf = info->readbuf;
+
+	{
+		unsigned char buf[rsize];
+
+		if (unlikely(info->reset)) {
+			bitmain_running_reset(bitmain, info);
+			/* Discard anything in the buffer */
+			offset = 0;
+		}
+
+		//cgsleep_prepare_r(&ts_start);
+		//applog(LOG_DEBUG, "======start bitmain_get_results bitmain_read");
+		ret = bitmain_read(bitmain, buf, rsize, BITMAIN_READ_TIMEOUT);
+		//applog(LOG_DEBUG, "======stop bitmain_get_results bitmain_read=%d", ret);
+
+		if ((ret < 1) || (ret == 18)) {
+			++info->errorcount2;
+#ifdef WIN32
+			if(info->errorcount2 > 200) {
+				//applog(LOG_ERR, "bitmain_read errorcount ret=%d", ret);
+				cgsleep_ms(20);
+				info->errorcount2 = 0;
+			}
+#else
+			if(info->errorcount2 > 3) {
+				//applog(LOG_ERR, "bitmain_read errorcount ret=%d", ret);
+				cgsleep_ms(20);
+				info->errorcount2 = 0;
+			}
+#endif
+			if(ret < 1)
+				return;
+		}
+
+		if (opt_debug) {
+			char hex[(ret * 2) + 1];
+			bin2hex(hex, buf, ret);
+			applog(LOG_DEBUG, "BitMain: get: %s", hex);
+		}
+
+		memcpy(readbuf+offset, buf, ret);
+		offset += ret;
+
+		//applog(LOG_DEBUG, "+++++++bitmain_get_results offset=%d", offset);
+
+		if (offset >= (int)BITMAIN_READ_SIZE) {
+			//applog(LOG_DEBUG, "======start bitmain_get_results ");
+			bitmain_parse_results(bitmain, info, thr, readbuf, &offset);
+			//applog(LOG_DEBUG, "======stop bitmain_get_results ");
+		}
+
+		if (unlikely(offset + rsize >= BITMAIN_READBUF_SIZE)) {
+			/* This should never happen */
+			applog(LOG_DEBUG, "BitMain readbuf overflow, resetting buffer");
+			offset = 0;
+		}
+
+		/* As the usb read returns after just 1ms, sleep long enough
+		 * to leave the interface idle for writes to occur, but do not
+		 * sleep if we have been receiving data as more may be coming. */
+		//if (offset == 0) {
+		//	cgsleep_ms_r(&ts_start, BITMAIN_READ_TIMEOUT);
+		//}
+	}
+	
+	info->readbuf_offset = offset;
+	
+	bitmain_prune_old_work(bitmain);
+	
+	timer_set_delay_from_now(&thr->tv_poll, bitmain_poll_interval_us);
+}
+
+static void bitmain_init(struct cgpu_info *bitmain)
+{
+	applog(LOG_INFO, "BitMain: Opened on %s", bitmain->device_path);
+}
+
+static bool bitmain_prepare(struct thr_info *thr)
+{
+	struct cgpu_info *bitmain = thr->cgpu;
+	struct bitmain_info *info = bitmain->device_data;
+
+	mutex_init(&info->qlock);
+
+	// To initialise queue_full
+	bitmain_set_fifo_space(bitmain, info->fifo_space);
+	
+	bitmain_init(bitmain);
+
+	timer_set_now(&thr->tv_poll);
+	
+	return true;
+}
+
+static int bitmain_initialize(struct cgpu_info *bitmain)
+{
+	uint8_t data[BITMAIN_READBUF_SIZE];
+	struct bitmain_info *info = NULL;
+	int ret = 0;
+	uint8_t sendbuf[BITMAIN_SENDBUF_SIZE];
+	int readlen = 0;
+	int sendlen = 0;
+	int trycount = 3;
+	struct timespec p;
+	struct bitmain_rxstatus_data rxstatusdata;
+	int i = 0, j = 0, m = 0, r = 0, statusok = 0;
+	uint32_t checkbit = 0x00000000;
+	int hwerror_eft = 0;
+	int beeper_ctrl = 1;
+	int tempover_ctrl = 1;
+	int home_mode = 0;
+	struct bitmain_packet_head packethead;
+	int asicnum = 0;
+	int mod = 0,tmp = 0;
+
+	/* Send reset, then check for result */
+	if(!bitmain) {
+		applog(LOG_WARNING, "bitmain_initialize cgpu_info is null");
+		return -1;
+	}
+	info = bitmain->device_data;
+
+	/* clear read buf */
+	ret = bitmain_read(bitmain, data, BITMAIN_READBUF_SIZE,
+				  BITMAIN_RESET_TIMEOUT);
+	if(ret > 0) {
+		if (opt_debug) {
+			char hex[(ret * 2) + 1];
+			bin2hex(hex, data, ret);
+			applog(LOG_DEBUG, "BTM%d Clear Read(%d): %s", bitmain->device_id, ret, hex);
+		}
+	}
+
+	sendlen = bitmain_set_rxstatus((struct bitmain_rxstatus_token *)sendbuf, 0, 1, 0, 0);
+	if(sendlen <= 0) {
+		applog(LOG_ERR, "bitmain_initialize bitmain_set_rxstatus error(%d)", sendlen);
+		return -1;
+	}
+
+	ret = bitmain_send_data(sendbuf, sendlen, bitmain);
+	if (unlikely(ret == BTM_SEND_ERROR)) {
+		applog(LOG_ERR, "bitmain_initialize bitmain_send_data error");
+		return -1;
+	}
+	while(trycount >= 0) {
+		ret = bitmain_read(bitmain, data+readlen, BITMAIN_READBUF_SIZE, BITMAIN_RESET_TIMEOUT);
+		if(ret > 0) {
+			readlen += ret;
+			if(readlen > BITMAIN_READ_SIZE) {
+				for(i = 0; i < readlen; i++) {
+					if(data[i] == 0xa1) {
+						if (opt_debug) {
+							char hex[(readlen * 2) + 1];
+							bin2hex(hex, data, readlen);
+							applog(LOG_DEBUG, "%s%d initset: get: %s", bitmain->drv->name, bitmain->device_id, hex);
+						}
+						memcpy(&packethead, data+i, sizeof(struct bitmain_packet_head));
+						packethead.length = htole16(packethead.length);
+
+						if(packethead.length > 1130) {
+							applog(LOG_ERR, "bitmain_initialize rxstatus datalen=%d error", packethead.length+4);
+							continue;
+						}
+						if(readlen-i < packethead.length+4) {
+							applog(LOG_ERR, "bitmain_initialize rxstatus datalen=%d<%d low", readlen-i, packethead.length+4);
+							continue;
+						}
+						if (bitmain_parse_rxstatus(data+i, packethead.length+4, &rxstatusdata) != 0) {
+							applog(LOG_ERR, "bitmain_initialize bitmain_parse_rxstatus error");
+							continue;
+						}
+						info->chain_num = rxstatusdata.chain_num;
+						// NOTE: This is before thr_info is allocated, so we cannot use bitmain_set_fifo_space (bitmain_prepare will re-set it for us)
+						info->fifo_space = rxstatusdata.fifo_space;
+						info->hw_version[0] = rxstatusdata.hw_version[0];
+						info->hw_version[1] = rxstatusdata.hw_version[1];
+						info->hw_version[2] = rxstatusdata.hw_version[2];
+						info->hw_version[3] = rxstatusdata.hw_version[3];
+						info->nonce_error = 0;
+						info->last_nonce_error = 0;
+						sprintf(info->g_miner_version, "%d.%d.%d.%d", info->hw_version[0], info->hw_version[1], info->hw_version[2], info->hw_version[3]);
+						applog(LOG_ERR, "bitmain_initialize rxstatus v(%d) chain(%d) fifo(%d) hwv1(%d) hwv2(%d) hwv3(%d) hwv4(%d) nerr(%d) freq=%d",
+								rxstatusdata.version, info->chain_num, info->fifo_space, info->hw_version[0], info->hw_version[1], info->hw_version[2], info->hw_version[3],
+								rxstatusdata.nonce_error, info->frequency);
+
+						memcpy(info->chain_asic_exist, rxstatusdata.chain_asic_exist, BITMAIN_MAX_CHAIN_NUM*32);
+						memcpy(info->chain_asic_status, rxstatusdata.chain_asic_status, BITMAIN_MAX_CHAIN_NUM*32);
+						for(i = 0; i < rxstatusdata.chain_num; i++) {
+							info->chain_asic_num[i] = rxstatusdata.chain_asic_num[i];
+							memset(info->chain_asic_status_t[i], 0, 320);
+							j = 0;
+							mod = 0;
+
+							if(info->chain_asic_num[i] <= 0) {
+								asicnum = 0;
+							} else {
+								mod = info->chain_asic_num[i] % 32;
+								if(mod == 0) {
+									asicnum = info->chain_asic_num[i] / 32;
+								} else {
+									asicnum = info->chain_asic_num[i] / 32 + 1;
+								}
+							}
+							if(asicnum > 0) {
+									for(m = asicnum-1; m >= 0; m--) {
+									tmp = mod ? (32-mod):0;
+									for(r = tmp;r < 32;r++){
+										if((r-tmp)%8 == 0 && (r-tmp) !=0){
+													info->chain_asic_status_t[i][j] = ' ';
+													j++;
+												}
+												checkbit = num2bit(r);
+												if(rxstatusdata.chain_asic_exist[i*8+m] & checkbit) {
+													if(rxstatusdata.chain_asic_status[i*8+m] & checkbit) {
+														info->chain_asic_status_t[i][j] = 'o';
+													} else {
+														info->chain_asic_status_t[i][j] = 'x';
+													}
+												} else {
+													info->chain_asic_status_t[i][j] = '-';
+												}
+												j++;
+											}
+											info->chain_asic_status_t[i][j] = ' ';
+											j++;
+										mod = 0;
+								}
+							}
+							applog(LOG_DEBUG, "bitmain_initialize chain(%d) asic_num=%d asic_exist=%08x%08x%08x%08x%08x%08x%08x%08x asic_status=%08x%08x%08x%08x%08x%08x%08x%08x",
+									i, info->chain_asic_num[i],
+									info->chain_asic_exist[i*8+0], info->chain_asic_exist[i*8+1], info->chain_asic_exist[i*8+2], info->chain_asic_exist[i*8+3], info->chain_asic_exist[i*8+4], info->chain_asic_exist[i*8+5], info->chain_asic_exist[i*8+6], info->chain_asic_exist[i*8+7],
+									info->chain_asic_status[i*8+0], info->chain_asic_status[i*8+1], info->chain_asic_status[i*8+2], info->chain_asic_status[i*8+3], info->chain_asic_status[i*8+4], info->chain_asic_status[i*8+5], info->chain_asic_status[i*8+6], info->chain_asic_status[i*8+7]);
+							applog(LOG_ERR, "bitmain_initialize chain(%d) asic_num=%d asic_status=%s", i, info->chain_asic_num[i], info->chain_asic_status_t[i]);
+						}
+						bitmain_update_temps(bitmain, info, &rxstatusdata);
+						statusok = 1;
+						break;
+					}
+				}
+				if(statusok) {
+					break;
+				}
+			}
+		}
+		trycount--;
+		p.tv_sec = 0;
+		p.tv_nsec = BITMAIN_RESET_PITCH;
+		nanosleep(&p, NULL);
+	}
+
+	p.tv_sec = 0;
+	p.tv_nsec = BITMAIN_RESET_PITCH;
+	nanosleep(&p, NULL);
+
+	if(statusok) {
+		applog(LOG_ERR, "bitmain_initialize start send txconfig");
+		if(opt_bitmain_hwerror)
+			hwerror_eft = 1;
+		else
+			hwerror_eft = 0;
+		if(opt_bitmain_nobeeper)
+			beeper_ctrl = 0;
+		else
+			beeper_ctrl = 1;
+		if(opt_bitmain_notempoverctrl)
+			tempover_ctrl = 0;
+		else
+			tempover_ctrl = 1;
+		if(opt_bitmain_homemode)
+			home_mode= 1;
+		else
+			home_mode= 0;
+		sendlen = bitmain_set_txconfig((struct bitmain_txconfig_token *)sendbuf, 1, 1, 1, 1, 1, 0, 1, hwerror_eft, beeper_ctrl, tempover_ctrl,home_mode,
+				info->chain_num, info->asic_num, BITMAIN_DEFAULT_FAN_MAX_PWM, info->timeout,
+				info->frequency, info->voltage, 0, 0, 0x04, info->reg_data);
+		if(sendlen <= 0) {
+			applog(LOG_ERR, "bitmain_initialize bitmain_set_txconfig error(%d)", sendlen);
+			return -1;
+		}
+
+		ret = bitmain_send_data(sendbuf, sendlen, bitmain);
+		if (unlikely(ret == BTM_SEND_ERROR)) {
+			applog(LOG_ERR, "bitmain_initialize bitmain_send_data error");
+			return -1;
+		}
+		applog(LOG_WARNING, "BMM%d: InitSet succeeded", bitmain->device_id);
+	} else {
+		applog(LOG_WARNING, "BMS%d: InitSet error", bitmain->device_id);
+		return -1;
+	}
+	return 0;
+}
+
+static bool bitmain_detect_one(const char * devpath)
+{
+	struct bitmain_info *info;
+	struct cgpu_info *bitmain;
+	int ret;
+
+	bitmain = btm_alloc_cgpu(&bitmain_drv, BITMAIN_MINER_THREADS);
+	info = bitmain->device_data;
+
+	drv_set_defaults(&bitmain_drv, bitmain_set_device_funcs_init, info, devpath, NULL, 1);
+	
+	if (!info->packet_max_work)
+		return_via_applog(shin, , LOG_ERR, "%s: Device not configured (did you forget --set bitmain:model=S5 ?)", bitmain_drv.dname);
+	
+	if (!(upk_u32be(info->reg_data, 0))) {
+		switch (info->chip_type) {
+			case BMC_BM1382:
+			case BMC_BM1384:
+				if (bm1382_freq_to_reg_data(info->reg_data, info->frequency))
+					break;
+				// fall thru if it failed
+			default:
+				return_via_applog(shin, , LOG_ERR, "%s: Device not configured (did you forget --set bitmain:reg_data=x???? ?)", bitmain_drv.dname);
+		}
+	}
+
+	if (!btm_init(bitmain, devpath))
+		goto shin;
+	applog(LOG_ERR, "bitmain_detect_one btm init ok");
+
+	info->fan_pwm = BITMAIN_DEFAULT_FAN_MIN_PWM;
+	info->temp_max = 0;
+	/* This is for check the temp/fan every 3~4s */
+	info->temp_history_count = (4 / (float)((float)info->timeout * ((float)1.67/0x32))) + 1;
+	if (info->temp_history_count <= 0)
+		info->temp_history_count = 1;
+
+	info->temp_history_index = 0;
+	info->temp_sum = 0;
+	info->temp_old = 0;
+
+	if (!add_cgpu(bitmain))
+		goto unshin;
+
+	ret = bitmain_initialize(bitmain);
+	applog(LOG_ERR, "bitmain_detect_one stop bitmain_initialize %d", ret);
+	if (ret)
+		goto unshin;
+
+	info->errorcount = 0;
+
+	applog(LOG_ERR, "BitMain Detected: %s "
+	       "(chain_num=%d asic_num=%d timeout=%d freq=%d-%s volt=%02x%02x-%s)",
+	       bitmain->device_path, info->chain_num, info->asic_num, info->timeout,
+	       info->frequency, info->frequency_t, info->voltage[0], info->voltage[1], info->voltage_t);
+
+	return true;
+
+unshin:
+	btm_uninit(bitmain);
+
+shin:
+	free(bitmain->device_data);
+	bitmain->device_data = NULL;
+
+	free(bitmain);
+
+	return false;
+}
+
+static int bitmain_detect_auto(void)
+{
+	const char * const auto_bitmain_dev = "/dev/bitmain-asic";
+	applog(LOG_DEBUG, "BTM detect dev: %s", auto_bitmain_dev);
+	return bitmain_detect_one(auto_bitmain_dev) ? 1 : 0;
+}
+
+static void bitmain_detect()
+{
+	generic_detect(&bitmain_drv, bitmain_detect_one, bitmain_detect_auto, GDF_REQUIRE_DNAME | GDF_DEFAULT_NOAUTO);
+}
+
+static void do_bitmain_close(struct thr_info *thr)
+{
+	struct cgpu_info *bitmain = thr->cgpu;
+	struct bitmain_info *info = bitmain->device_data;
+
+	bitmain_running_reset(bitmain, info);
+
+	info->no_matching_work = 0;
+}
+
+static uint8_t diff_to_bitmain(float diff)
+{
+	uint8_t res = 0;
+	if (diff > UINT64_MAX)
+		diff = UINT64_MAX;
+	for (uint64_t tmp = diff; tmp >>= 1; ) {
+		if (++res == UINT8_MAX)
+			break;
+	}
+	return res;
+}
+
+static bool bitmain_queue_append(struct thr_info * const thr, struct work * const work)
+{
+	struct cgpu_info * const proc = thr->cgpu;
+	struct cgpu_info * const dev = proc->device;
+	struct thr_info * const master_thr = dev->thr[0];
+	struct bitmain_info * const info = dev->device_data;
+	const struct pool * const pool = work->pool;
+	const struct mining_goal_info * const goal = pool->goal;
+	
+	applog(LOG_DEBUG, "%s: %s with fifo_space=%d (max=%d) work_restart=%d", dev->dev_repr, __func__, info->fifo_space, info->max_fifo_space, (int)info->work_restart);
+	
+	if (info->work_restart) {
+		info->work_restart = false;
+		info->ready_to_queue = 0;
+		bitmain_set_fifo_space(dev, info->max_fifo_space);
+		info->queuebuf[4] = 1;  // clear work queues
+	}
+	
+	if (!info->fifo_space) {
+		thr->queue_full = true;
+		return false;
+	}
+	
+	uint8_t * const wbuf = &info->queuebuf[BITMAIN_TASK_HEADER_SIZE + (BITMAIN_WORK_SIZE * info->ready_to_queue)];
+	const int work_nonce_bmdiff = diff_to_bitmain(work->nonce_diff);
+	if (work_nonce_bmdiff < info->diff)
+		info->diff = work_nonce_bmdiff;
+	if (goal->current_diff < info->lowest_goal_diff)
+		info->lowest_goal_diff = goal->current_diff;
+	
+	work->device_id = info->next_work_id++;
+	pk_u32le(wbuf, 0, work->device_id);
+	memcpy(&wbuf[4], work->midstate, 0x20);
+	memcpy(&wbuf[0x24], &work->data[0x40], 0xc);
+	
+	HASH_ADD(hh, master_thr->work_list, device_id, sizeof(work->device_id), work);
+	++info->ready_to_queue;
+	
+	if (!(info->ready_to_queue >= info->packet_max_work || info->fifo_space == info->ready_to_queue || info->fifo_space == info->max_fifo_space)) {
+		applog(LOG_DEBUG, "%s: %s now has ready_to_queue=%d; deferring send", dev->dev_repr, __func__, info->ready_to_queue);
+		return true;
+	}
+	
+	applog(LOG_DEBUG, "%s: %s now has ready_to_queue=%d; sending to device", dev->dev_repr, __func__, info->ready_to_queue);
+	
+	uint8_t * const buf = info->queuebuf;
+	const size_t buflen = BITMAIN_TASK_HEADER_SIZE + (info->ready_to_queue * BITMAIN_WORK_SIZE) + BITMAIN_TASK_FOOTER_SIZE;
+	
+	buf[0] = BITMAIN_TOKEN_TYPE_TXTASK;
+	buf[1] = 0;  // packet version
+	pk_u16le(buf, 2, buflen - 4);  // length of data after this field (including CRC)
+	// buf[4] is set to 1 to clear work queues, when the first work item is added, and reset to 0 after we send
+	buf[5] = info->diff;
+	pk_u16le(buf, 6, diff_to_bitmain(info->lowest_goal_diff));
+	
+	pk_u16le(buf, buflen - 2, CRC16(buf, buflen - 2));
+	
+	int sendret = bitmain_send_data(buf, buflen, proc);
+	if (unlikely(sendret == BTM_SEND_ERROR)) {
+		applog(LOG_ERR, "%s: Comms error(buffer)", dev->dev_repr);
+		//dev_error(bitmain, REASON_DEV_COMMS_ERROR);
+		info->reset = true;
+		info->errorcount++;
+		if (info->errorcount > 1000) {
+			info->errorcount = 0;
+			applog(LOG_ERR, "%s: Device disappeared, shutting down thread", dev->dev_repr);
+			dev->shutdown = true;
+		}
+		// The work is in the queuebuf already, so we're okay-ish for that...
+		return true;
+	} else {
+		applog(LOG_DEBUG, "bitmain_send_data send ret=%d", sendret);
+		info->errorcount = 0;
+	}
+	buf[4] = 0;
+	info->fifo_space -= info->ready_to_queue;
+	info->ready_to_queue = 0;
+	
+	struct timeval tv_now;
+	timer_set_now(&tv_now);
+	if (timer_passed(&master_thr->tv_poll, &tv_now)) {
+		bitmain_poll(master_thr);
+	}
+	
+	return true;
+}
+
+static void bitmain_queue_flush(struct thr_info * const thr)
+{
+	struct cgpu_info * const proc = thr->cgpu;
+	struct cgpu_info * const dev = proc->device;
+	struct bitmain_info * const info = dev->device_data;
+	
+	// Can't use thr->work_restart as that merely triggers this function in minerloop_queue
+	info->work_restart = true;
+	thr->queue_full = false;
+}
+
+static struct api_data *bitmain_api_stats(struct cgpu_info *cgpu)
+{
+	struct api_data *root = NULL;
+	struct bitmain_info *info = cgpu->device_data;
+	double hwp = (cgpu->hw_errors + cgpu->diff1) ?
+			(double)(cgpu->hw_errors) / (double)(cgpu->hw_errors + cgpu->diff1) : 0;
+
+	root = api_add_int(root, "miner_count", &(info->chain_num), false);
+	root = api_add_int(root, "asic_count", &(info->asic_num), false);
+	root = api_add_int(root, "timeout", &(info->timeout), false);
+	root = api_add_string(root, "frequency", info->frequency_t, false);
+	root = api_add_string(root, "voltage", info->voltage_t, false);
+	root = api_add_int(root, "hwv1", &(info->hw_version[0]), false);
+	root = api_add_int(root, "hwv2", &(info->hw_version[1]), false);
+	root = api_add_int(root, "hwv3", &(info->hw_version[2]), false);
+	root = api_add_int(root, "hwv4", &(info->hw_version[3]), false);
+
+	root = api_add_int(root, "fan_num", &(info->fan_num), false);
+	root = api_add_int(root, "fan1", &(info->fan[0]), false);
+	root = api_add_int(root, "fan2", &(info->fan[1]), false);
+	root = api_add_int(root, "fan3", &(info->fan[2]), false);
+	root = api_add_int(root, "fan4", &(info->fan[3]), false);
+	root = api_add_int(root, "fan5", &(info->fan[4]), false);
+	root = api_add_int(root, "fan6", &(info->fan[5]), false);
+	root = api_add_int(root, "fan7", &(info->fan[6]), false);
+	root = api_add_int(root, "fan8", &(info->fan[7]), false);
+	root = api_add_int(root, "fan9", &(info->fan[8]), false);
+	root = api_add_int(root, "fan10", &(info->fan[9]), false);
+	root = api_add_int(root, "fan11", &(info->fan[10]), false);
+	root = api_add_int(root, "fan12", &(info->fan[11]), false);
+	root = api_add_int(root, "fan13", &(info->fan[12]), false);
+	root = api_add_int(root, "fan14", &(info->fan[13]), false);
+	root = api_add_int(root, "fan15", &(info->fan[14]), false);
+	root = api_add_int(root, "fan16", &(info->fan[15]), false);
+
+	root = api_add_int(root, "temp_num", &(info->temp_num), false);
+	root = api_add_int(root, "temp1", &(info->temp[0]), false);
+	root = api_add_int(root, "temp2", &(info->temp[1]), false);
+	root = api_add_int(root, "temp3", &(info->temp[2]), false);
+	root = api_add_int(root, "temp4", &(info->temp[3]), false);
+	root = api_add_int(root, "temp5", &(info->temp[4]), false);
+	root = api_add_int(root, "temp6", &(info->temp[5]), false);
+	root = api_add_int(root, "temp7", &(info->temp[6]), false);
+	root = api_add_int(root, "temp8", &(info->temp[7]), false);
+	root = api_add_int(root, "temp9", &(info->temp[8]), false);
+	root = api_add_int(root, "temp10", &(info->temp[9]), false);
+	root = api_add_int(root, "temp11", &(info->temp[10]), false);
+	root = api_add_int(root, "temp12", &(info->temp[11]), false);
+	root = api_add_int(root, "temp13", &(info->temp[12]), false);
+	root = api_add_int(root, "temp14", &(info->temp[13]), false);
+	root = api_add_int(root, "temp15", &(info->temp[14]), false);
+	root = api_add_int(root, "temp16", &(info->temp[15]), false);
+	root = api_add_int(root, "temp_avg", &(info->temp_avg), false);
+	root = api_add_int(root, "temp_max", &(info->temp_max), false);
+	root = api_add_percent(root, "Device Hardware%", &hwp, true);
+	root = api_add_int(root, "no_matching_work", &(info->no_matching_work), false);
+	/*
+	for (int i = 0; i < info->chain_num; ++i) {
+		char mcw[24];
+
+		sprintf(mcw, "match_work_count%d", i + 1);
+		root = api_add_int(root, mcw, &(info->matching_work[i]), false);
+	}*/
+
+	root = api_add_int(root, "chain_acn1", &(info->chain_asic_num[0]), false);
+	root = api_add_int(root, "chain_acn2", &(info->chain_asic_num[1]), false);
+	root = api_add_int(root, "chain_acn3", &(info->chain_asic_num[2]), false);
+	root = api_add_int(root, "chain_acn4", &(info->chain_asic_num[3]), false);
+	root = api_add_int(root, "chain_acn5", &(info->chain_asic_num[4]), false);
+	root = api_add_int(root, "chain_acn6", &(info->chain_asic_num[5]), false);
+	root = api_add_int(root, "chain_acn7", &(info->chain_asic_num[6]), false);
+	root = api_add_int(root, "chain_acn8", &(info->chain_asic_num[7]), false);
+	root = api_add_int(root, "chain_acn9", &(info->chain_asic_num[8]), false);
+	root = api_add_int(root, "chain_acn10", &(info->chain_asic_num[9]), false);
+	root = api_add_int(root, "chain_acn11", &(info->chain_asic_num[10]), false);
+	root = api_add_int(root, "chain_acn12", &(info->chain_asic_num[11]), false);
+	root = api_add_int(root, "chain_acn13", &(info->chain_asic_num[12]), false);
+	root = api_add_int(root, "chain_acn14", &(info->chain_asic_num[13]), false);
+	root = api_add_int(root, "chain_acn15", &(info->chain_asic_num[14]), false);
+	root = api_add_int(root, "chain_acn16", &(info->chain_asic_num[15]), false);
+
+	//applog(LOG_ERR, "chain asic status:%s", info->chain_asic_status_t[0]);
+	root = api_add_string(root, "chain_acs1", info->chain_asic_status_t[0], false);
+	root = api_add_string(root, "chain_acs2", info->chain_asic_status_t[1], false);
+	root = api_add_string(root, "chain_acs3", info->chain_asic_status_t[2], false);
+	root = api_add_string(root, "chain_acs4", info->chain_asic_status_t[3], false);
+	root = api_add_string(root, "chain_acs5", info->chain_asic_status_t[4], false);
+	root = api_add_string(root, "chain_acs6", info->chain_asic_status_t[5], false);
+	root = api_add_string(root, "chain_acs7", info->chain_asic_status_t[6], false);
+	root = api_add_string(root, "chain_acs8", info->chain_asic_status_t[7], false);
+	root = api_add_string(root, "chain_acs9", info->chain_asic_status_t[8], false);
+	root = api_add_string(root, "chain_acs10", info->chain_asic_status_t[9], false);
+	root = api_add_string(root, "chain_acs11", info->chain_asic_status_t[10], false);
+	root = api_add_string(root, "chain_acs12", info->chain_asic_status_t[11], false);
+	root = api_add_string(root, "chain_acs13", info->chain_asic_status_t[12], false);
+	root = api_add_string(root, "chain_acs14", info->chain_asic_status_t[13], false);
+	root = api_add_string(root, "chain_acs15", info->chain_asic_status_t[14], false);
+	root = api_add_string(root, "chain_acs16", info->chain_asic_status_t[15], false);
+
+	//root = api_add_int(root, "chain_acs1", &(info->chain_asic_status[0]), false);
+	//root = api_add_int(root, "chain_acs2", &(info->chain_asic_status[1]), false);
+	//root = api_add_int(root, "chain_acs3", &(info->chain_asic_status[2]), false);
+	//root = api_add_int(root, "chain_acs4", &(info->chain_asic_status[3]), false);
+
+	return root;
+}
+
+static void bitmain_shutdown(struct thr_info *thr)
+{
+	do_bitmain_close(thr);
+}
+
+static
+const char *bitmain_set_layout(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct bitmain_info *info = proc->device_data;
+	char *endptr, *next_field;
+	const long int n_chains = strtol(newvalue, &endptr, 0);
+	if (endptr == newvalue || n_chains < 1)
+		return "Missing chain count";
+	long int n_asics = 0;
+	if (endptr[0] == ':' || endptr[1] == ',')
+	{
+		next_field = &endptr[1];
+		n_asics = strtol(next_field, &endptr, 0);
+	}
+	if (n_asics < 1)
+		return "Missing ASIC count";
+	if (n_asics > BITMAIN_DEFAULT_ASIC_NUM)
+		return "ASIC count too high";
+	info->chain_num = n_chains;
+	info->asic_num = n_asics;
+	return NULL;
+}
+
+static
+const char *bitmain_set_timeout(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct bitmain_info *info = proc->device_data;
+	const int timeout = atoi(newvalue);
+	if (timeout < 0 || timeout > 0xff)
+		return "Invalid timeout setting";
+	info->timeout = timeout;
+	return NULL;
+}
+
+static
+const char *bitmain_set_clock(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct bitmain_info *info = proc->device_data;
+	const int freq = atoi(newvalue);
+	if (freq < BITMAIN_MIN_FREQUENCY || freq > BITMAIN_MAX_FREQUENCY)
+		return "Invalid clock frequency";
+	info->frequency = freq;
+	sprintf(info->frequency_t, "%d", freq);
+	return NULL;
+}
+
+static
+const char *bitmain_set_reg_data(struct cgpu_info * const proc, const char * const optname, const char *newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct bitmain_info *info = proc->device_data;
+	uint8_t reg_data[4] = {0};
+	
+	if (newvalue[0] == 'x')
+		++newvalue;
+	
+	size_t nvlen = strlen(newvalue);
+	if (nvlen > (sizeof(reg_data) * 2) || !nvlen || nvlen % 2)
+		return "reg_data must be a hex string of 2-8 digits (1-4 bytes)";
+	
+	if (!hex2bin(reg_data, newvalue, nvlen / 2))
+		return "Invalid reg data hex";
+	
+	memcpy(info->reg_data, reg_data, sizeof(reg_data));
+	
+	return NULL;
+}
+
+static
+const char *bitmain_set_voltage(struct cgpu_info * const proc, const char * const optname, const char *newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct bitmain_info *info = proc->device_data;
+	uint8_t voltage_data[2] = {0};
+	
+	if (newvalue[0] == 'x')
+		++newvalue;
+	else
+voltage_usage:
+		return "voltage must be 'x' followed by a hex string of 1-4 digits (1-2 bytes)";
+	
+	size_t nvlen = strlen(newvalue);
+	if (nvlen > (sizeof(voltage_data) * 2) || !nvlen || nvlen % 2)
+		goto voltage_usage;
+	
+	if (!hex2bin(voltage_data, newvalue, nvlen / 2))
+		return "Invalid voltage data hex";
+	
+	memcpy(info->voltage, voltage_data, sizeof(voltage_data));
+	bin2hex(info->voltage_t, voltage_data, 2);
+	info->voltage_t[5] = 0;
+	info->voltage_t[4] = info->voltage_t[3];
+	info->voltage_t[3] = info->voltage_t[2];
+	info->voltage_t[2] = info->voltage_t[1];
+	info->voltage_t[1] = '.';
+	
+	return NULL;
+}
+
+static bool bitmain_set_packet_max_work(struct cgpu_info * const dev, const unsigned i)
+{
+	struct bitmain_info * const info = dev->device_data;
+	uint8_t * const new_queuebuf = realloc(info->queuebuf, BITMAIN_TASK_HEADER_SIZE + (i * BITMAIN_WORK_SIZE) + BITMAIN_TASK_FOOTER_SIZE);
+	if (!new_queuebuf)
+		return false;
+	info->packet_max_work = i;
+	info->queuebuf = new_queuebuf;
+	return true;
+}
+
+static const char *bitmain_set_packet_max_work_opt(struct cgpu_info * const proc, const char * const optname, const char *newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	const int i = atoi(newvalue);
+	if (i < 1)
+		return "Invalid setting";
+	if (!bitmain_set_packet_max_work(proc->device, i))
+		return "realloc failure";
+	return NULL;
+}
+
+static
+const char *bitmain_set_packet_max_nonce_opt(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct bitmain_info *info = proc->device_data;
+	const int i = atoi(newvalue);
+	if (i < 0 || i > BITMAIN_MAX_PACKET_MAX_NONCE)
+		return "Invalid setting";
+	info->packet_max_nonce = i;
+	return NULL;
+}
+
+static const char *bitmain_set_model(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct cgpu_info * const dev = proc->device;
+	struct bitmain_info * const info = dev->device_data;
+	
+	if (toupper(newvalue[0]) != 'S') {
+unknown_model:
+		return "Unknown model";
+	}
+	char *endptr;
+	long Sn = strtol(&newvalue[1], &endptr, 10);
+	if (Sn < 1 || Sn > 5)
+		goto unknown_model;
+	if (Sn == 5 && endptr[0] == '+')
+		++endptr;
+	if (endptr[0] && !isspace(endptr[0]))
+		goto unknown_model;
+	
+	info->chip_type = BMC_UNKNOWN;
+	switch (Sn) {
+		case 1:
+			info->chip_type = BMC_BM1380;
+			bitmain_set_packet_max_work(dev, 8);
+			info->packet_max_nonce = 8;
+			break;
+		case 2:
+			info->chip_type = BMC_BM1380;
+			bitmain_set_packet_max_work(dev, 0x40);
+			info->packet_max_nonce = 0x80;
+			break;
+		case 3:
+			info->chip_type = BMC_BM1382;
+			bitmain_set_packet_max_work(dev, 8);
+			info->packet_max_nonce = 0x80;
+			break;
+		case 4:
+			info->chip_type = BMC_BM1382;
+			bitmain_set_packet_max_work(dev, 0x40);
+			info->packet_max_nonce = 0x80;
+			break;
+		case 5:
+			info->chip_type = BMC_BM1384;
+			bitmain_set_packet_max_work(dev, 0x40);
+			info->packet_max_nonce = 0x80;
+			break;
+	}
+	return NULL;
+}
+
+static const struct bfg_set_device_definition bitmain_set_device_funcs_init[] = {
+	{"model", bitmain_set_model, "model of unit (S1-S5)"},
+	{"layout", bitmain_set_layout, "number of chains ':' number of ASICs per chain (eg: 32:8)"},
+	{"timeout", bitmain_set_timeout, "timeout"},
+	{"clock", bitmain_set_clock, "clock frequency"},
+	{"reg_data", bitmain_set_reg_data, "reg_data (eg: x0d82)"},
+	{"voltage", bitmain_set_voltage, "voltage (must be specified as 'x' and hex data; eg: x0725)"},
+	{"packet_max_work", bitmain_set_packet_max_work_opt, NULL},
+	{"packet_max_nonce", bitmain_set_packet_max_nonce_opt, NULL},
+	{NULL},
+};
+
+struct device_drv bitmain_drv = {
+	.dname = "bitmain",
+	.name = "BTM",
+	.drv_detect = bitmain_detect,
+	.thread_prepare = bitmain_prepare,
+	
+	.minerloop = minerloop_queue,
+	.queue_append = bitmain_queue_append,
+	.queue_flush = bitmain_queue_flush,
+	.poll = bitmain_poll,
+	
+	.get_api_stats = bitmain_api_stats,
+	.reinit_device = bitmain_init,
+	.thread_shutdown = bitmain_shutdown,
+};

+ 251 - 0
driver-bitmain.h

@@ -0,0 +1,251 @@
+/*
+ * Copyright 2013 BitMain project
+ * Copyright 2013 BitMain <xlc1985@126.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#ifndef BITMAIN_H
+#define BITMAIN_H
+
+#ifdef USE_BITMAIN
+
+#include <curl/curl.h>
+
+#include "util.h"
+
+//#define BITMAIN_TYPE_S1
+//#define BITMAIN_TYPE_S2
+//#define BITMAIN_TYPE_S3
+#define BITMAIN_TYPE_S4
+
+#define BITMAIN_MINER_THREADS 1
+
+#define BITMAIN_RESET_PITCH	(300*1000*1000)
+
+#define BITMAIN_TOKEN_TYPE_TXCONFIG 0x51
+#define BITMAIN_TOKEN_TYPE_TXTASK   0x52
+#define BITMAIN_TOKEN_TYPE_RXSTATUS 0x53
+
+#define BITMAIN_DATA_TYPE_RXSTATUS  0xa1
+#define BITMAIN_DATA_TYPE_RXNONCE   0xa2
+
+#define BITMAIN_FAN_FACTOR 60
+#define BITMAIN_PWM_MAX 0xA0
+#define BITMAIN_DEFAULT_FAN_MIN 20
+#define BITMAIN_DEFAULT_FAN_MAX 100
+#define BITMAIN_DEFAULT_FAN_MAX_PWM 0xA0 /* 100% */
+#define BITMAIN_DEFAULT_FAN_MIN_PWM 0x20 /*  20% */
+
+#define BITMAIN_DEFAULT_TIMEOUT 0x2D
+#define BITMAIN_MIN_FREQUENCY 10
+#define BITMAIN_MAX_FREQUENCY 1000000
+#define BITMAIN_TIMEOUT_FACTOR 12690
+#define BITMAIN_DEFAULT_FREQUENCY 282
+#define BITMAIN_DEFAULT_VOLTAGE_T "0725"
+#define BITMAIN_DEFAULT_VOLTAGE0 0x07
+#define BITMAIN_DEFAULT_VOLTAGE1 0x25
+#define BITMAIN_DEFAULT_CHAIN_NUM 8
+#define BITMAIN_DEFAULT_ASIC_NUM 32
+#define BITMAIN_DEFAULT_REG_DATA 0
+
+#define BITMAIN_AUTO_CYCLE 1024
+
+#define BITMAIN_FTDI_READSIZE 2048
+#define BITMAIN_USB_PACKETSIZE 512
+#define BITMAIN_SENDBUF_SIZE 8192
+#define BITMAIN_READBUF_SIZE 8192
+#define BITMAIN_RESET_TIMEOUT 100
+#define BITMAIN_READ_TIMEOUT 18 /* Enough to only half fill the buffer */
+#define BITMAIN_LATENCY 1
+
+#define BITMAIN_MAX_CHAIN_NUM      16
+
+#define BITMAIN_TASK_HEADER_SIZE   8
+#define BITMAIN_TASK_FOOTER_SIZE   2
+#define BITMAIN_WORK_SIZE          0x30
+
+#define BITMAIN_MAX_PACKET_MAX_NONCE  0x80
+#define BITMAIN_MAX_TEMP_NUM       32
+#define BITMAIN_MAX_FAN_NUM        32
+
+struct bitmain_packet_head {
+	uint8_t token_type;
+	uint8_t version;
+	uint16_t length;
+} __attribute__((packed, aligned(4)));
+
+struct bitmain_txconfig_token {
+	uint8_t token_type;
+	uint8_t version;
+	uint16_t length;
+	uint8_t reset                :1;
+	uint8_t fan_eft              :1;
+	uint8_t timeout_eft          :1;
+	uint8_t frequency_eft        :1;
+	uint8_t voltage_eft          :1;
+	uint8_t chain_check_time_eft :1;
+	uint8_t chip_config_eft      :1;
+	uint8_t hw_error_eft         :1;
+	uint8_t beeper_ctrl          :1;
+	uint8_t temp_over_ctrl       :1;
+	uint8_t fan_home_mode        :1;
+	uint8_t reserved1            :5;
+	uint8_t chain_check_time;
+	uint8_t reserved2;
+
+	uint8_t chain_num;
+	uint8_t asic_num;
+	uint8_t fan_pwm_data;
+	uint8_t timeout_data;
+
+	uint16_t frequency;
+	uint8_t voltage[2];
+
+	uint8_t reg_data[4];
+	uint8_t chip_address;
+	uint8_t reg_address;
+	uint16_t crc;
+} __attribute__((packed, aligned(4)));
+
+struct bitmain_rxstatus_token {
+	uint8_t token_type;
+	uint8_t version;
+	uint16_t length;
+	uint8_t chip_status_eft      :1;
+	uint8_t detect_get           :1;
+	uint8_t reserved1            :6;
+	uint8_t reserved2[3];
+
+	uint8_t chip_address;
+	uint8_t reg_address;
+	uint16_t crc;
+} __attribute__((packed, aligned(4)));
+
+struct bitmain_rxstatus_data {
+	uint8_t data_type;
+	uint8_t version;
+	uint16_t length;
+	uint8_t chip_value_eft       :1;
+	uint8_t reserved1            :3;
+	uint8_t get_blk_num          :4;
+	uint8_t chain_num;
+	uint16_t fifo_space;
+	uint8_t hw_version[4];
+	uint8_t fan_num;
+	uint8_t temp_num;
+	uint16_t fan_exist;
+	uint32_t temp_exist;
+	uint32_t nonce_error;
+	uint32_t reg_value;
+	uint32_t chain_asic_exist[BITMAIN_MAX_CHAIN_NUM*8];
+	uint32_t chain_asic_status[BITMAIN_MAX_CHAIN_NUM*8];
+	uint8_t chain_asic_num[BITMAIN_MAX_CHAIN_NUM];
+	uint8_t temp[BITMAIN_MAX_TEMP_NUM];
+	uint8_t fan[BITMAIN_MAX_FAN_NUM];
+	uint16_t crc;
+} __attribute__((packed, aligned(4)));
+
+struct bitmain_rxnonce_nonce {
+	uint32_t work_id;
+	uint32_t nonce;
+} __attribute__((packed, aligned(4)));
+
+struct bitmain_rxnonce_data {
+	uint8_t data_type;
+	uint8_t version;
+	uint16_t length;
+	uint16_t fifo_space;
+	uint16_t diff;
+	uint64_t total_nonce_num;
+	struct bitmain_rxnonce_nonce nonces[BITMAIN_MAX_PACKET_MAX_NONCE];
+	uint16_t crc;
+} __attribute__((packed, aligned(4)));
+
+enum bitmain_chip {
+	BMC_UNKNOWN,
+	BMC_BM1380,
+	BMC_BM1382,
+	BMC_BM1384,
+};
+
+struct bitmain_info {
+	void *device_curl;
+	SOCKETTYPE curl_sock;
+	
+	enum bitmain_chip chip_type;
+	int chain_num;
+	int asic_num;
+	int chain_asic_num[BITMAIN_MAX_CHAIN_NUM];
+	uint32_t chain_asic_exist[BITMAIN_MAX_CHAIN_NUM*8];
+	uint32_t chain_asic_status[BITMAIN_MAX_CHAIN_NUM*8];
+	char chain_asic_status_t[BITMAIN_MAX_CHAIN_NUM][320];
+	int timeout;
+	int errorcount;
+	int errorcount2;
+	uint32_t nonce_error;
+	uint32_t last_nonce_error;
+	uint8_t reg_data[4];
+	
+	unsigned packet_max_work;  // BITMAIN_MAX_WORK_NUM
+	unsigned poll_prio_threshold;  // BITMAIN_MAX_WORK_QUEUE_NUM
+	unsigned packet_max_nonce;     // BITMAIN_MAX_NONCE_NUM
+
+	int fan_num;
+	int fan[BITMAIN_MAX_FAN_NUM];
+	int temp_num;
+	int temp[BITMAIN_MAX_TEMP_NUM];
+
+	int temp_max;
+	int temp_avg;
+	int temp_history_count;
+	int temp_history_index;
+	int temp_sum;
+	int temp_old;
+	int fan_pwm;
+
+	int frequency;
+	char frequency_t[256];
+	uint8_t voltage[2];
+	char voltage_t[8];
+
+	int diff;
+	float lowest_goal_diff;
+	uint32_t next_work_id;
+
+	int no_matching_work;
+	//int matching_work[BITMAIN_DEFAULT_CHAIN_NUM];
+
+	pthread_mutex_t qlock;
+	int fifo_space;
+	int max_fifo_space;
+	int hw_version[4];
+
+	int ready_to_queue;
+	uint8_t *queuebuf;
+	
+	bool reset;
+	bool work_restart;
+	
+	char g_miner_version[256];
+	
+	uint8_t readbuf[BITMAIN_READBUF_SIZE];
+	int readbuf_offset;
+};
+
+#define BITMAIN_READ_SIZE 12
+
+#define BTM_GETS_ERROR -1
+#define BTM_GETS_OK 0
+
+#define BTM_SEND_ERROR -1
+#define BTM_SEND_OK 0
+
+#define BITMAIN_READ_TIME(baud) ((double)BITMAIN_READ_SIZE * (double)8.0 / (double)(baud))
+#define ASSERT1(condition) __maybe_unused static char sizeof_uint32_t_must_be_4[(condition)?1:-1]
+
+#endif /* USE_BITMAIN */
+#endif	/* BITMAIN_H */

+ 23 - 0
driver-hashfast.c

@@ -844,6 +844,27 @@ void hashfast_wlogprint_status(struct cgpu_info * const proc)
 		}
 	}
 }
+
+static
+void hashfast_tui_wlogprint_choices(struct cgpu_info * const proc)
+{
+	wlogprint("[C]lock speed ");
+}
+
+static
+const char *hashfast_tui_handle_choice(struct cgpu_info * const proc, const int input)
+{
+	switch (input)
+	{
+		case 'c': case 'C':
+		{
+			char prompt[0x80];
+			snprintf(prompt, sizeof(prompt), "Set clock speed (%u-%u)", 1, 0xffe);
+			return proc_set_device_tui_wrapper(proc, NULL, hashfast_set_clock_runtime, prompt, NULL);
+		}
+	}
+	return NULL;
+}
 #endif
 
 struct device_drv hashfast_ums_drv = {
@@ -865,5 +886,7 @@ struct device_drv hashfast_ums_drv = {
 	
 #ifdef HAVE_CURSES
 	.proc_wlogprint_status = hashfast_wlogprint_status,
+	.proc_tui_wlogprint_choices = hashfast_tui_wlogprint_choices,
+	.proc_tui_handle_choice = hashfast_tui_handle_choice,
 #endif
 };

+ 1 - 0
driver-icarus.h

@@ -129,6 +129,7 @@ struct ICARUS_INFO {
 	// Custom driver functions
 	bool (*detect_init_func)(const char *devpath, int fd, struct ICARUS_INFO *);
 	bool (*job_start_func)(struct thr_info *);
+	bool has_bm1382_freq_register;
 	
 #ifdef USE_DUALMINER
 #ifdef USE_SCRYPT

+ 6 - 0
driver-jingtian.c

@@ -245,4 +245,10 @@ struct device_drv jingtian_drv = {
 	.poll = aan_poll,
 	
 	.get_api_extra_device_status = aan_api_device_status,
+	
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = aan_wlogprint_status,
+	.proc_tui_wlogprint_choices = aan_tui_wlogprint_choices,
+	.proc_tui_handle_choice = aan_tui_handle_choice,
+#endif
 };

+ 25 - 9
lowl-vcom.c

@@ -1110,20 +1110,27 @@ int serial_open(const char *devpath, unsigned long baud, uint8_t timeout, bool p
 	comCfg.dcb.fRtsControl = RTS_CONTROL_ENABLE;
 	comCfg.dcb.ByteSize = 8;
 
-	SetCommConfig(hSerial, &comCfg, sizeof(comCfg));
+		if (!SetCommConfig(hSerial, &comCfg, sizeof(comCfg)))
+			// FIXME: We should probably be setting even if baud is clear (in which case, only LOG_DEBUG this)
+			applog(LOG_WARNING, "%s: %s failed: %s", devpath, "SetCommConfig", bfg_strerror(GetLastError(), BST_SYSTEM));
 
 	}
 
 	// Code must specify a valid timeout value (0 means don't timeout)
 	const DWORD ctoms = ((DWORD)timeout * 100);
 	COMMTIMEOUTS cto = {ctoms, 0, ctoms, 0, ctoms};
-	SetCommTimeouts(hSerial, &cto);
+	if (!SetCommTimeouts(hSerial, &cto))
+		applog(timeout ? LOG_WARNING : LOG_DEBUG, "%s: %s failed: %s", devpath, "SetCommTimeouts", bfg_strerror(GetLastError(), BST_SYSTEM));
 
 	if (purge) {
-		PurgeComm(hSerial, PURGE_RXABORT);
-		PurgeComm(hSerial, PURGE_TXABORT);
-		PurgeComm(hSerial, PURGE_RXCLEAR);
-		PurgeComm(hSerial, PURGE_TXCLEAR);
+		if (!PurgeComm(hSerial, PURGE_RXABORT))
+			applog(LOG_WARNING, "%s: %s failed: %s", devpath, "PURGE_RXABORT", bfg_strerror(GetLastError(), BST_SYSTEM));
+		if (!PurgeComm(hSerial, PURGE_TXABORT))
+			applog(LOG_WARNING, "%s: %s failed: %s", devpath, "PURGE_TXABORT", bfg_strerror(GetLastError(), BST_SYSTEM));
+		if (!PurgeComm(hSerial, PURGE_RXCLEAR))
+			applog(LOG_WARNING, "%s: %s failed: %s", devpath, "PURGE_RXCLEAR", bfg_strerror(GetLastError(), BST_SYSTEM));
+		if (!PurgeComm(hSerial, PURGE_TXCLEAR))
+			applog(LOG_WARNING, "%s: %s failed: %s", devpath, "PURGE_TXCLEAR", bfg_strerror(GetLastError(), BST_SYSTEM));
 	}
 
 	return _open_osfhandle((intptr_t)hSerial, 0);
@@ -1156,7 +1163,10 @@ int serial_open(const char *devpath, unsigned long baud, uint8_t timeout, bool p
 
 	struct termios my_termios;
 
-	tcgetattr(fdDev, &my_termios);
+	if (tcgetattr(fdDev, &my_termios))
+		applog(baud ? LOG_WARNING : LOG_DEBUG, "%s: %s failed: %s", devpath, "tcgetattr", bfg_strerror(errno, BST_ERRNO));
+	else
+	{
 
 #ifdef TERMIOS_DEBUG
 	termios_debug(devpath, &my_termios, "before");
@@ -1195,15 +1205,21 @@ int serial_open(const char *devpath, unsigned long baud, uint8_t timeout, bool p
 	termios_debug(devpath, &my_termios, "settings");
 #endif
 
-	tcsetattr(fdDev, TCSANOW, &my_termios);
+		if (tcsetattr(fdDev, TCSANOW, &my_termios))
+			applog(baud ? LOG_WARNING : LOG_DEBUG, "%s: %s failed: %s", devpath, "tcsetattr", bfg_strerror(errno, BST_ERRNO));
 
 #ifdef TERMIOS_DEBUG
 	tcgetattr(fdDev, &my_termios);
 	termios_debug(devpath, &my_termios, "after");
 #endif
 
+	}
+
 	if (purge)
-		tcflush(fdDev, TCIOFLUSH);
+	{
+		if (tcflush(fdDev, TCIOFLUSH))
+			applog(LOG_WARNING, "%s: %s failed: %s", devpath, "tcflush", bfg_strerror(errno, BST_ERRNO));
+	}
 	return fdDev;
 #endif
 }

+ 1 - 1
m4/bundled_lib.m4

@@ -50,7 +50,7 @@ AC_DEFUN([BFG_BUNDLED_LIB_VARS],[
 	BFG_CHECK_LD_ORIGIN
 	_AC_SRCDIRS(["$ac_dir"])
 	$1_CFLAGS='-I'"${ac_abs_top_srcdir}"'/$2'
-	$1_LIBS='-L'"${ac_abs_top_srcdir}"'/$2/.libs -Wl,-rpath,\$$ORIGIN/$2/.libs'"$origin_LDFLAGS"' m4_foreach_w([mylib],[$3],[ -l[]mylib])'
+	$1_LIBS='-L'"${ac_abs_top_builddir}"'/$2/.libs -Wl,-rpath,\$$ORIGIN/$2/.libs'"$origin_LDFLAGS"' m4_foreach_w([mylib],[$3],[ -l[]mylib])'
 	$1_SUBDIRS=$2
 	$1_EXTRADEPS=$1_directory
 	BUNDLED_LIB_RULES="$BUNDLED_LIB_RULES

+ 137 - 59
miner.c

@@ -1216,6 +1216,19 @@ static
 void pool_set_uri(struct pool * const pool, char * const uri)
 {
 	pool->rpc_url = uri;
+	pool->pool_diff_effective_retroactively = uri_get_param_bool2(uri, "retrodiff");
+}
+
+static
+bool pool_diff_effective_retroactively(struct pool * const pool)
+{
+	if (pool->pool_diff_effective_retroactively != BTS_UNKNOWN) {
+		return pool->pool_diff_effective_retroactively;
+	}
+	
+	// By default, we enable retrodiff for stratum pools since some servers implement mining.set_difficulty in this way
+	// Note that share_result will explicitly disable BTS_UNKNOWN -> BTS_FALSE if a retrodiff share is rejected specifically for its failure to meet the target.
+	return pool->stratum_active;
 }
 
 /* Pool variant of test and set */
@@ -3384,18 +3397,21 @@ void refresh_bitcoind_address(struct mining_goal_info * const goal, const bool f
 			}
 			applog(LOG_WARNING, "Error %cetting coinbase address from pool %d: %s", 'g', pool->pool_no, estrc);
 			free(estr);
+			json_decref(json);
 			continue;
 		}
 		s = bfg_json_obj_string(json, "result", NULL);
 		if (unlikely(!s))
 		{
 			applog(LOG_WARNING, "Error %cetting coinbase address from pool %d: %s", 'g', pool->pool_no, "(return value was not a String)");
+			json_decref(json);
 			continue;
 		}
 		s2 = set_b58addr(s, &newscript);
 		if (unlikely(s2))
 		{
 			applog(LOG_WARNING, "Error %cetting coinbase address from pool %d: %s", 's', pool->pool_no, s2);
+			json_decref(json);
 			continue;
 		}
 		if (goal->generation_script)
@@ -3403,6 +3419,7 @@ void refresh_bitcoind_address(struct mining_goal_info * const goal, const bool f
 			if (bytes_eq(&newscript, goal->generation_script))
 			{
 				applog(LOG_DEBUG, "Pool %d returned coinbase address already in use (%s)", pool->pool_no, s);
+				json_decref(json);
 				break;
 			}
 		}
@@ -3414,6 +3431,7 @@ void refresh_bitcoind_address(struct mining_goal_info * const goal, const bool f
 		bytes_assimilate(goal->generation_script, &newscript);
 		coinbase_script_block_id = blkchain->currentblk->block_id;
 		applog(LOG_NOTICE, "Now using coinbase address %s, provided by pool %d", s, pool->pool_no);
+		json_decref(json);
 		break;
 	}
 	
@@ -5259,6 +5277,16 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work,
 		char reason[32];
 		put_in_parens(reason, sizeof(reason), extract_reject_reason(val, res, err, work));
 		applog(LOG_DEBUG, "Share above target rejected%s by pool %u as expected, ignoring", reason, pool->pool_no);
+		
+		// Stratum error 23 is "low difficulty share", which suggests this pool tracks job difficulty correctly.
+		// Therefore, we disable retrodiff if it was enabled-by-default.
+		if (pool->pool_diff_effective_retroactively == BTS_UNKNOWN) {
+			json_t *errnum;
+			if (work->stratum && err && json_is_array(err) && json_array_size(err) >= 1 && (errnum = json_array_get(err, 0)) && json_is_number(errnum) && ((int)json_number_value(errnum)) == 23) {
+				applog(LOG_DEBUG, "Disabling retroactive difficulty adjustments for pool %u", pool->pool_no);
+				pool->pool_diff_effective_retroactively = false;
+			}
+		}
 	} else {
 		mutex_lock(&stats_lock);
 		cgpu->rejected++;
@@ -8068,6 +8096,55 @@ void zero_stats(void)
 	}
 }
 
+int bfg_strategy_parse(const char * const s)
+{
+	char *endptr;
+	if (!(s && s[0]))
+		return -1;
+	long int selected = strtol(s, &endptr, 0);
+	if (endptr == s || *endptr) {
+		// Look-up by name
+		selected = -1;
+		for (unsigned i = 0; i <= TOP_STRATEGY; ++i) {
+			if (!strcasecmp(strategies[i].s, s)) {
+				selected = i;
+			}
+		}
+	}
+	if (selected < 0 || selected > TOP_STRATEGY) {
+		return -1;
+	}
+	return selected;
+}
+
+bool bfg_strategy_change(const int selected, const char * const param)
+{
+	if (param && param[0]) {
+		switch (selected) {
+			case POOL_ROTATE:
+			{
+				char *endptr;
+				long int n = strtol(param, &endptr, 0);
+				if (n < 0 || n > 9999 || *endptr) {
+					return false;
+				}
+				opt_rotate_period = n;
+				break;
+			}
+			default:
+				return false;
+		}
+	}
+	
+	mutex_lock(&lp_lock);
+	pool_strategy = selected;
+	pthread_cond_broadcast(&lp_cond);
+	mutex_unlock(&lp_lock);
+	switch_pools(NULL);
+	
+	return true;
+}
+
 #ifdef HAVE_CURSES
 static
 void loginput_mode(const int size)
@@ -8200,25 +8277,25 @@ retry:
 	} else if (!strncasecmp(&input, "c", 1)) {
 		for (i = 0; i <= TOP_STRATEGY; i++)
 			wlogprint("%d: %s\n", i, strategies[i].s);
-		selected = curses_int("Select strategy number type");
+		{
+			char * const selected_str = curses_input("Select strategy type");
+			selected = bfg_strategy_parse(selected_str);
+			free(selected_str);
+		}
 		if (selected < 0 || selected > TOP_STRATEGY) {
 			wlogprint("Invalid selection\n");
 			goto retry;
 		}
+		char *param = NULL;
 		if (selected == POOL_ROTATE) {
-			opt_rotate_period = curses_int("Select interval in minutes");
-
-			if (opt_rotate_period < 0 || opt_rotate_period > 9999) {
-				opt_rotate_period = 0;
-				wlogprint("Invalid selection\n");
-				goto retry;
-			}
+			param = curses_input("Select interval in minutes");
+		}
+		bool result = bfg_strategy_change(selected, param);
+		free(param);
+		if (!result) {
+			wlogprint("Invalid selection\n");
+			goto retry;
 		}
-		mutex_lock(&lp_lock);
-		pool_strategy = selected;
-		pthread_cond_broadcast(&lp_cond);
-		mutex_unlock(&lp_lock);
-		switch_pools(NULL);
 		goto updated;
 	} else if (!strncasecmp(&input, "i", 1)) {
 		selected = curses_int("Select pool number");
@@ -10545,7 +10622,7 @@ enum test_nonce2_result _test_nonce2(struct work *work, uint32_t nonce, bool che
 	{
 		bool high_hash = true;
 		struct pool * const pool = work->pool;
-		if (pool->stratum_active)
+		if (pool_diff_effective_retroactively(pool))
 		{
 			// Some stratum pools are buggy and expect difficulty changes to be immediate retroactively, so if the target has changed, check and submit just in case
 			if (memcmp(pool->next_target, work->target, sizeof(work->target)))
@@ -10553,7 +10630,10 @@ enum test_nonce2_result _test_nonce2(struct work *work, uint32_t nonce, bool che
 				applog(LOG_DEBUG, "Stratum pool %u target has changed since work job issued, checking that too",
 				       pool->pool_no);
 				if (hash_target_check_v(work->hash, pool->next_target))
+				{
 					high_hash = false;
+					work->work_difficulty = target_diff(pool->next_target);
+				}
 			}
 		}
 		if (high_hash)
@@ -12370,8 +12450,8 @@ rescan:
 		pthread_join(info->probe_pth, NULL);
 #endif
 	
-	struct driver_registration *reg, *tmp;
-	BFG_FOREACH_DRIVER_BY_PRIORITY(reg, tmp)
+	struct driver_registration *reg;
+	BFG_FOREACH_DRIVER_BY_PRIORITY(reg)
 	{
 		const struct device_drv * const drv = reg->drv;
 		if (!(drv_algo_check(drv) && drv->drv_detect))
@@ -12546,31 +12626,6 @@ bool _probe_device_match(const struct lowlevel_device_info * const info, const c
 	return true;
 }
 
-static
-const struct device_drv *_probe_device_find_drv(const char * const _dname, const size_t dnamelen)
-{
-	struct driver_registration *dreg;
-	char dname[dnamelen];
-	int i;
-	
-	for (i = 0; i < dnamelen; ++i)
-		dname[i] = tolower(_dname[i]);
-	BFG_FIND_DRV_BY_DNAME(dreg, dname, dnamelen);
-	if (!dreg)
-	{
-		for (i = 0; i < dnamelen; ++i)
-			dname[i] = toupper(_dname[i]);
-		BFG_FIND_DRV_BY_NAME(dreg, dname, dnamelen);
-		if (!dreg)
-			return NULL;
-	}
-	
-	if (!drv_algo_check(dreg->drv))
-		return NULL;
-	
-	return dreg->drv;
-}
-
 static
 bool _probe_device_do_probe(const struct device_drv * const drv, const struct lowlevel_device_info * const info, bool * const request_rescan_p)
 {
@@ -12608,7 +12663,7 @@ void *probe_device_thread(void *p)
 	
 	// if lowlevel device matches specific user assignment, probe requested driver(s)
 	struct string_elist *sd_iter, *sd_tmp;
-	struct driver_registration *dreg, *dreg_tmp;
+	struct driver_registration *dreg;
 	DL_FOREACH_SAFE(scan_devices, sd_iter, sd_tmp)
 	{
 		const char * const dname = sd_iter->string;
@@ -12620,17 +12675,26 @@ void *probe_device_thread(void *p)
 		{
 			if (!_probe_device_match(info, ser))
 				continue;
+			
 			const size_t dnamelen = (colon - dname);
-			const struct device_drv * const drv = _probe_device_find_drv(dname, dnamelen);
-			if (!(drv && drv->lowl_probe && drv_algo_check(drv)))
-				continue;
-			if (_probe_device_do_probe(drv, info, &request_rescan))
-				return NULL;
+			char dname_nt[dnamelen + 1];
+			memcpy(dname_nt, dname, dnamelen);
+			dname_nt[dnamelen] = '\0';
+			
+			BFG_FOREACH_DRIVER_BY_PRIORITY(dreg) {
+				const struct device_drv * const drv = dreg->drv;
+				if (!(drv && drv->lowl_probe && drv_algo_check(drv)))
+					continue;
+				if (strcasecmp(drv->dname, dname_nt) && strcasecmp(drv->name, dname_nt))
+					continue;
+				if (_probe_device_do_probe(drv, info, &request_rescan))
+					return NULL;
+			}
 		}
 	}
 	
 	// probe driver(s) with auto enabled and matching VID/PID/Product/etc of device
-	BFG_FOREACH_DRIVER_BY_PRIORITY(dreg, dreg_tmp)
+	BFG_FOREACH_DRIVER_BY_PRIORITY(dreg)
 	{
 		const struct device_drv * const drv = dreg->drv;
 		
@@ -12650,8 +12714,14 @@ void *probe_device_thread(void *p)
 			if (strcasecmp("noauto", &colon[1]) && strcasecmp("auto", &colon[1]))
 				continue;
 			const ssize_t dnamelen = (colon - dname);
-			if (dnamelen >= 0 && _probe_device_find_drv(dname, dnamelen) != drv)
-				continue;
+			if (dnamelen >= 0) {
+				char dname_nt[dnamelen + 1];
+				memcpy(dname_nt, dname, dnamelen);
+				dname_nt[dnamelen] = '\0';
+				
+				if (strcasecmp(drv->dname, dname_nt) && strcasecmp(drv->name, dname_nt))
+					continue;
+			}
 			doauto = (tolower(colon[1]) == 'a');
 			if (dnamelen != -1)
 				break;
@@ -12704,7 +12774,7 @@ void *probe_device_thread(void *p)
 					_probe_device_match(info, (dname[0] == '@') ? &dname[1] : dname))
 				{
 					bool dont_rescan = false;
-					BFG_FOREACH_DRIVER_BY_PRIORITY(dreg, dreg_tmp)
+					BFG_FOREACH_DRIVER_BY_PRIORITY(dreg)
 					{
 						const struct device_drv * const drv = dreg->drv;
 						if (!drv_algo_check(drv))
@@ -12728,15 +12798,23 @@ void *probe_device_thread(void *p)
 		if (strcasecmp(&colon[1], "all"))
 			continue;
 		const size_t dnamelen = (colon - dname);
-		const struct device_drv * const drv = _probe_device_find_drv(dname, dnamelen);
-		if (!(drv && drv->lowl_probe && drv_algo_check(drv)))
-			continue;
-		LL_FOREACH2(infolist, info, same_devid_next)
-		{
-			if (info->lowl->exclude_from_all)
+		char dname_nt[dnamelen + 1];
+		memcpy(dname_nt, dname, dnamelen);
+		dname_nt[dnamelen] = '\0';
+
+		BFG_FOREACH_DRIVER_BY_PRIORITY(dreg) {
+			const struct device_drv * const drv = dreg->drv;
+			if (!(drv && drv->lowl_probe && drv_algo_check(drv)))
 				continue;
-			if (_probe_device_do_probe(drv, info, NULL))
-				return NULL;
+			if (strcasecmp(drv->dname, dname_nt) && strcasecmp(drv->name, dname_nt))
+				continue;
+			LL_FOREACH2(infolist, info, same_devid_next)
+			{
+				if (info->lowl->exclude_from_all)
+					continue;
+				if (_probe_device_do_probe(drv, info, NULL))
+					return NULL;
+			}
 		}
 	}
 	

+ 6 - 0
miner.h

@@ -969,6 +969,8 @@ extern bool opt_protocol;
 extern bool opt_dev_protocol;
 extern char *opt_coinbase_sig;
 extern char *request_target_str;
+extern float request_pdiff;
+extern double request_bdiff;
 extern int opt_skip_checks;
 extern char *opt_kernel_path;
 extern char *opt_socks_proxy;
@@ -1115,6 +1117,8 @@ extern void adjust_quota_gcd(void);
 extern struct pool *add_pool2(struct mining_goal_info *);
 #define add_pool()  add_pool2(get_mining_goal("default"))
 extern bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass);
+extern int bfg_strategy_parse(const char *strategy);
+extern bool bfg_strategy_change(int strategy, const char *param);
 
 #define MAX_GPUDEVICES 16
 #define MAX_DEVICES 4096
@@ -1361,6 +1365,7 @@ struct pool {
 	char work_restart_timestamp[11];
 	uint32_t	block_id;
 	struct mining_goal_info *goal;
+	enum bfg_tristate pool_diff_effective_retroactively;
 
 	enum pool_protocol proto;
 
@@ -1718,5 +1723,6 @@ extern struct api_data *api_add_volts(struct api_data *root, const char *name, c
 extern struct api_data *api_add_hs(struct api_data *root, const char *name, const double *data, bool copy_data);
 extern struct api_data *api_add_diff(struct api_data *root, const char *name, const double *data, bool copy_data);
 extern struct api_data *api_add_json(struct api_data *root, const char *name, json_t *data, bool copy_data);
+extern struct api_data *api_add_percent(struct api_data *root, const char *name, const double *data, bool copy_data);
 
 #endif /* __MINER_H__ */

+ 1 - 1
openwrt/bfgminer/Makefile

@@ -11,7 +11,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=bfgminer
 PKG_TITLE:=BFGMiner
-PKG_VERSION:=5.3.0
+PKG_VERSION:=5.4.0
 PKG_RELEASE:=1
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).txz

+ 73 - 1
util.c

@@ -15,6 +15,7 @@
 
 #include "config.h"
 
+#include <float.h>
 #include <math.h>
 #include <stdbool.h>
 #include <stdint.h>
@@ -3162,6 +3163,21 @@ bool auth_stratum(struct pool *pool)
 	applog(LOG_INFO, "Stratum authorisation success for pool %d", pool->pool_no);
 	pool->probed = true;
 	successful_connect = true;
+	
+	if (uri_get_param_bool(pool->rpc_url, "cksuggest", false)) {
+		unsigned long req_bdiff = request_bdiff;
+		
+		const char *q = uri_find_param(pool->rpc_url, "cksuggest", NULL);
+		if (q && q != URI_FIND_PARAM_FOUND) {
+			req_bdiff = atoi(q);
+		}
+		
+		if (req_bdiff) {
+			int sz = snprintf(s, sizeof(s), "{\"id\": null, \"method\": \"mining.suggest_difficulty\", \"params\": [%lu]}", req_bdiff);
+			stratum_send(pool, s, sz);
+		}
+	}
+	
 out:
 	if (val)
 		json_decref(val);
@@ -3340,7 +3356,7 @@ void suspend_stratum(struct pool *pool)
 bool initiate_stratum(struct pool *pool)
 {
 	bool ret = false, recvd = false, noresume = false, sockd = false;
-	bool trysuggest = request_target_str;
+	bool trysuggest = request_target_str && !uri_get_param_bool(pool->rpc_url, "cksuggest", false);
 	char s[RBUFSIZE], *sret = NULL, *nonce1, *sessionid;
 	json_t *val = NULL, *res_val, *err_val;
 	json_error_t err;
@@ -4045,6 +4061,62 @@ void run_cmd(const char *cmd)
 }
 
 
+#if defined(USE_BITMAIN) || defined(USE_ICARUS)
+bool bm1382_freq_to_reg_data(uint8_t * const out_reg_data, float mhz)
+{
+	// We add 1 so fractions don't interfere with near-integer settings
+	++mhz;
+	
+	if (mhz < 100)
+		return false;
+	float best_delta = FLT_MAX;
+	unsigned best_dc = 0;
+	unsigned try_list[4], *tlp = try_list;
+	if (mhz >= 200) {
+		if (mhz >= 403.125) {
+			*(tlp++) = 0x0101;
+			*(tlp++) = 0x0205;
+		} else {
+			*(tlp++) = 0x0202;
+		}
+		*(tlp++) = 0x0406;
+	} else {
+		*(tlp++) = 0x0403;
+	}
+	*(tlp++) = 0x0807;
+	for (unsigned *tli = try_list; tli < tlp; ++tli) {
+		const float d = *tli >> 8;
+		const float df = 25. / d;
+		unsigned n = mhz / df;
+		// NOTE: 0x3f here is 0x3e in the final register
+		if (n > 0x3f) {
+			n = 0x3f;
+		}
+		const float delta = mhz - (n * df);
+		if (delta < best_delta) {
+			best_delta = delta;
+			best_dc = *tli;
+			if (delta == 0) {
+				break;
+			}
+		}
+	}
+	if (!best_dc)
+		return false;
+	const float d = best_dc >> 8;
+	const float df = 25. / d;
+	const unsigned di = best_dc & 0xff;
+	unsigned n = (mhz / df) - 1;
+	if (n > 0x3e) {
+		n = 0x3e;
+	}
+	const uint16_t reg_num = (n << 7) | di;
+	pk_u16be(out_reg_data, 0, reg_num);
+	return true;
+}
+#endif
+
+
 uint8_t crc5usb(unsigned char *ptr, uint8_t len)
 {
     uint8_t i, j, k;

+ 3 - 0
util.h

@@ -830,6 +830,9 @@ extern char *trimmed_strdup(const char *);
 extern void run_cmd(const char *cmd);
 
 
+extern bool bm1382_freq_to_reg_data(uint8_t *out_reg_data, float mhz);
+
+
 extern uint8_t crc5usb(unsigned char *ptr, uint8_t len);
 extern void bfg_init_checksums(void);
 extern uint8_t crc8ccitt(const void *, size_t);