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'
       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"
     - 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'
       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"
     - compiler: ": Only bitforce"
       env: myCC='clang' UBUNTU_DEPS='linux-libc-dev' EXTRA_DEPS='pkg-config libncursesw5-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-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"
     - compiler: ": Only icarus"
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-icarus'
       env: myCC='clang' EXTRA_DEPS='pkg-config libncursesw5-dev' CONFIGURE_ARGS='--disable-other-drivers --enable-icarus'
     - compiler: ": Only dualminer"
     - compiler: ": Only dualminer"

+ 1 - 0
AUTHORS

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

+ 10 - 2
Makefile.am

@@ -92,8 +92,8 @@ TEST_EXTENSIONS = .sh
 
 
 .PHONY: update-version
 .PHONY: update-version
 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
 version.h: update-version
 bfgminer_SOURCES += version.c version.h
 bfgminer_SOURCES += version.c version.h
 BUILT_SOURCES = version.h
 BUILT_SOURCES = version.h
@@ -257,10 +257,18 @@ if HAS_ASIC
 dist_doc_DATA += README.ASIC
 dist_doc_DATA += README.ASIC
 endif
 endif
 
 
+if USE_ALCHEMIST
+bfgminer_SOURCES += driver-alchemist.c
+endif
+
 if USE_BITFORCE
 if USE_BITFORCE
 bfgminer_SOURCES += driver-bitforce.c
 bfgminer_SOURCES += driver-bitforce.c
 endif
 endif
 
 
+if USE_BITMAIN
+bfgminer_SOURCES += driver-bitmain.c driver-bitmain.h
+endif
+
 if USE_BIGPIC
 if USE_BIGPIC
 bfgminer_SOURCES += driver-bigpic.c driver-bigpic.h
 bfgminer_SOURCES += driver-bigpic.c driver-bigpic.h
 endif
 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
 BFGMiner Version 5.3.0 - September 5, 2015
 
 
 - README.ASIC: Compac docs
 - README.ASIC: Compac docs

+ 3 - 0
README

@@ -142,6 +142,7 @@ BFGMiner driver configuration options:
 	--enable-broad-udevrules
 	--enable-broad-udevrules
 	                        Include udev rules for ambiguous devices which may
 	                        Include udev rules for ambiguous devices which may
 	                        not be miners
 	                        not be miners
+	--enable-alchemist      Compile support for AlcheMist (default disabled)
 	--disable-avalon        Compile support for Avalon (default enabled)
 	--disable-avalon        Compile support for Avalon (default enabled)
 	--disable-avalonmm      Compile support for Avalon2/3 (default enabled)
 	--disable-avalonmm      Compile support for Avalon2/3 (default enabled)
 	--enable-bfsb           Compile support for BFSB (default disabled)
 	--enable-bfsb           Compile support for BFSB (default disabled)
@@ -151,6 +152,8 @@ BFGMiner driver configuration options:
 	                        enabled)
 	                        enabled)
 	--disable-bitforce      Compile support for BitForce (default enabled)
 	--disable-bitforce      Compile support for BitForce (default enabled)
 	--disable-bitfury       Compile support for Bitfury (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)
 	--disable-cointerra     Compile support for CoinTerra (default enabled)
 	--enable-cpumining      Compile support for CPU mining (default disabled)
 	--enable-cpumining      Compile support for CPU mining (default disabled)
 	--disable-drillbit      Compile support for DrillBit (default enabled)
 	--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
 Currently supported ASIC devices include Avalon, Bitfountain's Block Erupter
 series (both USB and blades), a large variety of Bitfury-based miners,
 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
 ANTMINER U3
@@ -12,21 +92,16 @@ ANTMINER U3
 The U3 does not support autodetection, so you will want to use --scan-serial to
 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:
 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
 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:
 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
 AVALON 1
@@ -187,9 +262,7 @@ COMPAC
 These USB sticks are based on Bitmain's BM1384 chip, and use the antminer
 These USB sticks are based on Bitmain's BM1384 chip, and use the antminer
 driver. You can set the clock frequency with
 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
 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=X, <- Y or N if ADL is compiled in the code
                               ADL in use=X, <- Y or N if any GPU has ADL
                               ADL in use=X, <- Y or N if any GPU has ADL
                               Strategy=Name, <- the current pool strategy
                               Strategy=Name, <- the current pool strategy
+                              Rotate Period=N, <- rotate strategy period
                               Log Interval=N, <- log interval (--log N)
                               Log Interval=N, <- log interval (--log N)
                               Device Code=GPU ICA , <- spaced list of compiled
                               Device Code=GPU ICA , <- spaced list of compiled
                                                        device drivers
                                                        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
                               queue, scantime, expiry (integer in the range
                                                        0 to 9999)
                                                        0 to 9999)
                               coinbase-sig (string)
                               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] (*)
  pgaset|N,opt[,val] (*)
                none           This is equivalent to PROCSET on the first
                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:
 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)
 API V3.3 (BFGMiner v5.0.0)
 
 
 Modified API command:
 Modified API command:
@@ -544,6 +557,7 @@ Modified API commands:
  'pgadisable' - disable all processors for a numbered full device
  'pgadisable' - disable all processors for a numbered full device
  'pgaidentify' - choose first processor of numbered full device
  'pgaidentify' - choose first processor of numbered full device
  'pgaset' - choose first processor of numbered full device
  'pgaset' - choose first processor of numbered full device
+ 'setconfig' - add 'stratum-port' number
 
 
 Added API commands:
 Added API commands:
  'procs'
  'procs'

+ 27 - 2
api.c

@@ -27,6 +27,7 @@
 #include <sys/types.h>
 #include <sys/types.h>
 
 
 #include <uthash.h>
 #include <uthash.h>
+#include <utlist.h>
 
 
 #include "compat.h"
 #include "compat.h"
 #include "deviceapi.h"
 #include "deviceapi.h"
@@ -311,6 +312,8 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_INVNEG 121
 #define MSG_INVNEG 121
 #define MSG_SETQUOTA 122
 #define MSG_SETQUOTA 122
 
 
+#define MSG_INVSTRATEGY 0x102
+
 #define USE_ALTMSG 0x4000
 #define USE_ALTMSG 0x4000
 
 
 enum code_severity {
 enum code_severity {
@@ -462,6 +465,7 @@ struct CODES {
  { SEVERITY_ERR,   MSG_UNKCON,	PARAM_STR,	"Unknown config '%s'" },
  { 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_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_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_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_CONPAR,	PARAM_NONE,	"Missing config parameters 'name,N'" },
  { SEVERITY_ERR,   MSG_CONVAL,	PARAM_STR,	"Missing config value N for '%s,N'" },
  { SEVERITY_ERR,   MSG_CONVAL,	PARAM_STR,	"Missing config value N for '%s,N'" },
@@ -1282,7 +1286,7 @@ static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __
 	struct api_data *root = NULL;
 	struct api_data *root = NULL;
 	char buf[TMPBUFSIZ];
 	char buf[TMPBUFSIZ];
 	bool io_open;
 	bool io_open;
-	struct driver_registration *reg, *regtmp;
+	struct driver_registration *reg;
 	int pgacount = 0;
 	int pgacount = 0;
 	char *adlinuse = (char *)NO;
 	char *adlinuse = (char *)NO;
 	int i;
 	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_const(root, "ADL", (char *)adl, false);
 	root = api_add_string(root, "ADL in use", adlinuse, false);
 	root = api_add_string(root, "ADL in use", adlinuse, false);
 	root = api_add_const(root, "Strategy", strategies[pool_strategy].s, 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);
 	root = api_add_int(root, "Log Interval", &opt_log_interval, false);
 	
 	
 	strcpy(buf, ""
 	strcpy(buf, ""
@@ -1323,7 +1329,7 @@ static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __
 #endif
 #endif
 	);
 	);
 
 
-	BFG_FOREACH_DRIVER_BY_DNAME(reg, regtmp)
+	BFG_FOREACH_DRIVER_BY_DNAME(reg)
 	{
 	{
 		const struct device_drv * const drv = reg->drv;
 		const struct device_drv * const drv = reg->drv;
 		tailsprintf(buf, sizeof(buf), " %s", drv->name);
 		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);
 		message(io_data, MSG_SETCONFIG, 1, param, isjson);
 		return;
 		return;
 	}
 	}
+	else
 #endif
 #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);
 	value = atoi(comma);
 	if (value < 0 || value > 9999) {
 	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_maj], [5])
-m4_define([v_min], [3])
+m4_define([v_min], [4])
 m4_define([v_mic], [0])
 m4_define([v_mic], [0])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([v_ver], [v_maj.v_min.v_mic])
@@ -553,6 +553,11 @@ else
 	adl="no"
 	adl="no"
 fi
 fi
 
 
+BFG_DRIVER(,AlcheMist,scrypt,no,[
+	need_lowl_vcom=yes
+	has_asic=yes
+])
+
 BFG_DRIVER(,BitForce,SHA256d,auto,[
 BFG_DRIVER(,BitForce,SHA256d,auto,[
 	driverlist="$driverlist bitforce:pci/need_lowl_pci"
 	driverlist="$driverlist bitforce:pci/need_lowl_pci"
 	if test "x$lowl_pci" = "xyes"; then
 	if test "x$lowl_pci" = "xyes"; then
@@ -568,6 +573,11 @@ BFG_DRIVER(,BitForce,SHA256d,auto,[
 	have_udevrules=true
 	have_udevrules=true
 ])
 ])
 
 
+BFG_DRIVER(bitmain,Bitmain Antminer S* series,SHA256d,no,[
+	need_lowl_vcom=yes
+	has_asic=yes
+])
+
 BFG_DRIVER(,Icarus,SHA256d,auto,[
 BFG_DRIVER(,Icarus,SHA256d,auto,[
 	need_dynclock=yes
 	need_dynclock=yes
 	need_lowl_vcom=yes
 	need_lowl_vcom=yes
@@ -575,7 +585,7 @@ BFG_DRIVER(,Icarus,SHA256d,auto,[
 	has_asic=yes
 	has_asic=yes
 	have_udevrules=true
 	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,[
 BFG_DRIVER(,DualMiner,Icarus,auto,[
 	need_gc3355=yes
 	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
 bfgminer (5.3.0-0precise1) precise; urgency=low
 
 
   * compac: Support for the GekkoScience Compac BM1384 USB stick miner
   * compac: Support for the GekkoScience Compac BM1384 USB stick miner

+ 1 - 1
debian/control

@@ -2,7 +2,7 @@ Source: bfgminer
 Priority: optional
 Priority: optional
 Section: misc
 Section: misc
 Maintainer: Luke Dashjr <luke_bfgminer@dashjr.org>
 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
 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
 Package: bfgminer

+ 42 - 9
deviceapi.c

@@ -26,6 +26,8 @@
 #include <time.h>
 #include <time.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
+#include <utlist.h>
+
 #include "compat.h"
 #include "compat.h"
 #include "deviceapi.h"
 #include "deviceapi.h"
 #include "logging.h"
 #include "logging.h"
@@ -41,21 +43,17 @@ struct driver_registration *_bfg_drvreg2;
 
 
 void _bfg_register_driver(const struct device_drv *drv)
 void _bfg_register_driver(const struct device_drv *drv)
 {
 {
-	static struct driver_registration *initlist;
 	struct driver_registration *ndr;
 	struct driver_registration *ndr;
 	
 	
 	if (!drv)
 	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;
 			drv = ndr->drv;
 			if (drv->drv_init)
 			if (drv->drv_init)
 				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;
 		return;
 	}
 	}
 	
 	
@@ -63,7 +61,8 @@ void _bfg_register_driver(const struct device_drv *drv)
 	*ndr = (struct driver_registration){
 	*ndr = (struct driver_registration){
 		.drv = drv,
 		.drv = drv,
 	};
 	};
-	LL_PREPEND(initlist, ndr);
+	LL_PREPEND2(_bfg_drvreg1, ndr, next_dname);
+	LL_PREPEND2(_bfg_drvreg2, ndr, next_prio);
 }
 }
 
 
 static
 static
@@ -81,8 +80,17 @@ int sort_drv_by_priority(struct driver_registration * const a, struct driver_reg
 void bfg_devapi_init()
 void bfg_devapi_init()
 {
 {
 	_bfg_register_driver(NULL);
 	_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;
 	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
 #ifdef NEED_BFG_LOWL_VCOM
 bool _serial_detect_all(struct lowlevel_device_info * const info, void * const userp)
 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 <stdint.h>
 #include <sys/time.h>
 #include <sys/time.h>
 
 
-#include <uthash.h>
+#include <utlist.h>
 
 
 #include "miner.h"
 #include "miner.h"
 
 
@@ -13,8 +13,8 @@ struct driver_registration;
 struct driver_registration {
 struct driver_registration {
 	const struct device_drv *drv;
 	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
 	struct driver_registration *next;  // DO NOT USE
 };
 };
 
 
@@ -22,14 +22,10 @@ extern struct driver_registration *_bfg_drvreg1;
 extern struct driver_registration *_bfg_drvreg2;
 extern struct driver_registration *_bfg_drvreg2;
 extern void bfg_devapi_init();
 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 *);
 extern void _bfg_register_driver(const struct device_drv *);
 #define BFG_REGISTER_DRIVER(drv)                \
 #define BFG_REGISTER_DRIVER(drv)                \
@@ -95,6 +91,9 @@ struct bfg_set_device_definition {
 	const char *description;
 	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);
 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 bool(*detectone_func_t)(const char*);
 typedef int(*autoscan_func_t)();
 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"},
 	{"diff", aan_set_diff, "desired nonce difficulty"},
 	{NULL},
 	{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 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
 #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
 static
 const struct bfg_set_device_definition antminer_set_device_funcs[];
 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
 static
 bool antminer_detect_one_with_drv(const char * const devpath, struct device_drv * const drv)
 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,
 		.do_icarus_timing = true,
 		.read_size = 5,
 		.read_size = 5,
 		.reopen_mode = IRM_NEVER,
 		.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);
 	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
 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)
 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)
 	if (!setting || !*setting)
 		return "missing clock 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;
 		return replybuf;
 	}
 	}
 	
 	
@@ -234,6 +261,16 @@ invalid_voltage:
 	return NULL;
 	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
 static
 void antminer_flash_led(const struct cgpu_info *antminer)
 void antminer_flash_led(const struct cgpu_info *antminer)
 {
 {
@@ -265,6 +302,7 @@ bool antminer_identify(struct cgpu_info *antminer)
 
 
 static
 static
 const struct bfg_set_device_definition antminer_set_device_funcs[] = {
 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"},
 	{"baud"         , icarus_set_baud         , "serial baud rate"},
 	{"work_division", icarus_set_work_division, "number of pieces work is split into"},
 	{"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)"},
 	{"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},
 	{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
 static
 bool compac_lowl_match(const struct lowlevel_device_info * const info)
 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_match = antminer_lowl_match;
 	antminer_drv.lowl_probe = antminer_lowl_probe;
 	antminer_drv.lowl_probe = antminer_lowl_probe;
 	antminer_drv.identify_device = antminer_identify;
 	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;
 	++antminer_drv.probe_priority;
 	
 	
 	compac_drv = antminer_drv;
 	compac_drv = antminer_drv;
+	compac_drv.dname = "compac";
 	compac_drv.name = "CBM";
 	compac_drv.name = "CBM";
 	compac_drv.lowl_match = compac_lowl_match;
 	compac_drv.lowl_match = compac_lowl_match;
 	compac_drv.lowl_probe = compac_lowl_probe;
 	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},
 	{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 */
 /* Non blocking clearing of anything in the buffer */
 static void avalon_clear_readbuf(int fd)
 static void avalon_clear_readbuf(int fd)
 {
 {
@@ -1006,4 +1042,10 @@ struct device_drv avalon_drv = {
 	.get_api_stats = avalon_api_stats,
 	.get_api_stats = avalon_api_stats,
 	.reinit_device = avalon_init,
 	.reinit_device = avalon_init,
 	.thread_shutdown = avalon_shutdown,
 	.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 ");
 	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
 static
 const char *avalonmm_tui_handle_choice(struct cgpu_info * const proc, const int input)
 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 <ctype.h>
 #include <limits.h>
 #include <limits.h>
+#include <math.h>
 #include <pthread.h>
 #include <pthread.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
@@ -1810,6 +1811,35 @@ static bool bitforce_thread_init(struct thr_info *thr)
 	return true;
 	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
 #ifdef HAVE_CURSES
 static
 static
 void bitforce_tui_wlogprint_choices(struct cgpu_info *cgpu)
 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;
 	struct bitforce_data *data = cgpu->device_data;
 	if (data->supports_fanspeed)
 	if (data->supports_fanspeed)
 		wlogprint("[F]an control ");
 		wlogprint("[F]an control ");
+	wlogprint("[V]oltage ");
 }
 }
 
 
 static
 static
@@ -1851,6 +1882,8 @@ const char *bitforce_tui_handle_choice(struct cgpu_info *cgpu, int input)
 			mutex_unlock(mutexp);
 			mutex_unlock(mutexp);
 			return replybuf;
 			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;
 	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[] = {
 static const struct bfg_set_device_definition bitforce_set_device_funcs[] = {
 	{"fanmode", bitforce_set_fanmode, "range 0-5 (low to fast) or 9 (auto)"},
 	{"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},
 	{"_cmd1", bitforce_rpc_send_cmd1, NULL},
 	{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
 #endif
 
 
 struct device_drv hashfast_ums_drv = {
 struct device_drv hashfast_ums_drv = {
@@ -865,5 +886,7 @@ struct device_drv hashfast_ums_drv = {
 	
 	
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 	.proc_wlogprint_status = hashfast_wlogprint_status,
 	.proc_wlogprint_status = hashfast_wlogprint_status,
+	.proc_tui_wlogprint_choices = hashfast_tui_wlogprint_choices,
+	.proc_tui_handle_choice = hashfast_tui_handle_choice,
 #endif
 #endif
 };
 };

+ 1 - 0
driver-icarus.h

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

+ 6 - 0
driver-jingtian.c

@@ -245,4 +245,10 @@ struct device_drv jingtian_drv = {
 	.poll = aan_poll,
 	.poll = aan_poll,
 	
 	
 	.get_api_extra_device_status = aan_api_device_status,
 	.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.fRtsControl = RTS_CONTROL_ENABLE;
 	comCfg.dcb.ByteSize = 8;
 	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)
 	// Code must specify a valid timeout value (0 means don't timeout)
 	const DWORD ctoms = ((DWORD)timeout * 100);
 	const DWORD ctoms = ((DWORD)timeout * 100);
 	COMMTIMEOUTS cto = {ctoms, 0, ctoms, 0, ctoms};
 	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) {
 	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);
 	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;
 	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
 #ifdef TERMIOS_DEBUG
 	termios_debug(devpath, &my_termios, "before");
 	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");
 	termios_debug(devpath, &my_termios, "settings");
 #endif
 #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
 #ifdef TERMIOS_DEBUG
 	tcgetattr(fdDev, &my_termios);
 	tcgetattr(fdDev, &my_termios);
 	termios_debug(devpath, &my_termios, "after");
 	termios_debug(devpath, &my_termios, "after");
 #endif
 #endif
 
 
+	}
+
 	if (purge)
 	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;
 	return fdDev;
 #endif
 #endif
 }
 }

+ 1 - 1
m4/bundled_lib.m4

@@ -50,7 +50,7 @@ AC_DEFUN([BFG_BUNDLED_LIB_VARS],[
 	BFG_CHECK_LD_ORIGIN
 	BFG_CHECK_LD_ORIGIN
 	_AC_SRCDIRS(["$ac_dir"])
 	_AC_SRCDIRS(["$ac_dir"])
 	$1_CFLAGS='-I'"${ac_abs_top_srcdir}"'/$2'
 	$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_SUBDIRS=$2
 	$1_EXTRADEPS=$1_directory
 	$1_EXTRADEPS=$1_directory
 	BUNDLED_LIB_RULES="$BUNDLED_LIB_RULES
 	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)
 void pool_set_uri(struct pool * const pool, char * const uri)
 {
 {
 	pool->rpc_url = 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 */
 /* 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);
 			applog(LOG_WARNING, "Error %cetting coinbase address from pool %d: %s", 'g', pool->pool_no, estrc);
 			free(estr);
 			free(estr);
+			json_decref(json);
 			continue;
 			continue;
 		}
 		}
 		s = bfg_json_obj_string(json, "result", NULL);
 		s = bfg_json_obj_string(json, "result", NULL);
 		if (unlikely(!s))
 		if (unlikely(!s))
 		{
 		{
 			applog(LOG_WARNING, "Error %cetting coinbase address from pool %d: %s", 'g', pool->pool_no, "(return value was not a String)");
 			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;
 			continue;
 		}
 		}
 		s2 = set_b58addr(s, &newscript);
 		s2 = set_b58addr(s, &newscript);
 		if (unlikely(s2))
 		if (unlikely(s2))
 		{
 		{
 			applog(LOG_WARNING, "Error %cetting coinbase address from pool %d: %s", 's', pool->pool_no, s2);
 			applog(LOG_WARNING, "Error %cetting coinbase address from pool %d: %s", 's', pool->pool_no, s2);
+			json_decref(json);
 			continue;
 			continue;
 		}
 		}
 		if (goal->generation_script)
 		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))
 			if (bytes_eq(&newscript, goal->generation_script))
 			{
 			{
 				applog(LOG_DEBUG, "Pool %d returned coinbase address already in use (%s)", pool->pool_no, s);
 				applog(LOG_DEBUG, "Pool %d returned coinbase address already in use (%s)", pool->pool_no, s);
+				json_decref(json);
 				break;
 				break;
 			}
 			}
 		}
 		}
@@ -3414,6 +3431,7 @@ void refresh_bitcoind_address(struct mining_goal_info * const goal, const bool f
 		bytes_assimilate(goal->generation_script, &newscript);
 		bytes_assimilate(goal->generation_script, &newscript);
 		coinbase_script_block_id = blkchain->currentblk->block_id;
 		coinbase_script_block_id = blkchain->currentblk->block_id;
 		applog(LOG_NOTICE, "Now using coinbase address %s, provided by pool %d", s, pool->pool_no);
 		applog(LOG_NOTICE, "Now using coinbase address %s, provided by pool %d", s, pool->pool_no);
+		json_decref(json);
 		break;
 		break;
 	}
 	}
 	
 	
@@ -5259,6 +5277,16 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work,
 		char reason[32];
 		char reason[32];
 		put_in_parens(reason, sizeof(reason), extract_reject_reason(val, res, err, work));
 		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);
 		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 {
 	} else {
 		mutex_lock(&stats_lock);
 		mutex_lock(&stats_lock);
 		cgpu->rejected++;
 		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
 #ifdef HAVE_CURSES
 static
 static
 void loginput_mode(const int size)
 void loginput_mode(const int size)
@@ -8200,25 +8277,25 @@ retry:
 	} else if (!strncasecmp(&input, "c", 1)) {
 	} else if (!strncasecmp(&input, "c", 1)) {
 		for (i = 0; i <= TOP_STRATEGY; i++)
 		for (i = 0; i <= TOP_STRATEGY; i++)
 			wlogprint("%d: %s\n", i, strategies[i].s);
 			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) {
 		if (selected < 0 || selected > TOP_STRATEGY) {
 			wlogprint("Invalid selection\n");
 			wlogprint("Invalid selection\n");
 			goto retry;
 			goto retry;
 		}
 		}
+		char *param = NULL;
 		if (selected == POOL_ROTATE) {
 		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;
 		goto updated;
 	} else if (!strncasecmp(&input, "i", 1)) {
 	} else if (!strncasecmp(&input, "i", 1)) {
 		selected = curses_int("Select pool number");
 		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;
 		bool high_hash = true;
 		struct pool * const pool = work->pool;
 		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
 			// 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)))
 			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",
 				applog(LOG_DEBUG, "Stratum pool %u target has changed since work job issued, checking that too",
 				       pool->pool_no);
 				       pool->pool_no);
 				if (hash_target_check_v(work->hash, pool->next_target))
 				if (hash_target_check_v(work->hash, pool->next_target))
+				{
 					high_hash = false;
 					high_hash = false;
+					work->work_difficulty = target_diff(pool->next_target);
+				}
 			}
 			}
 		}
 		}
 		if (high_hash)
 		if (high_hash)
@@ -12370,8 +12450,8 @@ rescan:
 		pthread_join(info->probe_pth, NULL);
 		pthread_join(info->probe_pth, NULL);
 #endif
 #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;
 		const struct device_drv * const drv = reg->drv;
 		if (!(drv_algo_check(drv) && drv->drv_detect))
 		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;
 	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
 static
 bool _probe_device_do_probe(const struct device_drv * const drv, const struct lowlevel_device_info * const info, bool * const request_rescan_p)
 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)
 	// if lowlevel device matches specific user assignment, probe requested driver(s)
 	struct string_elist *sd_iter, *sd_tmp;
 	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)
 	DL_FOREACH_SAFE(scan_devices, sd_iter, sd_tmp)
 	{
 	{
 		const char * const dname = sd_iter->string;
 		const char * const dname = sd_iter->string;
@@ -12620,17 +12675,26 @@ void *probe_device_thread(void *p)
 		{
 		{
 			if (!_probe_device_match(info, ser))
 			if (!_probe_device_match(info, ser))
 				continue;
 				continue;
+			
 			const size_t dnamelen = (colon - dname);
 			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
 	// 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;
 		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]))
 			if (strcasecmp("noauto", &colon[1]) && strcasecmp("auto", &colon[1]))
 				continue;
 				continue;
 			const ssize_t dnamelen = (colon - dname);
 			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');
 			doauto = (tolower(colon[1]) == 'a');
 			if (dnamelen != -1)
 			if (dnamelen != -1)
 				break;
 				break;
@@ -12704,7 +12774,7 @@ void *probe_device_thread(void *p)
 					_probe_device_match(info, (dname[0] == '@') ? &dname[1] : dname))
 					_probe_device_match(info, (dname[0] == '@') ? &dname[1] : dname))
 				{
 				{
 					bool dont_rescan = false;
 					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;
 						const struct device_drv * const drv = dreg->drv;
 						if (!drv_algo_check(drv))
 						if (!drv_algo_check(drv))
@@ -12728,15 +12798,23 @@ void *probe_device_thread(void *p)
 		if (strcasecmp(&colon[1], "all"))
 		if (strcasecmp(&colon[1], "all"))
 			continue;
 			continue;
 		const size_t dnamelen = (colon - dname);
 		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;
 				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 bool opt_dev_protocol;
 extern char *opt_coinbase_sig;
 extern char *opt_coinbase_sig;
 extern char *request_target_str;
 extern char *request_target_str;
+extern float request_pdiff;
+extern double request_bdiff;
 extern int opt_skip_checks;
 extern int opt_skip_checks;
 extern char *opt_kernel_path;
 extern char *opt_kernel_path;
 extern char *opt_socks_proxy;
 extern char *opt_socks_proxy;
@@ -1115,6 +1117,8 @@ extern void adjust_quota_gcd(void);
 extern struct pool *add_pool2(struct mining_goal_info *);
 extern struct pool *add_pool2(struct mining_goal_info *);
 #define add_pool()  add_pool2(get_mining_goal("default"))
 #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 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_GPUDEVICES 16
 #define MAX_DEVICES 4096
 #define MAX_DEVICES 4096
@@ -1361,6 +1365,7 @@ struct pool {
 	char work_restart_timestamp[11];
 	char work_restart_timestamp[11];
 	uint32_t	block_id;
 	uint32_t	block_id;
 	struct mining_goal_info *goal;
 	struct mining_goal_info *goal;
+	enum bfg_tristate pool_diff_effective_retroactively;
 
 
 	enum pool_protocol proto;
 	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_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_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_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__ */
 #endif /* __MINER_H__ */

+ 1 - 1
openwrt/bfgminer/Makefile

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

+ 73 - 1
util.c

@@ -15,6 +15,7 @@
 
 
 #include "config.h"
 #include "config.h"
 
 
+#include <float.h>
 #include <math.h>
 #include <math.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.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);
 	applog(LOG_INFO, "Stratum authorisation success for pool %d", pool->pool_no);
 	pool->probed = true;
 	pool->probed = true;
 	successful_connect = 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:
 out:
 	if (val)
 	if (val)
 		json_decref(val);
 		json_decref(val);
@@ -3340,7 +3356,7 @@ void suspend_stratum(struct pool *pool)
 bool initiate_stratum(struct pool *pool)
 bool initiate_stratum(struct pool *pool)
 {
 {
 	bool ret = false, recvd = false, noresume = false, sockd = false;
 	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;
 	char s[RBUFSIZE], *sret = NULL, *nonce1, *sessionid;
 	json_t *val = NULL, *res_val, *err_val;
 	json_t *val = NULL, *res_val, *err_val;
 	json_error_t err;
 	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 crc5usb(unsigned char *ptr, uint8_t len)
 {
 {
     uint8_t i, j, k;
     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 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 uint8_t crc5usb(unsigned char *ptr, uint8_t len);
 extern void bfg_init_checksums(void);
 extern void bfg_init_checksums(void);
 extern uint8_t crc8ccitt(const void *, size_t);
 extern uint8_t crc8ccitt(const void *, size_t);