Browse Source

Merge branch 'bfgminer' into cointerra_fresh

Conflicts:
	deviceapi.h
	miner.h
Luke Dashjr 11 years ago
parent
commit
78909786bb
100 changed files with 9645 additions and 1766 deletions
  1. 2 0
      .gitignore
  2. 3 0
      .gitmodules
  3. 31 1
      70-bfgminer.rules.in
  4. 74 42
      AUTHORS
  5. 45 24
      Makefile.am
  6. 1015 0
      NEWS
  7. 44 8
      README
  8. 109 17
      README.ASIC
  9. 6 5
      README.FPGA
  10. 14 2
      README.RPC
  11. 10 2
      README.scrypt
  12. 1 1
      adl.c
  13. 2 2
      api-example.c
  14. 38 0
      api-example.rb
  15. 74 40
      api.c
  16. 6 1
      autogen.sh
  17. 0 108
      bitforce-firmware-flash.c
  18. 1 1
      ccan-upstream
  19. 137 45
      configure.ac
  20. 92 0
      debian/changelog
  21. 1 1
      debian/control
  22. 26 1
      deviceapi.c
  23. 6 0
      deviceapi.h
  24. 641 0
      driver-aan.c
  25. 50 0
      driver-aan.h
  26. 2 2
      driver-antminer.c
  27. 16 3
      driver-avalon.c
  28. 1 0
      driver-avalon.h
  29. 952 0
      driver-avalonmm.c
  30. 1 0
      driver-bfx.c
  31. 91 55
      driver-bifury.c
  32. 457 109
      driver-bitforce.c
  33. 45 27
      driver-bitfury.c
  34. 1 1
      driver-cairnsmore.c
  35. 3 3
      driver-cpu.c
  36. 7 7
      driver-drillbit.c
  37. 15 7
      driver-dualminer.c
  38. 34 22
      driver-getwork.c
  39. 268 248
      driver-gridseed.c
  40. 8 2
      driver-hashbuster.c
  41. 2 0
      driver-hashbusteravalon.c
  42. 7 1
      driver-hashbusterusb.c
  43. 182 6
      driver-hashfast.c
  44. 196 157
      driver-icarus.c
  45. 23 3
      driver-icarus.h
  46. 248 0
      driver-jingtian.c
  47. 17 1
      driver-klondike.c
  48. 8 33
      driver-knc.c
  49. 8 59
      driver-littlefury.c
  50. 483 0
      driver-minergate.c
  51. 56 22
      driver-nanofury.c
  52. 9 7
      driver-opencl.c
  53. 28 1
      driver-proxy.c
  54. 15 0
      driver-proxy.h
  55. 589 0
      driver-rockminer.c
  56. 124 14
      driver-stratum.c
  57. 1 1
      driver-twinfury.c
  58. 3 1
      driver-x6500.c
  59. 355 0
      driver-zeusminer.c
  60. 2 1
      driver-ztex.c
  61. 97 213
      gc3355.c
  62. 11 15
      gc3355.h
  63. 24 0
      gen-version.sh
  64. 1 1
      hexdump.c
  65. 2 1
      httpsrv.c
  66. 1 1
      jtag.c
  67. 1 0
      libbase58
  68. 64 48
      libbitfury.c
  69. 12 12
      libbitfury.h
  70. 1 1
      libblkmaker
  71. 7 3
      logging.c
  72. 25 3
      logging.h
  73. 1 0
      lowl-ftdi.c
  74. 92 0
      lowl-mswin.c
  75. 12 0
      lowl-mswin.h
  76. 12 7
      lowl-pci.c
  77. 70 14
      lowl-spi.c
  78. 11 0
      lowl-spi.h
  79. 1 1
      lowl-usb.c
  80. 138 1
      lowl-vcom.c
  81. 1 0
      lowl-vcom.h
  82. 13 1
      lowlevel.c
  83. 5 0
      lowlevel.h
  84. 98 0
      m4/bundled_lib.m4
  85. 34 0
      m4/custom_subdirs.m4
  86. 95 35
      make-release
  87. 371 132
      miner.c
  88. 80 9
      miner.h
  89. 32 21
      ocl.c
  90. 1 1
      opencl/poclbm.cl
  91. 795 0
      opencl/psw.cl
  92. 5 2
      opencl/scrypt.cl
  93. 832 0
      opencl/zuikkis.cl
  94. 14 22
      openwrt/bfgminer/Makefile
  95. 1 1
      openwrt/multibuild.sh
  96. 0 11
      packaging/suse/Makefile.am.patch
  97. 0 11
      packaging/suse/Makefile.in.patch
  98. 0 9
      packaging/suse/bfgminer.changes
  99. 0 6
      packaging/suse/bfgminer.rpmlintrc
  100. 0 90
      packaging/suse/bfgminer.spec

+ 2 - 0
.gitignore

@@ -51,6 +51,8 @@ lib/string.h
 lib/stdint.h
 lib/stdint.h
 lib/warn-on-use.h
 lib/warn-on-use.h
 iospeeds_local.h
 iospeeds_local.h
+version.h
+version.h.new
 
 
 mkinstalldirs
 mkinstalldirs
 
 

+ 3 - 0
.gitmodules

@@ -4,3 +4,6 @@
 [submodule "ccan"]
 [submodule "ccan"]
 	path = ccan-upstream
 	path = ccan-upstream
 	url = git://git.ozlabs.org/~ccan/ccan
 	url = git://git.ozlabs.org/~ccan/ccan
+[submodule "libbase58"]
+	path = libbase58
+	url = https://github.com/luke-jr/libbase58.git

+ 31 - 1
70-bfgminer.rules.in

@@ -14,20 +14,50 @@ LABEL="bfgminer_start"
 @USE_HASHBUSTER_TRUE@ENV{ID_MODEL}=="*HashBuster*", GOTO="bfgminer_add"
 @USE_HASHBUSTER_TRUE@ENV{ID_MODEL}=="*HashBuster*", GOTO="bfgminer_add"
 @USE_HASHBUSTERUSB_TRUE@ENV{ID_MODEL}=="*HashBuster*", GOTO="bfgminer_add"
 @USE_HASHBUSTERUSB_TRUE@ENV{ID_MODEL}=="*HashBuster*", GOTO="bfgminer_add"
 @USE_HASHFAST_TRUE@ENV{idVendor}=="297c", ENV{manufacturer}=="*HashFast*", GOTO="bfgminer_add"
 @USE_HASHFAST_TRUE@ENV{idVendor}=="297c", ENV{manufacturer}=="*HashFast*", GOTO="bfgminer_add"
+@USE_HASHFAST_TRUE@ENV{ID_MODEL}=="*GoldenNonce*", GOTO="bfgminer_add"
 @HAS_KLONDIKE_TRUE@ENV{idVendor}=="04d8", ENV{idProduct}=="f60a", ENV{manufacturer}=="*Klondike*", GOTO="bfgminer_add"
 @HAS_KLONDIKE_TRUE@ENV{idVendor}=="04d8", ENV{idProduct}=="f60a", ENV{manufacturer}=="*Klondike*", GOTO="bfgminer_add"
 @HAS_KLONDIKE_TRUE@ENV{idVendor}=="fa05", ENV{idProduct}=="0001", ENV{manufacturer}=="*HashBuster*", GOTO="bfgminer_add"
 @HAS_KLONDIKE_TRUE@ENV{idVendor}=="fa05", ENV{idProduct}=="0001", ENV{manufacturer}=="*HashBuster*", GOTO="bfgminer_add"
 @HAS_LITTLEFURY_TRUE@ENV{ID_MODEL}=="*LittleFury*", GOTO="bfgminer_add"
 @HAS_LITTLEFURY_TRUE@ENV{ID_MODEL}=="*LittleFury*", GOTO="bfgminer_add"
 @HAS_MODMINER_TRUE@ENV{ID_MODEL}=="*ModMiner*", GOTO="bfgminer_add"
 @HAS_MODMINER_TRUE@ENV{ID_MODEL}=="*ModMiner*", GOTO="bfgminer_add"
 @HAS_NANOFURY_TRUE@ENV{idVendor}=="04d8", ENV{idProduct}=="00de", ENV{ID_MODEL}=="*NanoFury*", GOTO="bfgminer_add"
 @HAS_NANOFURY_TRUE@ENV{idVendor}=="04d8", ENV{idProduct}=="00de", ENV{ID_MODEL}=="*NanoFury*", GOTO="bfgminer_add"
+@USE_ROCKMINER_TRUE@ENV{ID_MODEL}=="*R-BOX miner*", GOTO="bfgminer_add"
+@USE_ROCKMINER_TRUE@ENV{ID_MODEL}=="*RX-BOX miner*", GOTO="bfgminer_add"
 @HAS_TWINFURY_TRUE@ENV{ID_MODEL}=="*Twinfury*", GOTO="bfgminer_add"
 @HAS_TWINFURY_TRUE@ENV{ID_MODEL}=="*Twinfury*", GOTO="bfgminer_add"
 @HAS_X6500_TRUE@ENV{idVendor}=="0403", ENV{idProduct}=="6001", ENV{ID_MODEL}=="*X6500 FPGA Miner*", GOTO="bfgminer_add"
 @HAS_X6500_TRUE@ENV{idVendor}=="0403", ENV{idProduct}=="6001", ENV{ID_MODEL}=="*X6500 FPGA Miner*", GOTO="bfgminer_add"
 @HAS_ZTEX_TRUE@ENV{ID_MODEL}=="*btcminer for ZTEX*", GOTO="bfgminer_add"
 @HAS_ZTEX_TRUE@ENV{ID_MODEL}=="*btcminer for ZTEX*", GOTO="bfgminer_add"
 
 
+# The below are broad udev rules that may match devices other than the miners expected.
+# You can uncomment them with the --enable-broad-udevrules configure option.
+
+# Avalon1
+@BROAD_UDEVRULES_TRUE@@HAS_AVALON_TRUE@ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", GOTO="bfgminer_add"
+# AvalonMM
+@BROAD_UDEVRULES_TRUE@@USE_AVALONMM_TRUE@ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", GOTO="bfgminer_add"
+# DualMiner
+@BROAD_UDEVRULES_TRUE@@USE_DUALMINER_TRUE@ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6010", GOTO="bfgminer_add"
+# GridSeed
+@BROAD_UDEVRULES_TRUE@@USE_GRIDSEED_TRUE@ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", GOTO="bfgminer_add"
+# Icarus
+@BROAD_UDEVRULES_TRUE@@HAS_ICARUS_TRUE@ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", GOTO="bfgminer_add"
+# Cairnsmore1
+@BROAD_UDEVRULES_TRUE@@HAS_ICARUS_TRUE@ATTRS{idVendor}=="067b", ATTRS{idProduct}=="0230", GOTO="bfgminer_add"
+@BROAD_UDEVRULES_TRUE@@HAS_ICARUS_TRUE@ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8350", GOTO="bfgminer_add"
+# Block Erupter and Antminer U*
+@BROAD_UDEVRULES_TRUE@@HAS_ICARUS_TRUE@ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", GOTO="bfgminer_add"
+# ZeusMiner
+@BROAD_UDEVRULES_TRUE@@USE_ZEUSMINER_TRUE@ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", GOTO="bfgminer_add"
+# Possibly unprogrammed ZTEX
+@BROAD_UDEVRULES_TRUE@@HAS_ZTEX_TRUE@ATTRS{idVendor}=="221a", ATTRS{idProduct}=="0100", GOTO="bfgminer_add"
+# BFx2
+@BROAD_UDEVRULES_TRUE@@USE_BFX_TRUE@ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6014", GOTO="bfgminer_add"
+# RockMiner
+@BROAD_UDEVRULES_TRUE@@USE_ROCKMINER_TRUE@ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", GOTO="bfgminer_add"
+
 GOTO="bfgminer_end"
 GOTO="bfgminer_end"
 
 
 LABEL="bfgminer_add"
 LABEL="bfgminer_add"
 
 
-GROUP="video"
+@USE_UDEVRULES_GROUP_TRUE@GROUP="@UDEVRULES_GROUP@"
 ENV{ID_MM_DEVICE_IGNORE}="1"
 ENV{ID_MM_DEVICE_IGNORE}="1"
 
 
 LABEL="bfgminer_end"
 LABEL="bfgminer_end"

+ 74 - 42
AUTHORS

@@ -1,53 +1,85 @@
-FPGA/ASIC mining and refactor: Luke Dashjr <luke-jr+bfgminer@utopios.org> 1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh
-GPU mining and refactor: Con Kolivas <kernel@kolivas.org> 15qSxP1SQcUX3o4nhkfdbgyoWEFMomJ4rZ
-AntMiner driver: Nate Woolls <nwoolls@gmail.com> and Lingchao Xu <lingchao.xu@bitmaintech.com>
-DualMiner driver: Nate Woolls <nwoolls@gmail.com> and Dualminer Team <dualminer@broadeng.net>
-GridSeed driver: Nate Woolls <nwoolls@gmail.com> and GridSeed Team <develop@gridseed.com>
-Bitfury GPIO-based drivers: Bitfury and Anatoly Legkodymov <legko777@fastmail.fm>
-Big Picture Mining and TwinFury drivers: Andreas Auer <aauer1@gmail.com>
-Avalon and Icarus drivers: Xiangfu <xiangfu@openmobilefree.net>
-ZTEX FPGA driver: Nelisky <nelisky.btc@gmail.com>
-Original CPU mining software: Jeff Garzik <jgarzik@pobox.com>
-RPC API: Andrew Smith <kan0i@kano-kun.net> 1Jjk2LmktEQKnv8r2cZ9MvLiZwZ9gxabKm
-
-SUSE packaging: Christian Berendt <berendt@b1-systems.de>
-Ubuntu packaging: Graeme Humphries <graeme@sudo.ca>
-
-Contributors:
+CURRENT MAINTAINERS:
 
 
-Jason Hughes <wizkid057@gmail.com>
-Ycros <michael@kedzierski.id.au>
-Denis Ahrens <denis@h3q.com>
+Luke Dashjr <luke-jr+bfgminer@utopios.org> 1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh
+Nate Woolls <nwoolls@gmail.com> 1JnZoFeCVYJgaKbKwDUxSkTZWWpBmwWTgV
+
+Debian packaging: Dmitry Smirnov <onlyjob@member.fsf.org>
+
+---
+
+PAST MAINTAINERS:
+
+Anatoly Legkodymov <legko777@fastmail.fm>
+Andreas Auer <aauer1@gmail.com>
+Andrew Smith <kan0i@kano-kun.net> 1Jjk2LmktEQKnv8r2cZ9MvLiZwZ9gxabKm
+Con Kolivas <kernel@kolivas.org> 15qSxP1SQcUX3o4nhkfdbgyoWEFMomJ4rZ
+Jeff Garzik <jgarzik@pobox.com>
+Nelisky <nelisky.btc@gmail.com>
+Xiangfu <xiangfu@openmobilefree.net>
+
+---
+
+CONTRIBUTORS:
+
+Abracadabra <hocuscapocus@gmail.com>
+anajavi
+Andrew McDonald <andrew@mcdonald.org.uk>
+Ang Iongchun <angiongchun@gmail.com>
+ArtForz
+Bitfury
 blinkier <blinkiest@gmail.com>
 blinkier <blinkiest@gmail.com>
-Peter Stuge <peter@stuge.se>
-Paul Sheppard <shepsoft@gmail.com>
-Vladimir Strinski <vstrinski@nanofury.com>
+bluemurder <bluemurder@engineer.com>
+capa66 <capa66@x204.com>
+Christian Berendt <berendt@b1-systems.de>
+Colin Percival
+Daniel Mack <daniel@caiaq.de>
+Denis Ahrens <denis@h3q.com>
+Dmitriy Korniychuk <dmitriy@korniychuk.org.ua>
 Dmitry Sorokin <asfins@gmail.com>
 Dmitry Sorokin <asfins@gmail.com>
+Dualminer Team <dualminer@broadeng.net>
+fleger <florian6.leger@laposte.net>
+Glenn Francis Murray <glenn@gfm.cc>
+gluk <glukolog@mail.ru>
+Graeme Humphries <graeme@sudo.ca>
+GridSeed Team <develop@gridseed.com>
+HashBuster team <contact@hashbuster.com>
+Huang Le <4tarhl@gmail.com>
+Isidoro Ghezzi <isidoro.ghezzi@icloud.com>
+James Hilliard <james.hilliard1@gmail.com>
+James Morris <jmorris@intercode.com.au>
+Jason Hughes <wizkid057@gmail.com>
 Jason Snell <abysss@gmail.com>
 Jason Snell <abysss@gmail.com>
+Jean-Luc Cooke <jlcooke@certainkey.com>
+Jonathan Lynch <jonathan.lynch@intel.com>
+Josh Lehan <krellan@krellan.net>
+Lingchao Xu <lingchao.xu@bitmaintech.com>
 Mark Crichton <crichton@gmail.com>
 Mark Crichton <crichton@gmail.com>
-Zefir Kurtisi <zefir.kurtisi@gmail.com>
-HashBuster team <contact@hashbuster.com>
-bluemurder <bluemurder@engineer.com>
-Philip Kaufmann <phil.kaufmann@t-online.de>
-Rusty Russell <rusty@rustcorp.com.au>
-Znort 987 <znort987@yahoo.com>
-Phateus <Jesse.Moll@gmail.com>
 Martin Danielsen <kalroth@gmail.com>
 Martin Danielsen <kalroth@gmail.com>
+Michael Kedzierski <michael@kedzierski.id.au>
+Mr O <notanatheist@gmail.com>
+mtrlt
+Neil Kettle <neil@digit-labs.org>
+Nico Oelgart <nico@nicoswd.com>
 Olivier Gay <olivier.gay@a3.epfl.ch>
 Olivier Gay <olivier.gay@a3.epfl.ch>
-Glenn Francis Murray <glenn@gfm.cc>
-fleger <florian6.leger@laposte.net>
-pooler <pooler@litecoinpool.org>
-Ricardo Iván Vieitez Parra <cop3504@memoryplate.com>
-gluk <glukolog@mail.ru>
+Paul Sheppard <shepsoft@gmail.com>
 Paul Wouters <pwouters@redhat.com>
 Paul Wouters <pwouters@redhat.com>
-Abracadabra <hocuscapocus@gmail.com>
-Josh Lehan <krellan@krellan.net>
+Pavel Semjanov <pavel@semjanov.com>
+Peter Stuge <peter@stuge.se>
+Phateus <Jesse.Moll@gmail.com>
+Philip Kaufmann <phil.kaufmann@t-online.de>
 pontus <liquidpontus@yahoo.se>
 pontus <liquidpontus@yahoo.se>
-Nico Oelgart <nico@nicoswd.com>
-Tydus <Tydus@Tydus.org>
+pooler <pooler@litecoinpool.org>
 Raulo <p987341@gmail.com>
 Raulo <p987341@gmail.com>
-Thorsten Gilling <tgilling@web.de>
-Isidoro Ghezzi <isidoro.ghezzi@icloud.com>
-capa66 <capa66@x204.com>
 Red_Wolf_2 <redwolf@wolfnexus.net>
 Red_Wolf_2 <redwolf@wolfnexus.net>
-Mr O <notanatheist@gmail.com>
+Ricardo Iván Vieitez Parra <cop3504@memoryplate.com>
+Rusty Russell <rusty@rustcorp.com.au>
+slax0r <frcole@gmail.com>
+Teemu Suikki <zuikkis@gmail.com>
+Thorsten Gilling <tgilling@web.de>
+Tydus <Tydus@Tydus.org>
+Ufasoft <support@ufasoft.com>
+Vitalii Demianets <vitalii@orsoc.se>
+Vladimir Strinski <vstrinski@nanofury.com>
+Zefir Kurtisi <zefir.kurtisi@gmail.com>
+ZeusMiner Team <cs@zeusminer.com>
+Znort 987 <znort987@yahoo.com>

+ 45 - 24
Makefile.am

@@ -1,7 +1,8 @@
-# Copyright 2012-2013 Luke Dashjr
+# Copyright 2012-2014 Luke Dashjr
 # Copyright 2012 zefir
 # Copyright 2012 zefir
 # Copyright 2011-2013 Con Kolivas
 # Copyright 2011-2013 Con Kolivas
 # Copyright 2013 James Z.M. Gao
 # Copyright 2013 James Z.M. Gao
+# Copyright 2013-2014 Nate Woolls
 #
 #
 # This program is free software; you can redistribute it and/or modify it
 # 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
 # under the terms of the GNU General Public License as published by the Free
@@ -40,6 +41,8 @@ INCLUDES	= -fno-strict-aliasing
 
 
 bin_PROGRAMS	= bfgminer
 bin_PROGRAMS	= bfgminer
 
 
+sbin_SCRIPTS =
+
 if HAVE_WINDOWS
 if HAVE_WINDOWS
 else
 else
 bin_SCRIPTS = start-bfgminer.sh
 bin_SCRIPTS = start-bfgminer.sh
@@ -62,10 +65,6 @@ bfgminer_CPPFLAGS += $(NCURSES_CPPFLAGS)
 bfgminer_CPPFLAGS += $(AUTOSCAN_CPPFLAGS)
 bfgminer_CPPFLAGS += $(AUTOSCAN_CPPFLAGS)
 bfgminer_LDADD += $(AUTOSCAN_LIBS)
 bfgminer_LDADD += $(AUTOSCAN_LIBS)
 
 
-bfgminer_LDADD += $(libblkmaker_LIBS)
-bfgminer_LDFLAGS += $(libblkmaker_LDFLAGS)
-bfgminer_CPPFLAGS += $(libblkmaker_CFLAGS)
-
 # common sources
 # common sources
 bfgminer_SOURCES := miner.c
 bfgminer_SOURCES := miner.c
 
 
@@ -75,20 +74,19 @@ bfgminer_SOURCES += miner.h compat.h  \
 		   sha2.c sha2.h api.c
 		   sha2.c sha2.h api.c
 EXTRA_bfgminer_DEPENDENCIES =
 EXTRA_bfgminer_DEPENDENCIES =
 
 
-if NEED_LIBBLKMAKER
-SUBDIRS           += libblkmaker
-EXTRA_bfgminer_DEPENDENCIES += libblkmaker_directory
-libblkmaker_directory:
-	cd libblkmaker && $(MAKE)
-
-if HAVE_CYGWIN
-EXTRA_bfgminer_DEPENDENCIES += cygblkmaker-0.1-0.dll cygblkmaker_jansson-0.1-0.dll
+.PHONY: update-version
+update-version:
+	./gen-version.sh >version.h.new
+	cmp version.h version.h.new && rm version.h.new || mv version.h.new version.h
+version.h: update-version
+bfgminer_SOURCES += version.h
+BUILT_SOURCES = version.h
 
 
-cyg%.dll: libblkmaker/.libs/cyg%.dll
-	cp -p $< $@
-endif
-
-endif
+SUBDIRS += $(libbase58_SUBDIRS) $(libblkmaker_SUBDIRS)
+bfgminer_LDADD += $(libbase58_LIBS) $(libblkmaker_LIBS)
+bfgminer_CPPFLAGS += $(libbase58_CFLAGS) $(libblkmaker_CFLAGS)
+EXTRA_bfgminer_DEPENDENCIES += $(libbase58_EXTRADEPS) $(libblkmaker_EXTRADEPS)
+@BUNDLED_LIB_RULES@
 
 
 bfgminer_SOURCES	+= logging.c
 bfgminer_SOURCES	+= logging.c
 
 
@@ -216,12 +214,6 @@ endif
 
 
 if HAS_BITFORCE
 if HAS_BITFORCE
 bfgminer_SOURCES += driver-bitforce.c
 bfgminer_SOURCES += driver-bitforce.c
-
-if HAVE_WINDOWS
-else
-bin_PROGRAMS += bitforce-firmware-flash
-bitforce_firmware_flash_SOURCES = bitforce-firmware-flash.c
-endif
 endif
 endif
 
 
 if HAS_BIGPIC
 if HAS_BIGPIC
@@ -255,10 +247,18 @@ if USE_DUALMINER
 bfgminer_SOURCES += driver-dualminer.c
 bfgminer_SOURCES += driver-dualminer.c
 endif
 endif
 
 
+if USE_ZEUSMINER
+bfgminer_SOURCES += driver-zeusminer.c
+endif
+
 if HAS_AVALON
 if HAS_AVALON
 bfgminer_SOURCES += driver-avalon.c driver-avalon.h hexdump.c
 bfgminer_SOURCES += driver-avalon.c driver-avalon.h hexdump.c
 endif
 endif
 
 
+if USE_AVALONMM
+bfgminer_SOURCES += driver-avalonmm.c
+endif
+
 if USE_KNC
 if USE_KNC
 bfgminer_SOURCES += driver-knc.c
 bfgminer_SOURCES += driver-knc.c
 endif
 endif
@@ -324,6 +324,19 @@ if USE_HASHFAST
 bfgminer_SOURCES += driver-hashfast.c
 bfgminer_SOURCES += driver-hashfast.c
 endif
 endif
 
 
+if USE_JINGTIAN
+bfgminer_SOURCES += driver-aan.c driver-aan.h
+bfgminer_SOURCES += driver-jingtian.c
+endif
+
+if USE_MINERGATE
+bfgminer_SOURCES += driver-minergate.c
+endif
+
+if USE_ROCKMINER
+bfgminer_SOURCES += driver-rockminer.c
+endif
+
 if NEED_BFG_LOWL_FTDI
 if NEED_BFG_LOWL_FTDI
 bfgminer_SOURCES += lowl-ftdi.c lowl-ftdi.h
 bfgminer_SOURCES += lowl-ftdi.c lowl-ftdi.h
 endif
 endif
@@ -333,8 +346,16 @@ bfgminer_SOURCES += lowl-hid.c lowl-hid.h
 bfgminer_CPPFLAGS += $(hidapi_CFLAGS)
 bfgminer_CPPFLAGS += $(hidapi_CFLAGS)
 endif
 endif
 
 
+if NEED_BFG_LOWL_MSWIN
+bfgminer_SOURCES += lowl-mswin.c lowl-mswin.h
+endif
+
 if NEED_BFG_LOWL_PCI
 if NEED_BFG_LOWL_PCI
 bfgminer_SOURCES += lowl-pci.c lowl-pci.h
 bfgminer_SOURCES += lowl-pci.c lowl-pci.h
+
+if USE_VFIO
+sbin_SCRIPTS += setup-vfio
+endif
 endif
 endif
 
 
 if NEED_BFG_LOWL_SPI
 if NEED_BFG_LOWL_SPI

+ 1015 - 0
NEWS

@@ -1,3 +1,1018 @@
+BFGMiner Version 4.7.0 - August 17, 2014
+
+- openwrt/multibuild: Avoid copying bitforce-firmware-flash, which is no longer
+included
+- AUTHORS: Simpler design, alphabetise lists
+- Remove obsolete SuSE packaging
+- Bugfix: test_hash: Fix Htarg calculation for exact binary divisions of diff 1
+- Fix target calculation from diff < 1.0 in test_hash()
+- avalonmm: Try to autodetect a sane default voltage and clock from MM version
+- avalonmm: Only poll one module at a time, so they don't try to talk over each
+other
+- avalonmm: Set baud rate for detection
+- Stratum: Ignore response from mining.extranonce.subscribe
+- Stratum: Implement mining.set_extranonce, and advertise support for it to
+pools with a #xnsub flag
+- Stratum: Keep nonce1 and n2size in a "staging" state until mining.notify is
+received
+- Stratum: Avoid putting new targets on pool stratum_work until mining.notify is
+received for it
+- minergate: Flush during init
+- minergate: Flush ready-to-queue list
+- minergate: Avoid preparing new jobs to queue while we are pending a flush,
+since the flush would occur after queuing the new jobs
+- minergate: Check for reused job ids
+- minergate: Avoid counting flushed jobs toward hashes done
+- minergate: Report all temperatures individually to RPC
+- minergate: Load temperatures from stats file
+- minergate: Implement hashmeter
+- minergate: Scale nonce difficulty up to pdiff 32
+- minergate: Implement mining
+- minergate: Support for detecting a SP10
+- Bugfix: configure: avalonmm needs work2d
+- Bugfix: bitforce: Remove sanity check triggered by race conditions on 65nm
+devices
+- Bugfix: bitforce: Avoid double-free of voltage data
+
+
+BFGMiner Version 4.6.0 - August 2, 2014
+
+- avalonmm: Even if no fans report speed, display set %
+- Bugfix: avalonmm: Fix fan speed setting
+- Bugfix: avalonmm: Actually read the result needed to get the correct module id
+- README.ASIC: Document AvalonMM driver usage with Avalon 2/3 rigs
+- Bugfix: Makefile.am: Remove reference to non-existent driver-avalonmm.h
+- avalonmm: Safely handle an improper job id that is within the last 2 sent
+- avalonmm: Include asserted fan speed in RPC
+- avalonmm: Include asserted fan speed in ManageTUI
+- avalonmm: Silence warning about detect ack at runtime
+- avalonmm: Make fan speed an option (both RPC and TUI)
+- avalonmm: Allow changing clock speed and voltage from Manage TUI
+- Bugfix: avalonmm: Show proper units for fans & voltage
+- avalonmm: Support for disabling the entire chain
+- Implement broad_udevrules for avalonmm
+- avalonmm: Show extranonce1, module id, temperatures, fans, clock, and voltage
+in Manage TUI
+- avalonmm: Include Module Id and ExtraNonce1 in RPC devdetails
+- avalonmm: Add Temperature0/1 and Fan Percent 0/1 to RPC
+- avalonmm: Add Frequency and Voltage to RPC
+- avalonmm: Add voltage setting (defaults to 0.6625 V)
+- avalonmm: Add clock setting and try to autodetect it if not provided
+- avalonmm: Implement hashmeter
+- avalonmm: Adjust device target up to pdiff 32 when possible
+- avalonmm: Update job when current pool changes
+- Bugfix: avalonmm: MM flips the xnonce2, so we need to do the same
+- avalonmm: Implement mining logic
+- lowl-spi: Move bit order reverse to bitflip8 function in util
+- avalonmm: Treat multiple chained modules as slaves rather than processors
+- avalonmm: Probing for devices using Avalon Miner Manager (Avalon2/3 rigs)
+- littlefury: Move crc16 logic to util
+- Use BUILT_SOURCES to ensure version.h is always built first
+- configure option --with-udevrules-group to allow customising the group name
+used
+- Bugfix: zero_stats: Only call cgpu function if it exists
+- Remove FPGA-only bitforce-firmware-flash tool (now located at
+https://github.com/luke-jr/bitforce-fpga-firmware-flash )
+
+
+BFGMiner Version 4.5.0 - July 26, 2014
+
+- Bugfix: zeusminer: Fix crash in TUI with newly introduced feature
+- Bugfix: gridseed: Fix crash in TUI with newly introduced feature
+- gridseed: Add the ability to set clock speed via the TUI
+- bitforce: Support for Monarch devices on Windows using new "mswin" lowlevel
+interface to scan for KMDF driver
+- Bugfix: gridseed: Implement a proper scanhash routine for GridSeeds
+- zeusminer: Add the ability to set clock speed via the TUI
+- Bugfix: gridseed: Only set PLL frequency once (not once per processor)
+- Bugfix: zeusminer: Retry detection on failure - ZM fails detection 1 / ~30
+times
+- Bugfix: zeusminer: Enabling the ZeusMiner driver should flag needing lowl-vcom
+- aan: Silence false warnings
+- Include broad udev rules when configured with --enable-broad-udevrules option
+- Bugfix: util: Lower the threshold for considering pool Scrypt diff broken
+- Bugfix: gc3355: Do not send work_id (or anything) in the last 4 bytes of work
+- gridseed: Refactor code to clean up and organize
+- gridseed: Document GridSeed specifics with comments and URLs
+- Copyright cleanups and updates
+- Bugfix: zeusminer: using icarus timing can lead to false positive Idle
+detection
+- zeusminer: Return the Chip # via the RPC API call procdetails
+- zeusminer: Display the Chip # in the UI when viewing per-proc details
+- Bugfix: miner: Check work->blk.nonce to see if work should be abandoned
+- rockminer: Allow setting clock 300-2560 as long as prefixed by "unsafe:"
+- util: Work around broken Scrypt pools automatically using realistic pdiff
+assumptions
+- scanhash: Document scanhash related methods with comments
+- Bugfix: gridseed: Report communication errors using dev_error()
+- gc3355: Return bytes read to distinguish 0 bytes from error
+- Bugfix: gridseed: Add delay between Scrypt reset and sending work
+- gridseed: Bugfix: fix the constant used for estimated hash rates
+- klondike: zero_stats support
+- bitforce: zero_stats support (Temperature, Voltage, and Avg Wait)
+- avalon: zero_stats support (temp_max, no_matching_work, match_work_count%d)
+- Add driver interface for zero_stats function
+- Bugfix: bitforce: Short-circuit bitforce_read(0) to avoid lowlif issues
+- Bugfix: bitforce: Ensure data for the current command is always read (and only
+once), with lowl-pci
+- Bugfix: setup-vfio: Add device ids to vfio-pci even if they didn't have a
+driver previously
+- Bugfix: lowl-pci: Use volatile qualifier for PCI mmaps
+- Bugfix: bitforce: Use lowlevel interface device was probed with, for actual
+mining
+- setup-vfio: New shell script to automatically configure VFIO
+- README.ASIC: Monarch: Need to do new_id for every affected device, and only
+after unbinding them
+- README.ASIC: Monarch: Use shell variables for commands
+- gridseed: Bugfix: Revert earlier changes to scanhash based on feedback
+- hashfast: Support for changing clock at runtime
+- hashfast: Store a copy of what we believe to be the chip configuration data
+- hashfast: Store firmware revision
+- util: pk_uNle macro for changing a number inside a packed structure
+- README.ASIC: KnCMiner: Talk about additional i2c-tools dependency
+- README.ASIC: KnCMiner: Remove mention of now-obsolete Bertmod
+- README.ASIC: KnCMiner: Grammatical corrections
+- Bugfix: RPC: Avoid processor-specific details in devdetails
+- gridseed: Bugfix: log invalid detect responses as debug info, not an error
+- zeusminer: Support setting clock via RPC API procset call
+- README: Add Controla and Minera controller software links & info
+- gridseed: Bugfix: Fix hash-rate calculation when no nonces are being found
+- dualminer: Bugfix: assign the proper value for work_division
+- gridseed: Refactor to clarify GridSeed terminology
+- gridseed: Add support for displaying per-chip statistics
+- gridseed: Convert to use newer set_device_funcs interface
+- Bugfix: gridseed: Don't leak cgpu_info when devices are already claimed
+- icarus: Processor detail support
+- DevAPI: Allow using device_proc_by_id with const struct cgpu_info
+- icarus: Ensure fpga_count is finalised before add_cgpu is called
+- icarus: Move work_division autodetection code into new
+icarus_probe_work_division function
+- icarus: Remove ability to change fpga_count at runtime
+- Bugfix: gen-version.sh: Replace bashism ("here string")
+- gridseed: Support devices with more than 255 physical processors
+- Use `git describe` to generate version.h to avoid user confusion over builds
+from git
+- zeusminer: Support devices with more than 255 physical processors
+- hashfast: Include chip/core address in RPC procdetails
+- gridseed: Reduce traffic sending work to GridSeed devices
+- gridseed: Bugfix: previous refactor (unpublished) changed logic
+- gc3355: Refactor to remove SHA2 code specific to the 5-Chip GridSeed Orb
+- lowl-vcom: Bugfix: do not attempt to open the USB devices when enumerating
+
+
+BFGMiner Version 4.4.0 - July 7, 2014
+
+- lowl-vcom: Added support for auto scanning (-S auto) on Mac OS X
+- rockminer: implement --device-protocol-dump for debugging
+- README: Update for commandline options
+- README: Update configure options
+- Bugfix: bfg_gpio_setpin_output: Clear alt-function bits via INP_GPIO macro
+- jingtian: Explicitly configure SPI device while opening
+- jingtian: Toggle ASIC reset GPIO at startup
+- aan: Set defaults as soon as a proc is initialised
+- aan: Allow specifying clock as xHEXX for a raw PLL register config
+- aan: Include current frequency in RPC status
+- aan: Implement --set jtn:clock=MHz
+- aan: Logic to calculate PLL configurations for a given frequency
+- jingtian: Use SPI enable GPIO to disconnect SPI during chipselect changes
+- aan: Set PLL to 850 MHz
+- aan: Simplify register buffer
+- jingtian: Decode extra temperature bytes in read_reg
+- aan: Add a read_reg hook
+- aan: Enable configuring nonce diff with (eg) --set jtn:diff=32
+- aan: Properly handle nonce_diff
+- aan: Implement mining
+- DevAPI: Some designs set the main thr tv_poll from secondary thrs, so check it
+after the loop
+- aan: aan_spi_parse_rx implies spi_clear_buf
+- jingtian: Do detection asynchronously across all possible chipselects so they
+complete in parallel
+- aan: Refactor aan_spi_cmd a bit
+- jingtian: Implement device protocol dump
+- jingtian: Detection-only code for new driver
+- lowl-spi: GPIO access functions
+- lowl-spi: Move knc_spi_txrx to linux_spi_txrx
+- SGW: Support for proxy-share difficulty preferences
+- SSM: Propagate proxy-share difficulty changes to established connections
+- SSM: Track stratum connections for each proxy user
+- SSM: Track authorised users for each connection
+- SSM: Initialise proxyshare difficulty from --set pxy:diff=N
+- proxy: Accept --set pxy:diff=N to set preferred proxyshare difficulty
+- proxy: Provide a place to store desired proxyshare difficulty on a
+per-username basis, and copy it to SSM connections when authorising them
+- SSM: Track proxy share difficulties
+- Expose target_diff function and add pdiff_to_bdiff macro
+- util: double_find_precision function to identify ideal precision for a fp
+number
+- work2d: Expose WORK2D_MAX_DIVISIONS in header
+- add_local_gbt: Avoid adding servers already configured
+- Bugfix: Avoid writing automatically configured local GBT servers to the config
+file unless they have been manually enabled
+- add_local_gbt: Use rpcconnect when configured
+- rockminer: Bugfix: must specify a baud rate (maximum of 115200) to get a read
+response
+- Bugfix: Use atexit() to ensure a final \n is always printed at exit to work
+cleanly with new logging design
+- Restore compatibility with old versions of libblkmaker
+- Bugfix: probe for ZeusMiner before probing for DualMiner
+- Wait until coinbase-addr is needed again, before updating it following a block
+change (always using getaccountaddress)
+- Don't automatically use #getcbaddr for local bitcoind if the user provided
+their own
+- Bugfix: refresh_bitcoind_address: Check for NULL json (which is not JSON
+"null")
+- Bugfix: add_pool: If no current pool set, initialise it (otherwise pool
+testing may start a longpoll thread which tries to access currentpool
+uninitialised)
+- devpath_to_devid: *nix: Reject anything that doesn't begin with a /
+
+
+BFGMiner Version 4.3.0 - June 30, 2014
+
+- Bugfix: zeusminer: Include config.h
+- openwrt: Disable libusb via --without-libusb
+- Avoid waiting for local bitcoind test if we have other pools defined already
+- lowl-pci: Silence warning on big endian
+- bitfury: Portability fixes, including big endian compatibility
+- Bugfix: bifury: strtoll already implies native endian, no need to flip it
+again
+- bitforce: Additional sanity checks, including ensuring our final queued count
+matches that seen by the device
+- bitforce: Go back to ignoring race-triggered sanity check warnings for ZqX
+- bitforce: Refactor FLB and queue flush sanity checks
+- bitforce: Use binary FLB protocol for Monarch
+- bitforce: Add bitforce_read function to deal with binary responses
+- bitforce: Support for queue id based jobs
+- Make work->device_id unsigned
+- bitforce: Support device explicit "Scan Interval" to override hardcoded sleep
+times
+- bitforce: Allow queued_max to exceed BITFORCE_MAX_QUEUED_MAX iff the firmware
+provides an explicit Queue Depth
+- bitforce: Fix bitforce_chips_to_plan_for to work beyond 32 chips
+- configure: Clean up zeusminer logic
+- icarus: Use estimated hashes for hw errors (more accurate hashrate for devices
+where hw error values vary significantly from hashes performed)
+- zeusminer: Bugfix: calculate work_division based on chips and cores
+- Replace swabn with bswap_32mult (matching swap32yes parameters and
+performance)
+- Bugfix: zeusminer: Correctly encode job header regardless of native endian
+- zeusminer: support added for ZeusMiner scrypt ASICs
+- icarus: refactoring: commenting ICARUS_INFO members
+- icarus: Accept any power of two as a valid work_division
+- icarus: option added for Icarus-based drivers to ignore the golden nonce
+during probe
+- util: is_power_of_two function
+- Bugfix: Display proper statline R and HW error percents for values < 1
+- openwrt: Provide scrypt option
+- Benchmark: Debuglog headers generated
+- Bugfix: cpu: Fix scrypt CPU miner
+- Bugfix: scrypt: Fix scrypt hash postprocessing for big endian
+- Bugfix: scrypt: Correct endian handling in PBKDF2_SHA256_80_128
+- scrypt: Add unit test for scrypt_1024_1_1_256_sp
+- scrypt: Add unit tests for PBKDF2_SHA256_80_128 and salsa20_8
+- Bugfix: Copy ALL the data with swap32to<native>
+- Automatically add pool configured from bitcoin.conf for failover only
+- Add failover_only pool flag, to avoid using it regardless of strategy
+- Accept --default-config option to search and load default configuration files,
+even if user is specifying their own
+- Use appdata_file_call to find BFGMiner config file(s)
+- util: appdata_file_call and appdata_file_find_first functions
+- ccan: Update to latest version (which includes floatval option support)
+- Bugfix: Adapt quit function to new logging design
+- Workaround GCC 4.6 initialisation bugs with BYTES_INIT
+- Bugfix: Use int rather than ssize_t to type-match %d expectation
+- Minor refactor of text-only mode: avoid wasting bottom line of console, and
+save status lines as they are replaced by log items
+- Bugfix: Wake up wait_lpcurrent if its conditions for returning may have
+changed
+- Defer determining --quit-summary default until it is needed, so hotplugged
+devices affect it
+- Bugfix: In benchmark mode, only remove the new pools after putting them in the
+array, since the removal will try to remove it from the array
+- Bugfix: Initialise struct pool in add_pool rather than halfway through startup
+- URI parameter #getcbaddr to request coinbase address from bitcoind or
+compatible servers
+- pool_set_uri function
+- util: bytes_eq and bytes_assimilate
+- Replace struct _cbscript_t with bytes_t for simplicity
+- Bugfix: Parse userpass option with strchr rather than strtok to avoid
+usernameless passwords getting into the username field and being displayed
+- Bugfix: Free old coinbase script before setting a new one
+- util: upper_power_of_two_u32 function
+- Avoid unnecessarily finding drivers in a loop
+- lowl-pci: Never probe via -S *:all
+- configure: Succeed even if the libblkmaker submodule is missing (only
+--with-system-libblkmaker)
+- rockminer: Reset task timeout when queuing work
+- rockminer: When we detect a task failure, check if we ought to grab a new work
+rather than resend
+- rockminer: Add a time limit before resending work even outside of midtask
+state
+- Bugfix: rockminer: Keep count of requested jobs properly
+- make-release: Include ccan LICENSE symlinks as symlinks even in ZIP
+- make-release: Ensure ccan licenses get included in source
+- Bugfix: make-release: Correctly avoid unused parts of ccan
+- make-release: Do builds with the official source release, to test that it
+works
+- Bugfix: DevAPI: Make for_each_logical_proc work correctly
+- Avoid double hashing of shares
+- Create work_hash function to abstractly produce work->hash from work->data
+regardless of algorithm used
+
+
+BFGMiner Version 4.2.0 - June 11, 2014
+
+- Upgraded Windows libmicrohttpd from 0.9.35 to 0.9.38_pre33603
+- SGW: Workaround BE Cube bugs with new libmicrohttpd by forcing HTTP 1.0
+response
+- rockminer: Increase hw error count for problems
+- rockminer: Autodetect with "R-BOX miner" or "RX-BOX miner" product strings
+- rockminer: Support for seeing and setting clock frequency in Manage TUI
+- rockminer: Include clock frequency in RPC processor status
+- rockminer: Support for setting clock frequency
+- rockminer: Workaround lost tasks by resending them
+- rockminer: Support for temperature sensors
+- rockminer: Debug messages
+- Bugfix: rockminer: Initialise rockminer_chip_data
+- Bugfix: rockminer: Ensure work actually exists before testing against it
+- rockminer: Mine at 270 MHz
+- rockminer: Implement mining (at 200 MHz)
+- DevAPI: Move device_proc_by_id out of bifury driver, since it is generically
+useful
+- rockminer: Detection code for new driver
+- bfg_socket wrapper to ensure sockets are close-on-exec
+- set_cloexec_socket: Explicitly cast SOCKET to HANDLE
+
+
+BFGMiner Version 4.1.0 - June 6, 2014
+
+- Bugfix: Ensure variables are declared even without ADL support
+- RPC: Include a list of config files loaded in "config" reply
+- Bugfix: Save a linked list of config files loaded so output makes sense
+(previously only the most recent config file was named, and errors were reported
+inconsistently)
+- README.RPC: Document Coinbase-Sig in config reply
+- Bugfix: Safely handle pool status line when no pools are alive
+- bitforce: Refactor bitforce_vcom_gets slightly to be more sane
+- Bugfix: initiate_stratum: Ensure extranonce2 size is not negative (which could
+lead to exploits later as too little memory gets allocated)
+- Stratum: extract_sockaddr: Truncate overlong addresses rather than stack
+overflow
+- Stratum: tlsca parameter to require CA validation of TLS certificate
+- Bugfix: Avoid setting tv_idle before testing pool (it will be set if the test
+fails)
+- restart_stratum: Make use of return_via
+- return_via helper function family to assign a variable and goto
+- Bugfix: restart_stratum: Release pool_test_lock on failure
+- bfsb: Disable all banks before enabling the one we want, to avoid having two
+enabled at the same time (eg, when switching from bank 3 to bank 2)
+- Interpret present "tls" parameter to require TLS
+- uri_get_param_bool2 returning a tristate
+- Tests for uri_find_param
+- Split uri_find_param out of uri_get_param_bool
+- gridseed: Allow specifying an arbitrary number of chips with --set gsd:chips=X
+- gridseed: added support for the 80-chip (two blades of 40 chips) G-Blade
+Scrypt-only miner
+- Bugfix: gridseed: use a signed integer so that returning -1 has defined
+behavior
+- RPC: Return integer difficulties without decimal places
+- Bugfix: Zero pool "Works"
+- Bugfix: Set any listening sockets to close-on-exec/non-inheritable to avoid
+issues rebinding them on restart
+- RPC: Explicitly shutdown communication on client sockets to avoid them being
+held open by forked processes
+- RPC: Clean up mcast socket with tidyup_socket
+- RPC: Move socket tidyup code to its own function
+- Bugfix: RPC: Use pthread_exit rather than returning from the RPC thread, to
+ensure tidyup gets called
+- Bugfix: bitforce: During initialisation, clear each XLink slave exactly once
+only
+
+
+BFGMiner Version 4.0.0 - May 26, 2014
+
+- Update openwrt Makefile for xz source
+- Update libblkmaker to 0.4.0
+- Workaround Homebrew-induced segfault during device scan
+- Allow hotplug with scrypt
+- Bugfix: test_domain_funcs: printf precisions must be int, not size_t
+- littlefury: Cleanup to make avoiding memory leak easier
+- Bugfix: Avoid using an enum type to hold a bitfield
+- ruby extension is "rb" not "py"
+- README.RPC: Document api-example.rb
+- Add Ruby Api Example
+- hashfast: Check devices with Product matching "GoldenNonce" so we have a
+vendor-neutral way to detect them
+- Reduce set_device-not-implemented message to debug log level, since it can
+occur for init-only settings
+- Use a mutex to block pool_active on a common check per pool at any given time
+- Use cURL return code to check if cURL sockets hit CURLE_AGAIN
+- Abstract pool_recently_got_work into a dedicated function
+- AUTHORS: Dmitry Smirnov contributes BFGMiner packaging to Debian
+- README: Talk about more GUIs and mining OSs
+- icarus: Minor optimisation (swap byte order in 32-bit always-aligned groups,
+and skip pointless memory copy)
+- icarus: Initialise ob_bin to avoid leaking other memory to device
+- Bugfix: bitfury: Set stat_elapsed_secs early, just in case we jump with goto
+- Bugfix: Report actual kernel name in RPC, rather than kernel interface name
+- README.scrypt: Document psw kernel
+- opencl: Another optimised scrypt kernel ("psw")
+- README.scrypt: Document zuikkis kernel
+- opencl: Optimised scrypt kernel ("zuikkis")
+- Bugfix: Silence harmless warnings
+- Bugfix: vcom_set_timeout: Return whether successful
+- bitforce: Set name for ASIC devices
+- Bugfix: Avoid unnecessary rescans due to wrong devtype
+- bitforce: Support 28nm ChannelNN format for ZCX
+- Bugfix: bitforce: Don't confuse channels with X-Link
+- Bugfix: bitforce: Set VCOM timeout to 1 second for ZGX request, since it
+sometimes lacks a newline
+- lowl-vcom: vcom_set_timeout function
+- bitfury: Eventually (after 30 seconds) give up trying to detect chip
+generation and just assume gen1
+- bitfury: Use other nonces for gen1 detection so one bad core can't break it
+- Bugfix: bitfury: Account for necessary nonce fudging during chipgen detection
+- gridseed: Switch from the Queued miner loop to the Scanhash miner loop
+Improves performance on Raspberry Pi Fixes inaccurate hashrate estimates Fixes
+bug overwriting work inadvertently
+- If the current pool lacks its own block change detection, keep the pool used
+for that connected
+- pool_active_lp_pool function to complement select_longpoll_pool
+- Track which pools have active longpoll connections
+- Avoid retrying longpoll requests for removed pools (and possibly change block
+change notification source for existing ones) if longpoll connection gets
+dropped
+- util: Pass full json_rpc_call_state to upload_data_cb
+- Remove now-unused variable
+- nanofury: Update enable/disable/reinit to cleanly handle multichip devices
+- bifury: Default max_queued to chips * 5 + 6 so it is back up to the original
+16 for bi*fury (which seems to need it sometimes)
+- bifury: Default max_queued to chips * 5 for extra breathing room (avoids
+occasional issues with Hex*Fury)
+- README.ASIC: Document workarounds for OSM/Hex*Fury firmware bugs
+- bifury: Measure hashes done by nonces found since we cannot tell what
+generation chip is in use
+- bifury: Default max_queued to chips * 4
+- bifury: chips init setting to workaround buggy hardware which reports wrong
+chip count
+- bifury: free_after_job setting to workaround buggy hardware which ignores
+maxroll
+- bfg_strtobool helper function
+- bifury: Enable runtime modification of max_queued
+- bifury: Migrate to set_device_funcs interface
+- Stratum: Accept a "notls" parameter on pool URIs to disable opportunistic TLS
+- uri_get_param_bool helper function for pool parameters
+- nanofury: Only ramp up osc6_bits on multichip devices
+- Bugfix: nanofury: Move the bitfury pointer back to the last element before
+starting the ramp up loop
+- Bugfix: Use pdiff 1/0x10000 for scrypt benchmarking
+- benchmark: Use sane bits (of a very high difficulty to avoid triggering
+anti-reorg protections)
+- Ignore work difficulty minisculely harder (ie, rounding error) than what
+device supports
+- Benchmark: Add 2D work support
+- SSM: Use a lower share difficulty in scrypt mode
+- Rework test_nonce to share common logic for scrypt and SHA256d
+- work2d: Accept nonce difficulty with submissions
+- configure: Make work2d building abstract from libevent
+- work2d: Standardised way to pad extranonce beyond what work2d manages
+- Abstract code from stratumsrv_mining_submit into new work2d_submit_nonce
+function
+- Avoid handling hex encoding in work2d
+- Move/rename _ssm_gen_dummy_work to work2d_gen_dummy_work
+- SSM: Refactor _ssm_gen_dummy_work to work with struct stratum_work instead of
+struct stratumsrv_job
+- Move "nonce1" session id from struct pool to struct stratum_work
+- Add pool and work_restart_id to struct stratum_work so they can be used
+independently of struct pool
+- Move n2size from struct pool to struct stratum_work
+- autogen.sh: Automate cleaning INSTALL out of libblkmaker so git updates
+properly
+- Update libblkmaker to 0.4.0
+- Replace drv_rolllimit with struct ntime_roll_limits
+- util: Unpack and pack utility functions ([u]pk_u{8,16,32}{le,be})
+- GBT: Do not allow drivers to roll ntime
+- GBT: Use libblkmaker 2D work to service SSM and potentially other 2D work
+drivers
+- Hide blktemplate_t behind bfg_tmpl_ref to abstract reference counter
+- Add pool_has_usable_swork function
+- SSM: Split stratum work division into 2D work manager ("work2d")
+- bitforce: Avoid crashing when broken devices report more jobs flushed than
+they had to flush
+- nanofury: Gradually ramp up osc6_bits for NF6 design
+- util: memrchr is not portable (GNU extension), so implement our own my_memrchr
+- bitfury: Report correct hashrate for gen2 chips
+- bitfury: Detect gen2 chips
+- Stratum: If difficulty calculates out to 0.999 to 1, round it up to 1 to avoid
+something SHA2 hardware cannot handle
+- Stratum: If the pool target has changed since the job a work came from, check
+any shares against the new target too in case it expects retroactive difficulty
+adjustments
+- Stratum: Interpret integer difficulty values as pdiff (or Ldiff, for scrypt)
+to avoid losing shares on non-compliant servers
+- Rework difficulty-to-target functions to error on the safe side, and
+consistently work in pdiff or bdiff
+- Simplify stratum to convert difficulty to target immediately
+- Stratum: Attempt connection with unauthenticated TLS, with failover to raw TCP
+- Stratum: Return to curl_easy_{send,recv}
+- get_registered_domain: Return full IP for raw IP addresses, so they can at
+least redirect to the same IP
+- Reject redirection across different registered domain names (can be disabled
+by appending #redirect to pool URI)
+- util: match_domains function
+- util: Add isCalpha, get_registered_domain, and extract_domain functions
+- README: Update for gridseed 5-chip orb
+- configure: Clean up gridseed logic to only build by default when scrypt is
+enabled
+- gridseed: Fix warnings
+- gridseed: Added support for Scrypt hashing with 5-chip GridSeed devices
+- dualminer: Only one debug message needed for all init options
+- dualminer: Move opt_dual_mode to dualminer file
+- gc3355: move scrypt_only_reset_cmd out of scrypt_only_reset
+- dualminer: No need to reconfigure frequency every work
+- dualminer: refactor gc3355 code for readability, maintainability and use with
+other devices
+- dualminer: Abstract dualminer_init_hashrate out of dualminer_init_firstrun
+- dualminer: Initialise opt_pll_freq along with opt_sha2_units
+- dualminer: Move opt_sha2_units initialisation to new dualminer_set_defaults
+function
+- dualminer: Remove unnecessary opt_sha2_number
+- dualminer: Simplify teardown
+- dualminer: No need to parse strings for SHA2 unit counts
+- gc3355: Support for appending jobs with task id
+- gc3355: increase delays to 20ms
+- gc3355: use NULL for end-of-command terminator
+- dualminer: comment what various things are for and/or do
+- dualminer: Split gc3355_scrypt_prepare_work and gc3355_sha2_prepare_work out
+of dualminer_job_prepare
+- dualminer: Use cgsleep_ms rather than usleep
+- gc3355: Remove unused opt_hubfans variable
+- dualminer: rename various things to be clearer
+- Use a common enum bfg_gpio_value for both lowl-vcom (cts, dtr, rts) and
+mcp2210
+- README.RPC: Document quit/restart reply format change
+- RPC: Provide a full status section for quit/restart commands
+- RPC: Add "Miner" to version response to include software name along with
+version
+- Bugfix: Dereference udev monitor events when done with them
+- opencl: Workaround false warning regarding Mesa version number parsing
+- knc: use_dcdc setting that Nov batch users can use to disable DCDC usage
+- configure: Include <stddef.h> for _Static_assert check
+- opencl: If kernel does not specify an interface in scrypt mode, assume it's
+the scrypt interface
+- opencl: Replace dated versioning with hash of source code
+- opencl: Search all the same kernel paths when setting kernel
+- opencl: Accept arbitrary kernel filenames, provided they specify a kernel
+interface somewhere in the source file
+- Bugfix: Explicitly pass precision and width as int type
+- Make pool stability message use nicer English
+- Failover pool switching back delay is now configurable.
+- Expand extranonce2 size to 64-bit
+- README.ASIC: KnCMiner: Suggest --disable-other-drivers and remove
+no-optimisation CFLAGS
+- configure: libusb is implied by lowl-usb, so no need to list it as an option
+separately
+- Silence warnings when built without various drivers
+- DevAPI: Remove long deprecated serial_detect function family
+- Bugfix: Turn spidevc into lowl-spi to fix building the knc driver without the
+bitfury driver
+- Avoid triggering unnecessary device rescans (such as with pre-lowlevel
+drivers)
+- Replace --no-client-reconnect with --no-pool-redirect which also disables
+X-Stratum header redirects
+- Partial: A new --no-client-reconnect command that disables the
+'client.reconnect' function.
+- ftdi: Rename files to lowl-ftdi.{c,h} to fit with naming convention
+- bfx: New driver for BFx2 Bitfury USB stick miners
+- ftdi: ft232h_mpsse_readwrite_all function to do both reading and writing
+concurrently in MPSSE mode
+- ftdi: ft232h_mpsse_set_axbus function
+- ftdi: Support for ft232h MPSSE mode (currently only works with
+ft232r_write_all)
+- ftdi: Split most of ft232r_open into a ftdi_common_open function
+- ftdi: Support for --device-protocol-dump
+- ftdi: Scan for ft232h-based devices
+- ftdi: Avoid neutering lowlevel_device_info when opening it
+- ftdi: Accept const data in write functions
+- ftdi: Use actual USB packet size for FTDI status removal
+- ftdi: Make ftdi lowlevel code independent of x6500 driver
+- dualminer: Workaround false compiler warning in gc3355_config_cpm
+- Bugfix: --disable-other-drivers should not force libusb to be unused
+- Bugfix: README: Alphabetise and categorise build configuration options (and
+add missing ones)
+- TUI: Use _wlogprint for pool proto to avoid compiler warning
+- Bugfix: TUI: Fall back to RPC URI if sockaddr_url hasn't been extracted (such
+as benchmark mode)
+- Hide work update messages unless explicitly enabled with hidden
+--verbose-work-updates flag
+- TUI: Redesign pool info line to include share difficulties in multipool modes
+and last explicity work update timestamp
+- nanofury: Abstract both power gpios into a nanofury_power_enable function
+- nanofury: Add NANOFURY_GP_PIN_PWR_EN0 (inverted PWR_EN) - support for power
+management (hardware) optimizations
+- Bugfix: nanofury: Set cgpu_data for all processors (eg, to avoid crashing in
+nanofury_set_ledmode for non-first procs)
+- Bugfix: nanofury: Use correct SPI port for baud setting
+- proxy: "Report in" clients when their info is looked up by username
+- opencl: Replace (and deprecate) --no-opencl-binaries option, with --set
+opencl:binary=no
+- opencl: Reenable OpenCL kernel binaries for Mesa OpenCL >= 10.1
+- gc3355: Replace frequency-setting hex blobs with logic
+- README: Update for DualMiner
+- make-release: Switch to xz for source releases
+- Stratum: If a pool explicitly tells us it doesn't support get_transactions, no
+need to wait for a timeout
+- api - buffer size off by 1 for joined commands
+- miner.php - define a default rigport (that can be changed) and don't require a
+port number in the rigs array
+- miner.php allow links for rig buttons in tables and allow using the 4th IP
+octet if no rig name - default disabled for both
+- Remove wrong goto
+- Remove the unqueued work reference when we discard work from get queued as'
+well.
+- Wake the global work scheduler when we remove a work item from the unqueued
+work pointer.
+- Discard work that is stale in the get_queued() function, returning NULL
+instead.
+- Bugfix: dualminer: Declare support for both SHA256d and scrypt algorithms
+- gc3355: Use lowl-vcom set_serial_dtr function
+- lowl-vcom: Implement set_serial_dtr
+- gc3355: Use lowl-vcom cts/rts functions
+- lowl-vcom: Implement set_serial_rts for Windows
+- lowl-vcom: set_serial_rts should return the new rts value, if anything
+- Rename icarus-common.h to driver-icarus.h
+- icarus: probe_timeout setting to control how long we wait before giving up on
+probes
+- icarus: Defer initial open until init
+- Remove debugging garbage that snuck in
+- configure: New --disable-other-drivers options for users who want to build
+just select drivers
+- Simplify _now_gettimeofday on Windows, working around weird WINE crash
+- cpu: Fix and simplify benchmarking on Windows (removes hidden --bench-algo
+option)
+- Remove old bench_block.h, no longer needed
+- Bugfix: cpu: Adapt benchmarking code to new benchmark work generator
+- Report precise share difficulties below 1
+- Bugfix: lowlevel: Pretend drivers not matching the active algorithm don't
+exist
+- Bugfix: dualminer: Set min_nonce_diff before getting work
+- Bugfix: gc3355: Use correct byte counts for hex2bin
+- configure: Fix up dualminer logic
+- dualminer: Support for mining both Scrypt and SHA2 using DualMiner GC3355
+thumb sticks
+- miner: scan for low level devices even if --scrypt is specified by the user
+(to detect Scrypt ASICs)
+- icarus: output protocol information if the user specifies
+--device-protocol-dump
+- icarus: Support for driver-specified job command lengths
+- icarus: Support for custom driver job start function
+- icarus: Support for custom driver initialisation function
+- icarus: Call icarus_job_prepare via driver job_prepare key so it can be
+overridden
+- icarus: generic support for devices that return little-endian nonces
+- icarus: allow custom probes
+- icarus: expose do_icarus_close
+- RPC: Remove separate CPU and GPU counters from devs Msg
+- RPC: Optimise find_index_by_cgpu
+- Bugfix: RPC: Restore PGA index counting
+- Accept decimal values for --shares, and clarify weighed nature of the value
+- benchmark: Remove all real pools, and prevent adding them
+- benchmark: Fake submission of "shares"
+- benchmark: Roll data before nonce only
+- Bugfix: configure: Report bitforce:pci instead of bitforce:uio
+- bitforce: Workaround broken/old compilers by setting device_fd outside of
+initialisation
+- AUTHORS: Update email for Kano
+- RPC: Add "MHS rolling" key to status mirroring "MHS %ds"
+- minorfix: remove extra semicolon
+- Drillbit: Revert needless commit 270c1d01f, thanks @luke-jr
+- Drillbit: Add upper and lower bounds to "Eight boards have a multiple of 8
+ASICs" check
+- Drillbit: Clarify use of device_data pointer to store capabilities/protocol
+version temporarily
+- Drillbit: Keep reading work for as long as the device returns results.
+- Drillbit: Be strict about not accepting any boards with newer protocol
+versions. Protocol version bumps are non-backwards-compatible.
+- Drillbit: Add support for "protocol version 4", non-device-specific
+configuration packet format
+- README.RPC: Add link to Node.js RPC wrapper
+- opencl: Get temperature and fan speed updates with get_stats interface rather
+than abusing statline override interface
+- Bugfix: Remove devtype variable from driver API
+- opencl: Deprecate --auto-{fan,gpu} and --gpu-dyninterval options
+- opencl: Infer autoengine mode when the clock setting receives a range
+- opencl: Infer autofan mode when the fan setting receives a range
+- Bugfix: opencl: Defer initial intensity assignment until init, so opt_scrypt
+has a chance to be set
+- opencl: Strip leading and trailing spaces from names
+- trimmed_strdup helper function
+- icarus: Replace hard-coded "Icarus" mentions
+- opencl: Deprecate all dedicated commandline options for parameters accessible
+via set_device
+- opencl: Make current intensity, xintensity, and oclthreads available via RPC
+- opencl: Redo Manage TUI detail line to use xintensity when more reasonable
+- opencl: Support for setting oclthreads as intensity=xNNN (for NNN xintensity);
+also allow setting d<whatever> for an initial dynamic intensity
+- opencl: Store oclthreads and only convert to/from intensity numbers when
+dealing with external interfaces
+- RPC: Deprecate all cpu* and gpu* commands, and remove CPU/GPU counts from
+'devs' response
+- RPC: pgarestart command to match {cpu,gpu}restart
+- RPC: Unify common code under get_pga_cgpu function
+- README.RPC: Deprecate gpu{intensity,mem,engine,fan,vddc} now that they can be
+accessed via {pga,proc}set
+- RPC: Consider CPU and OpenCL devices as "PGAs" to begin migration to a simpler
+interface
+- RPC: Turn gpu{intensity,mem,engine,fan,vddc} into wrappers around set_device
+- opencl: Support configuration using set_device interface
+- Bugfix: miner_thread: Don't call cgpu_set_defaults if it has already been
+called
+- Common add_set_device_option for automatically generated --set-device options
+- Bugfix: opencl: Safely handle work->device_data across work copies and cleans
+- set_device: Accept underscores for temp_{cutoff,target}
+- opencl: Allow specifying a comma separated list for --gpu-threads
+- opencl: _SET_INT_LIST2 to set variables not necessarily within
+opencl_device_data
+- hashfast: Enable setting device-wide clock at probe time using USB_INIT
+- Bugfix: hashfast: Use signed type for manipulating raw temperature data, in
+case it is below 0 C
+- hashbusteravalon: Add udev rule
+- klondike: Split up work and submissions among logical processors
+- klondike: Make reply_wait_time a settable variable (configured lower for
+hashbusteravalon)
+- klondike: Explicitly enable slaves as well as the master
+- hashbusteravalon: Klondike-based metadriver
+- klondike: Pre-initialise klninfo separately from probe
+- klondike: Allow setting max_work_count and max_work_time via set_device
+- klondike: Variablise max_work_count and old_work_ms
+- Move all OpenCL-specific data behind device_data pointers, and relocate
+OpenCL-specific code out of miner.c
+- opencl: Macro-ise code for list options
+- Reduce failure applying set-device rules to debug loglevel
+- Add --set as alias for --set-device
+- Bugfix: miner.c: Correct ccan include
+- Bugfix: Correct ccan-upstream directory include
+- Load default config before commandline options, so the latter override the
+former (but prioritise defaultconfig pools last)
+- configure: Check for sys/termios.h used by ccan/opt
+- make-release: Only include specific components of ccan
+- Use git submodule for ccan (moving opt_*_floatval into miner.c)
+- Probe erupter before icarus, since they are far more common now
+- Accept --no-config option to inhibit loading default config file, even without
+specifying another config
+- Bugfix: RPC: Ensure isjoin always gets initialised
+- bitforce: Remove two really-unused variables
+- nanofury: Silence false warning from some compilers about uninitialised
+variable use
+- hashfast: Promote problematic write() replies to warning level
+- hashfast: Log errno on write failures
+- Extend maximum processor count to 17,576 (3 letters)
+- DevAPI: Make processor lettering code more extensible
+- Remove shorthand option for undocumented --bench-algo
+- Remove long-deprecated and non-functional --enable-cpu option
+- Deprecate shorthand options for uncommonly-used --algo, --cpu-threads,
+--expiry, --gpu-threads, --intensity, --kernel-path, --kernel, --scan-time,
+--vectors, and --worksize
+- API-README correct new text format documentation
+- API allow multiple commands/replies in one request
+- Due to work restarts causing ~all processors to request work at once, it is
+always ideal to stage at least mining_threads extra works
+- scrypt: raise the maximum GPU intensity for scrypt mining to 31 - benefits
+shown for AMD R9 290 models
+- Bugfix: bitforce: ZNX/ZWX expect size minus 1
+- Bugfix: bitforce: Start building send_queue command at the real end
+- Bugfix: bitforce: Defer opening until after devdata is initialised (since it
+is now used to track open-ness)
+- Document uio/vfio configure options as --without-* since they are enabled by
+default when available
+- Include list of lowlevels built in configure and --help output
+- lowl-pci: Autodetect build-time support for UIO and/or VFIO during configure
+- README.ASIC: Document how to use Monarch in a PCI-Express arrangement on Linux
+- lowl-pci/vfio: Support pread/pwrite access to bars
+- lowl-pci: Support for vfio
+- Abstract UIO-specific code from bitforce driver into lowl-pci
+- bitforce: Initialise lasttag based on response register
+- bitforce: Tie in UIO with lowl-pci
+- lowl-pci: New lowlevel driver for raw PCI devices
+- util: bfg_slurp_file function to quickly read a file
+- bitforce: Support for PCI interface via UIO
+- bitforce: Hide vcom interfaces behind new struct bitforce_lowl_interface
+- bitforce: Let the lowlevel interface deal only with the actual device
+cgpu_info
+- bitforce: Abstract most of VCOM layer away from driver code
+- bitforce: Avoid checking fd by adding is_open flag
+- bitforce: Replace BF{open,close} with more abstract bitforce_vcom_{open,close}
+- bitforce: Abstract fd access mostly down to BFgets/BFwrite
+- bitforce: Support for 28nm WX single-stage bulkqueue command
+- bitforce: Use enum for style (FPGA vs SC)
+- bitforce: Remove never-used and buggy "work queue" mode
+- Round temperature to an integer in thermal cutoff warning
+- Bugfix: icarus: Initialise read_count and other timing-related variables
+- Change default log interval to 20 seconds
+- hashfast: Bump default thermal cutoff temperature to 100 C
+- Bugfix: DevAPI: Ensure temp-cutoff and temp-target are always supported
+settings
+- Bugfix: Initialise cutoff and target temperatures in allocate_cgpu if not
+initialised by the driver
+- Include temperature in thermal cutoff warning
+- Avoid automatic rescans when hotplug is disabled
+- nanofury: New "ledmode" RPC setting, to control LED behaviour
+- nanofury: Support for changing baud rate
+- nanofury: Detect number of chips, so multiple can be used
+- bitfury: When detecting chips, oscillate slower and tolerate clocks outside of
+a predefined range
+- Default --quit-summary to devs if there are more than 24 processors
+- Control printing of quit device summary with --quit-summary option
+- bitfury: Migrate all drivers to set_device_funcs interface
+- drv_set_defaults: Take devpath and serial params so matching by those can work
+- avalon: Replace avalon-options with set_device_funcs
+- klondike: Replace klondike-options with set_device_funcs
+- Replace temp-cutoff and temp-target parameters with set-device options
+- README.FPGA: Update documentation for Icarus driver
+- icarus: Replace icarus-timing with set_device_funcs (including wrapper for
+single icarus-timing case)
+- icarus: Replace icarus-options with set_device_funcs (including wrapper for
+single icarus-options case)
+- drv_set_defaults2 function to work with set_device_funcs
+- icarus: Clarify user_set flags with an enum
+- icarus: Clarify reopen modes with an enum
+- Accept parameter to set_device "help" as a request for help on a specific
+setting
+- set_device_funcs support for returning messages on success
+- RPC: Support for alternate message strings
+- bitfurce: Use new set_device_funcs interface
+- Refactor set_device interface to use option arrays
+- configure: Turn _Static_assert into a noop if the compiler lacks support
+- Store when the last getwork was retrieved and display it in the API summary.
+- bitforce: Consistently use fd -1 when device is not open
+- hashfast: Support for voltage in RPC stats
+- hashfast: Support for voltage displayed in ManageTUI
+- hashfast: Support for temperature
+- Trigger automatic rescans if an expected probe fails (assuming the device just
+needs more time to initialise)
+- Schedule rescan after a 1 second delay, should it be requested twice
+- hotplug: Wait 100ms before rescanning, so plugging in a hub can be handled at
+once and drivers have time to finish initialisation
+- Linux hotplug: Ignore EAGAIN and EINTR from epoll_wait so debugging works
+- Common hotplug_trigger function to use regardless of platform-specific
+implementation
+- Autoscan for new devices on Linux using libudev
+- Autoscan for new devices on Windows when DBT_DEVNODES_CHANGED message is
+broadcast
+- Replace suffix_string with a wrapper around format_unit3
+- Skip lowlevel-based scans in scrypt mode
+- README.GPU: Document new opencl autodetect behaviour
+- opencl: Enable by default in scrypt mode
+
+
+BFGMiner Version 3.10.1 - May 26, 2014
+
+- Upgraded Windows libraries:
+- - libcurl from 7.34.0 to 7.37.0 (and SSL support enabled)
+- - libjansson from 2.4 to 2.6
+- - libmicrohttpd from 0.9.30 to 0.9.35 (now Win64 also)
+- - libusb from libusbx 1.0.17 to 1.0.18
+- DevAPI: for_each_{managed,logical}_proc helper macros
+- Update libblkmaker to 0.3.3
+- make-release: Copy submodules from local system
+- make-release: Automatically determine DLL dependencies to include
+- Bugfix: littlefury: Avoid memory leak for already-claimed devices
+- Bugfix: drillbit: Avoid 9-byte memory leak for already-claimed devices
+- Bugfix: lowl-ftdi: ft232r_close: Free device handle
+- Bugfix: bitfury: Avoid memory leaks when detect fails
+- Bugfix: klondike: Correct case of dname
+- Bugfix: hashfast: Set LIFE_INIT2 so a dead engine doesn't hold up the stats
+line
+- Bugfix: bitforce: Restore device name loading for FPGA Singles
+- Bugfix: Add config.h include to files missing it
+- Bugfix: swap32to?e: Ensure conditionals always have the same type
+- Bugfix: Protect prev_cancelstate variables under console lock
+- opencl: Silence warning about duplicate const qualifier
+- hashbuster: Avoid signed char problems in return status check
+- Bugfix: bfg_claim_any: Use a mutex to avoid races around device claims
+- SSM: Silence JSON parse error message for HTTP POST and TLS attempts
+- bifury: Defer precision loss until after checking osc6_bits value
+- opencl: bfg_clBuildProgram function to share common error handling (logging)
+code
+- opencl: Avoid printing empty build logs
+- Bugfix: opencl: Free allocated memory when done with it
+- Bugfix: Stratum: Use an error buffer on struct pool rather than the stack, so
+it remains valid for the lifetime of the connection
+- Bugfix: Reset tv_idle on pools after test failure
+- Bugfix: Ignore last work time if pool is known to be down
+- pick_unit: Avoid infinite loop when passed inf float
+- Bugfix: bitfury: Correct comment about how much of the nonce range chips
+process
+- Bugfix: Initialise getq (and stgd_lock) earlier so it is ready in case startup
+interactive pool-add tries to stage work
+- bitfury: Wait for two low frequency measurements before acting on a freq drop
+(in case of a single misread)
+- Bugfix: SSM: decref parsed JSON when done with it
+- knc: Replace numeric constants with KNC_CORES_PER_DIE, KNC_DIE_PER_CHIP, and
+KNC_CORES_PER_CHIP defines
+- Bugfix: knc: Actually skip over extra processors rather than infinite loop
+- Bugfix: Use rlim_t type for old_soft_limit so comparison with RLIM_INFINITY is
+correct on all platforms
+- Update alloca logic to work on more platforms
+- start-bfgminer.sh: Shell script to (re)start bfgminer in a background screen
+session
+- Bugfix: Handle disabled CPU support properly in various places
+- Bugfix: README.ASIC: KnCMiner: Use supported Angstrom feeds only
+- Bugfix: pool_active: Skip testing explicitly when we have a recent answer
+- RPC: Use struct timeval for mcast bind timer
+- Bugfix: Restore 2-minutes-past-last-work wait before terminating unused
+stratum connections
+- Partial: Bugfix: Turn spidevc into lowl-spi to fix building the knc driver
+without the bitfury driver
+- SSM: Silence JSON parse error message for HTTP attempts
+- Bugfix: Use UTF-8 for micro prefix internally (and in logging)
+- Consistently allocate space used for formatting numbers
+- util: utf8_len and utf8_strlen functions to quickly measure a character or
+string
+- Bugfix: README: Add missing driver build configuration options
+- Bugfix: renumber_cgpu: No need to copy dev_repr over itself (and trying to is
+undefined)
+- Move OpenCL kernel FAQ to README.GPU and clarify it a bit
+- Bugfix: Log work updates for all active pools in multipool mode
+- test_work_current: Cleanup
+- Bugfix: Differentiate pool_actively_desired from pool_actively_in_use for
+cnx_needed
+- Abstract pool_actively_in_use to handle multipool checking for multiple uses
+- Bugfix: antminer: Fix typo
+- Bugfix: renumber_cgpu: Rebuild repr strings to match new information
+- Bugfix: Skip final pool_active check in balancing modes (where pools switch
+around often)
+- Bugfix: Adjust quota GCD only after completely adding the pool, otherwise it
+will be ignored by the adjustment
+- Bugfix: opencl: Can only BFI_INT patch if using OpenCL binaries
+- SGW: Support for scrypt
+- README: Document VCOM low_latency flag and latency_timer sysfs attribute,
+which can help run more VCOM-based devices on low-end USB hosts
+- Add USB faqs.
+- Bugfix: Stratum: Wait a bit for a response before assuming the pool is hiding
+block contents
+- README: FAQ about Raspberry Pi issues
+- Check for when errno is set on windows as well as the windows variant for
+errors.
+- Partial: Handle interruptions to various select calls in util.c
+- Bugfix: configure: Only fail due to not having libusb, if the user really
+needs or wants libusb
+- Bugfix: Update help display to replace (U)tility with (I)ncome
+- Bugfix: Deduplicate % symbols in help display
+- Bugfix: Correct documentation for --shares option
+- cpu/scrypt: Fix last_nonce to be host endian also
+- Bugfix: cpu: Correct results found by scrypt algorithm
+- Bugfix: lowl-vcom: _get_osfhandle failure returns INVALID_HANDLE_VALUE, not
+NULL
+- Bugfix: lowl-vcom: Invalid fd checks should be for -1, not 0
+- Bugfix: SSM: Actually acquire and release extranonce1s
+- Bugfix: C reserves identifiers beginning with an underscore and uppercase
+letter or another underscore
+- Skip trying to submit shares in benchmark mode
+- Rework benchmark mode
+- Bugfix: configure: Only pull in lowl-usb for lowl-vcom if libusb is available
+- Bugfix: hashfast: Ensure size of hex data passed to applog is of type int
+- README.ASIC: Update "SGW" virtual device identifier to current "PXY"
+- Bugfix: klondike: Reenable hw error reporting on nonces found for unknown work
+- Bugfix: Expand deprecated work->subid field to int width, needed by klondike
+driver for tracking work
+- Bugfix: erupter: Sapphire detected as Emerald and Emerald not detected
+- configure: Remove duplicate sys/file.h check
+- Bugfix: httpsrv: Add missing includes for stdarg, stddef, stdio, and stdlib
+- hashbusterusb: Initialise send packets fully to avoid leaking uninitialised
+data to devices
+- Bugfix: Correct typo in --help ("AlgoritHms")
+- Bugfix: twinfury: Avoid crashing when next_work is not populated here
+- Bugfix: hashbusterusb: Close device after failures
+- Bugfix: hashbuster: Close device after failures
+- README: List --quota in options
+- README.ASIC: Update documentation for Avalon
+- Bugfix: Leave thr->*work alone when disabling non-minerloop_async devices
+- udev rules: Set flag so ModemManager ignores devices
+- bifury: Thermal overheat causes restart losing the clock, so resend it while
+temperature is over 80 C
+- bitforce: Explicitly assign indexes for bitforce_proto enum
+- Bugfix: RPC: MSG_PGASETOK does not have a string param
+- littlefury: Close device if there are any communication problems
+- littlefury: Abstract out littlefury_set_power
+- Bugfix: hashfast: Add missing serial_claim
+- Bugfix: drillbit: Add missing serial_claim
+- Bugfix: bifury: Add missing serial_claim
+- Bugfix: littlefury: Add missing serial_claim
+- Bugfix: Allocate all new devices completely, before trying to activate any
+(since the first processor may control the secondary ones)
+- Since scrypt miners tend to work at actual share difficulty, use that for
+diff1 counting
+- Bugfix: diff1 measurements should be increased by nonce difficulty, not share
+difficulty
+- drillbit: strtol into a long int so negative responses properly get an error
+- Rename *nonces variables to *_diff1 to reflect their nature better
+- Refactor diff1 records to properly weigh non-diff1 work
+- AUTHORS: Add Nico Oelgart
+- Fixed multiple XSS injection vectors
+- drillbit: Expand allowed external clock range to 0-65535
+
+
 BFGMiner Version 3.10.0 - January 15, 2014
 BFGMiner Version 3.10.0 - January 15, 2014
 
 
 - Downgrade official Windows build compiler to GCC 4.7.3.
 - Downgrade official Windows build compiler to GCC 4.7.3.

+ 44 - 8
README

@@ -136,6 +136,9 @@ Optional Dependencies:
 BFGMiner driver configuration options:
 BFGMiner driver configuration options:
 	--disable-other-drivers Build without drivers by default unless explicitly
 	--disable-other-drivers Build without drivers by default unless explicitly
 	                        enabled
 	                        enabled
+	--enable-broad-udevrules
+	                        Include udev rules for ambiguous devices which may
+	                        not be miners
 	--disable-avalon        Compile support for Avalon (default enabled)
 	--disable-avalon        Compile support for Avalon (default enabled)
 	--enable-bfsb           Compile support for BFSB (default disabled)
 	--enable-bfsb           Compile support for BFSB (default disabled)
 	--disable-bfx           Compile support for BFx2 (default if libusb)
 	--disable-bfx           Compile support for BFx2 (default if libusb)
@@ -155,6 +158,7 @@ BFGMiner driver configuration options:
 	                        libusb)
 	                        libusb)
 	--disable-hashfast      Compile support for HashFast (default enabled)
 	--disable-hashfast      Compile support for HashFast (default enabled)
 	--disable-icarus        Compile support for Icarus (default enabled)
 	--disable-icarus        Compile support for Icarus (default enabled)
+	--enable-jingtian       Compile support for JingTian (default disabled)
 	--disable-klondike      Compile support for Klondike (default enabled)
 	--disable-klondike      Compile support for Klondike (default enabled)
 	--enable-knc            Compile support for KnC (default disabled)
 	--enable-knc            Compile support for KnC (default disabled)
 	--disable-littlefury    Compile support for LittleFury (default enabled)
 	--disable-littlefury    Compile support for LittleFury (default enabled)
@@ -163,9 +167,12 @@ BFGMiner driver configuration options:
 	--disable-nanofury      Compile support for NanoFury (default enabled)
 	--disable-nanofury      Compile support for NanoFury (default enabled)
 	--enable-opencl         Compile support for OpenCL (default disabled)
 	--enable-opencl         Compile support for OpenCL (default disabled)
 	--disable-adl           Build without ADL monitoring (default enabled)
 	--disable-adl           Build without ADL monitoring (default enabled)
+	--disable-rockminer     Compile support for RockMiner (default enabled)
 	--disable-twinfury      Compile support for Twinfury USB miner (default
 	--disable-twinfury      Compile support for Twinfury USB miner (default
 	                        enabled)
 	                        enabled)
 	--disable-x6500         Compile support for X6500 (default if libusb)
 	--disable-x6500         Compile support for X6500 (default if libusb)
+	--disable-zeusminer     Compile support for ZeusMiner (default enabled with
+	                        scrypt)
 	--disable-ztex          Compile support for ZTEX (default if libusb)
 	--disable-ztex          Compile support for ZTEX (default if libusb)
 
 
 BFGMiner algorithm configuration option:
 BFGMiner algorithm configuration option:
@@ -184,6 +191,9 @@ BFGMiner dependency configuration options:
 	                        Use system libblkmaker rather than bundled one
 	                        Use system libblkmaker rather than bundled one
 	                        (default disabled)
 	                        (default disabled)
 	--with-udevrulesdir=DIR Install udev rules into this directory
 	--with-udevrulesdir=DIR Install udev rules into this directory
+	--with-udevrules-group=groupname
+	                        Configure mining devices to be owned by a specific
+	                        group (default `video')
 	--without-uio           Compile support for PCI devices via Linux UIO
 	--without-uio           Compile support for PCI devices via Linux UIO
 	                        interface (default enabled)
 	                        interface (default enabled)
 	--without-vfio          Compile support for PCI devices via Linux VFIO
 	--without-vfio          Compile support for PCI devices via Linux VFIO
@@ -230,11 +240,13 @@ Options for both config file and command line:
 --api-mcast         Enable API Multicast listener, default: disabled
 --api-mcast         Enable API Multicast listener, default: disabled
 --api-mcast-addr <arg> API Multicast listen address (default: "224.0.0.75")
 --api-mcast-addr <arg> API Multicast listen address (default: "224.0.0.75")
 --api-mcast-code <arg> Code expected in the API Multicast message, don't use '-' (default: "FTW")
 --api-mcast-code <arg> Code expected in the API Multicast message, don't use '-' (default: "FTW")
+--api-mcast-des <arg>  Description appended to the API Multicast reply, default: ''
 --api-mcast-port <arg> API Multicast listen port (default: 4028)
 --api-mcast-port <arg> API Multicast listen port (default: 4028)
 --api-network       Allow API (if enabled) to listen on/for any address (default: only 127.0.0.1)
 --api-network       Allow API (if enabled) to listen on/for any address (default: only 127.0.0.1)
 --api-port          Port number of miner API (default: 4028)
 --api-port          Port number of miner API (default: 4028)
 --balance           Change multipool strategy from failover to even share balance
 --balance           Change multipool strategy from failover to even share balance
 --benchmark         Run BFGMiner in benchmark mode - produces no shares
 --benchmark         Run BFGMiner in benchmark mode - produces no shares
+--benchmark-intense Run BFGMiner in intensive benchmark mode - produces no shares
 --chroot-dir <arg>  Chroot to a directory right after startup
 --chroot-dir <arg>  Chroot to a directory right after startup
 --cmd-idle <arg>    Execute a command when a device is allowed to be idle (rest or wait)
 --cmd-idle <arg>    Execute a command when a device is allowed to be idle (rest or wait)
 --cmd-sick <arg>    Execute a command when a device is declared sick
 --cmd-sick <arg>    Execute a command when a device is declared sick
@@ -244,12 +256,14 @@ Options for both config file and command line:
 --compact           Use compact display without per device statistics
 --compact           Use compact display without per device statistics
 --debug|-D          Enable debug output
 --debug|-D          Enable debug output
 --debuglog          Enable debug logging
 --debuglog          Enable debug logging
+--device-protocol-dump Verbose dump of device protocol-level activities
 --device|-d <arg>   Enable only devices matching pattern (default: all)
 --device|-d <arg>   Enable only devices matching pattern (default: all)
 --disable-rejecting Automatically disable pools that continually reject shares
 --disable-rejecting Automatically disable pools that continually reject shares
 --http-port <arg>   Port number to listen on for HTTP getwork miners (-1 means disabled) (default: -1)
 --http-port <arg>   Port number to listen on for HTTP getwork miners (-1 means disabled) (default: -1)
 --expiry <arg>      Upper bound on how many seconds after getting work we consider a share from it stale (w/o longpoll active) (default: 120)
 --expiry <arg>      Upper bound on how many seconds after getting work we consider a share from it stale (w/o longpoll active) (default: 120)
 --expiry-lp <arg>   Upper bound on how many seconds after getting work we consider a share from it stale (with longpoll active) (default: 3600)
 --expiry-lp <arg>   Upper bound on how many seconds after getting work we consider a share from it stale (with longpoll active) (default: 3600)
 --failover-only     Don't leak work to backup pools when primary pool is lagging
 --failover-only     Don't leak work to backup pools when primary pool is lagging
+--failover-switch-delay <arg> Delay in seconds before switching back to a failed pool (default: 300)
 --force-dev-init    Always initialize devices when possible (such as bitstream uploads to some FPGAs)
 --force-dev-init    Always initialize devices when possible (such as bitstream uploads to some FPGAs)
 --kernel-path <arg> Specify a path to where bitstream and kernel files are
 --kernel-path <arg> Specify a path to where bitstream and kernel files are
 --load-balance      Change multipool strategy from failover to quota based balance
 --load-balance      Change multipool strategy from failover to quota based balance
@@ -260,6 +274,8 @@ Options for both config file and command line:
 --net-delay         Impose small delays in networking to avoid overloading slow routers
 --net-delay         Impose small delays in networking to avoid overloading slow routers
 --no-gbt            Disable getblocktemplate support
 --no-gbt            Disable getblocktemplate support
 --no-getwork        Disable getwork support
 --no-getwork        Disable getwork support
+--no-hotplug        Disable hotplug detection
+--no-local-bitcoin  Disable adding pools for local bitcoin RPC servers
 --no-longpoll       Disable X-Long-Polling support
 --no-longpoll       Disable X-Long-Polling support
 --no-pool-redirect  Ignore pool requests to redirect to another server
 --no-pool-redirect  Ignore pool requests to redirect to another server
 --no-restart        Do not attempt to restart devices that hang
 --no-restart        Do not attempt to restart devices that hang
@@ -269,6 +285,7 @@ Options for both config file and command line:
 --noncelog <arg>    Create log of all nonces found
 --noncelog <arg>    Create log of all nonces found
 --pass|-p <arg>     Password for bitcoin JSON-RPC server
 --pass|-p <arg>     Password for bitcoin JSON-RPC server
 --per-device-stats  Force verbose mode and output per-device statistics
 --per-device-stats  Force verbose mode and output per-device statistics
+--pool-priority <arg> Priority for just the previous-defined pool
 --pool-proxy|-x     Proxy URI to use for connecting to just the previous-defined pool
 --pool-proxy|-x     Proxy URI to use for connecting to just the previous-defined pool
 --protocol-dump|-P  Verbose dump of protocol-level activities
 --protocol-dump|-P  Verbose dump of protocol-level activities
 --queue|-Q <arg>    Minimum number of work items to have queued (0 - 10) (default: 1)
 --queue|-Q <arg>    Minimum number of work items to have queued (0 - 10) (default: 1)
@@ -276,7 +293,6 @@ Options for both config file and command line:
 --quit-summary <arg> Summary printed when you quit: none/devs/procs/detailed
 --quit-summary <arg> Summary printed when you quit: none/devs/procs/detailed
 --quota|-U <arg>    quota;URL combination for server with load-balance strategy quotas
 --quota|-U <arg>    quota;URL combination for server with load-balance strategy quotas
 --real-quiet        Disable all output
 --real-quiet        Disable all output
---remove-disabled   Remove disabled devices entirely, as if they didn't exist
 --request-diff <arg> Request a specific difficulty from pools (default: 1.0)
 --request-diff <arg> Request a specific difficulty from pools (default: 1.0)
 --retries <arg>     Number of times to retry failed submissions before giving up (-1 means never) (default: -1)
 --retries <arg>     Number of times to retry failed submissions before giving up (-1 means never) (default: -1)
 --rotate <arg>      Change multipool strategy from failover to regularly rotate at N minutes (default: 0)
 --rotate <arg>      Change multipool strategy from failover to regularly rotate at N minutes (default: 0)
@@ -304,9 +320,12 @@ Options for both config file and command line:
 --verbose           Log verbose output to stderr as well as status output
 --verbose           Log verbose output to stderr as well as status output
 --weighed-stats     Display statistics weighed to difficulty 1
 --weighed-stats     Display statistics weighed to difficulty 1
 --userpass|-O <arg> Username:Password pair for bitcoin JSON-RPC server
 --userpass|-O <arg> Username:Password pair for bitcoin JSON-RPC server
+--worktime                     Display extra work time debug information
 Options for command line only:
 Options for command line only:
 --config|-c <arg>   Load a JSON-format configuration file
 --config|-c <arg>   Load a JSON-format configuration file
 See example.conf for an example configuration.
 See example.conf for an example configuration.
+--no-default-config Inhibit loading default config file
+--default-config    Always load the default config file
 --help|-h           Print this message
 --help|-h           Print this message
 --version|-V        Display version and exit
 --version|-V        Display version and exit
 
 
@@ -536,13 +555,17 @@ BFGMiner supports solo mining with any GBT-compatible bitcoin node (such as
 bitcoind). To use this mode, you need to specify the URL of your bitcoind node
 bitcoind). To use this mode, you need to specify the URL of your bitcoind node
 using the usual pool options (--url, --userpass, etc), and the --coinbase-addr
 using the usual pool options (--url, --userpass, etc), and the --coinbase-addr
 option to specify the Bitcoin address you wish to receive the block rewards
 option to specify the Bitcoin address you wish to receive the block rewards
-mined. If you are solo mining with more than one instance of BFGMiner (or any
-other software) per payout address, you must also specify data using the
+mined. When you run Bitcoin Core on the same computer as your miner, the pool
+itself will be automatically configured for you.
+
+IMPORTANT: If you are solo mining with more than one instance of BFGMiner (or
+any other software) per payout address, you must also specify data using the
 --coinbase-sig option to ensure each miner is working on unique work. Note
 --coinbase-sig option to ensure each miner is working on unique work. Note
 that this data will be publicly seen if your miner finds a block using any
 that this data will be publicly seen if your miner finds a block using any
-GBT-enabled pool, even when not solo mining (such as failover). If your
-bitcoin node does not support longpolling (for example, bitcoind 0.8.x), you
-should consider setting up a failover pool to provide you with block
+GBT-enabled pool, even when not solo mining (such as failover).
+
+If your bitcoin node does not support longpolling (for example, bitcoind 0.8.x),
+you should consider setting up a failover pool to provide you with block
 notifications. Note that solo mining does not use shares, so BFGMiner's adjusted
 notifications. Note that solo mining does not use shares, so BFGMiner's adjusted
 hashrate (third column) may suddenly drop to zero if a block you submit is
 hashrate (third column) may suddenly drop to zero if a block you submit is
 rejected; this does not indicate that it has stopped mining.
 rejected; this does not indicate that it has stopped mining.
@@ -763,8 +786,21 @@ Q: What happened to CPU mining?
 A: See README.CPU for more information.
 A: See README.CPU for more information.
 
 
 Q: Is there a GUI version?
 Q: Is there a GUI version?
-A: Yes, Nate Woolls maintains a GUI interface for BFGMiner called MultiMiner,
-available at http://multiminerapp.com
+A: Yes, there are a number of GUI interfaces for BFGMiner:
+Name        Website                                Operating system(s)
+----        -------                                -------------------
+EasyMiner   http://www.butterflylabs.com/drivers/  Android, Linux, Windows
+MacMiner    http://fabulouspanda.co.uk/macminer/   Mac
+MultiMiner  http://www.multiminerapp.com/          Linux, Mac, Windows (.NET)
+
+Q: Is there a "bare-metal" version?
+A: Yes, there are a few dedicated mining operating systems built on BFGMiner:
+Name        Website                              Hardware
+----        -------                              --------
+Controla    http://hashra.com/support            Raspberry Pi
+MinePeon    http://mineforeman.com/minepeon/     BeagleBone Black, Raspberry Pi
+Minera      http://getminera.com/                Raspberry Pi
+PiMP        http://getpimp.org/                  x86
 
 
 Q: I'm having an issue. What debugging information should I provide?
 Q: I'm having an issue. What debugging information should I provide?
 A: Start BFGMiner with your regular commands and add -D -T --verbose and provide
 A: Start BFGMiner with your regular commands and add -D -T --verbose and provide

+ 109 - 17
README.ASIC

@@ -3,11 +3,11 @@ 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, Klondike modules, and
 Butterfly Labs' SC range of devices, HashBuster boards, Klondike modules, and
-KnCminer's Mercury, Jupiter and Saturn.
+KnCMiner's Mercury, Jupiter and Saturn.
 
 
 
 
-AVALON
-------
+AVALON 1
+--------
 
 
 Currently, Avalon boards are best supported by connecting them directly (or via
 Currently, Avalon boards are best supported by connecting them directly (or via
 a hub) to a regular PC running BFGMiner. It is also possible to install the
 a hub) to a regular PC running BFGMiner. It is also possible to install the
@@ -47,6 +47,26 @@ Sample settings for valid different frequencies (last 2 values):
 50:256
 50:256
 
 
 
 
+AVALON 2/3
+----------
+
+Avalon 2/3 units communicate with a UART, usually attached to your host via a
+generic USB UART adapter. Therefore, you will need to manually probe the correct
+UART device with the -S option:
+
+-S avalonmm:\\.\COM22
+
+Next, use the --set option to configure at least your desired clock frequency
+and voltage.
+
+Avalon 2: --set avalonmm:clock=1500 --set avalonmm:voltage=1
+Avalon 3: --set avalonmm:clock=450 --set avalonmm:voltage=0.6625
+
+You may also want to set the fan speed, which is specified as a percentage:
+
+--set avalonmm:fan=95
+
+
 BFSB, MEGABIGPOWER, AND METABANK BITFURY BOARDS
 BFSB, MEGABIGPOWER, AND METABANK BITFURY BOARDS
 -----------------------------------------------
 -----------------------------------------------
 
 
@@ -123,6 +143,19 @@ ports. They communicate with the Icarus protocol, which has some additional
 options in README.FPGA
 options in README.FPGA
 
 
 
 
+HEX*FURY
+--------
+
+Hex*Fury uses the bifury driver. Miners using earlier boards may need to
+workaround bugs in the firmware:
+    bfgminer --set bifury:chips=6 --set bifury:free_after_job=no
+This may cause poor behaviour or performance from other bifury-based devices.
+If you encounter this, you can set the workarounds per-device by using their
+serial number (which can be seen in the TUI device manager; in this example,
+141407160211cdf):
+    bfgminer --set bifury@141407160211cdf:chips=15 ...
+
+
 KLONDIKE
 KLONDIKE
 --------
 --------
 
 
@@ -132,10 +165,12 @@ KLONDIKE
 KNCMINER
 KNCMINER
 --------
 --------
 
 
-The KnC miner uses a BeagleBoneBlack(BBB) as the host, this is pluged into a
-cape that holds the FPGA and connections for 4-6 ASICS depending on the cape
-version. The BBB runs the Angstrom linux distribution, the following is a step
-by step install for BFGMiner on this distro;
+KnCMiner rigs use a BeagleBone Black (BBB) as the host; this is pluged into a
+"cape" with a FPGA and connections for 4-6 ASIC modules (depending on the cape
+version). Note that in addition to the usual dependencies, this driver also
+requires i2c-tools (aka libi2c-dev on some systems). The BBB comes with the
+Ångström Distribution by default. The following is a step by step install for
+BFGMiner on this system;
 
 
 -----------------Start------------
 -----------------Start------------
 cat >/etc/opkg/feeds.conf <<\EOF
 cat >/etc/opkg/feeds.conf <<\EOF
@@ -171,8 +206,6 @@ make AR=arm-angstrom-linux-gnueabi-ar
 
 
 ---------------END-------------
 ---------------END-------------
 
 
-BFGMiner has also been incorporated into an unofficial firmware by uski01 called Bertmod this can be found on the kncminer forum.
-
 
 
 MONARCH
 MONARCH
 -------
 -------
@@ -187,26 +220,85 @@ To enable uio on your cards, you may need to do:
     sudo modprobe uio_pci_generic
     sudo modprobe uio_pci_generic
     echo 1cf9 0001 | sudo tee /sys/bus/pci/drivers/uio_pci_generic/new_id
     echo 1cf9 0001 | sudo tee /sys/bus/pci/drivers/uio_pci_generic/new_id
 
 
-Enabling vfio is similar, but more complicated, but allows you to run BFGMiner
-without root privileges. First, load the kernel module and tell it to accept the
-Monarch:
+Enabling vfio is similar, but allows you to run BFGMiner without root
+privileges. Since setting this up is more complicated, BFGMiner includes a
+setup-vfio script (which must be run with root permissions). Simply run:
+    sudo setup-vfio --unsafe --user $(whoami) 1cf9 0001
+You will be asked about each Monarch found, and must answer 'yes' to each one.
+
+If you wish to manually setup VFIO, follow these steps:
+First, load the kernel module:
     sudo modprobe vfio-pci
     sudo modprobe vfio-pci
-    echo 1cf9 0001 | sudo tee /sys/bus/pci/drivers/vfio-pci/new_id
 Next, identify what the device ids are for your card(s):
 Next, identify what the device ids are for your card(s):
     lspci -D | grep 1cf9  # the first number of each line is the device id
     lspci -D | grep 1cf9  # the first number of each line is the device id
 From that, you can identify its IOMMU group, and list all devices sharing that
 From that, you can identify its IOMMU group, and list all devices sharing that
 group:
 group:
-    readlink /sys/bus/pci/devices/<device_id>/iommu_group
-    ls /sys/kernel/iommu_groups/<iommu_group>/devices/
+    readlink "/sys/bus/pci/devices/$DEVICE_ID/iommu_group"
+    ls "/sys/kernel/iommu_groups/$IOMMU_GROUP_ID/devices/"
 All of the devices listed (other than the Monarch), if any, will need to be
 All of the devices listed (other than the Monarch), if any, will need to be
 disabled and unbound! To do that, use:
 disabled and unbound! To do that, use:
-    echo <device_id> | sudo tee /sys/bus/pci/devices/<device_id>/driver/unbind
+    echo "$DEVICE_ID" | sudo tee "/sys/bus/pci/devices/$DEVICE_ID/driver/unbind"
+    echo "$DEVICE_CODE" | sudo tee /sys/bus/pci/drivers/vfio-pci/new_id
+Note that $DEVICE_ID should be something like "0000:01:00.0" and $DEVICE_CODE is
+something like "1cf9 0001" (this example is the Monarch itself).
 If you want to run BFGMiner as a normal user:
 If you want to run BFGMiner as a normal user:
-    chown <username> /dev/vfio/<iommu_group>
+    chown "$USERNAME" "/dev/vfio/$IOMMU_GROUP_ID"
 Depending on your system, you may also need to do:
 Depending on your system, you may also need to do:
     echo 1 | sudo tee /sys/module/vfio_iommu_type1/parameters/allow_unsafe_interrupts
     echo 1 | sudo tee /sys/module/vfio_iommu_type1/parameters/allow_unsafe_interrupts
 
 
 
 
+ONESTRINGMINER
+--------------
+
+OneStringMiner boards use the bifury driver. Miners using earlier boards may
+need to workaround bugs in the firmware:
+    bfgminer --set bifury:chips=15 --set bifury:free_after_job=no
+If you have different devices using the bifury driver, see the section on
+Hex*Fury for applying workarounds per-device.
+
+
+GRIDSEED
+--------
+
+Gridseed units, at the present time, come in two versions: Blade - a 40 chip
+unit and Orb - a 5 chip unit. Orb units can be used to mine both SHA256d and
+scrypt based coins whereas the Blade is scrypt only, although BFGMiner only
+supports scrypt mode at this time.
+
+BFGMiner allows a miner to connect both types of units to a single miner
+instance and provides for granular control of the clock frequencies for each
+device and each chip on each device. The basic use of this feature is to use the
+--set option on from the command line:
+
+bfgminer --scrypt -S gridseed:all --set gridseed@<serial_number>:clock=825
+
+for multiple devices, add multiple --set arguments.
+
+Additionally, these can be added to the bfgminer.conf file for persistence like
+this:
+
+"set" : [
+        "gridseed@<serial_number>:clock=825",
+        "gridseed@<serial_number>:clock=850",
+        "gridseed@<serial_number>:clock=875"
+]
+
+To find the device serial number, start bfgminer and press <M> to manage
+devices, then <Page Down> or <down arrow> through the list of devices and take
+note of the device serial number in the device information shown.
+
+...
+Select processor to manage using up/down arrow keys
+ GSD 0a:       |  74.4/ 72.9/ 10.2kh/s | A:  1 R:0+0(none) HW:0/none
+  STM32 Virtual COM Port from STMicroelectronics
+Serial: 6D85278F5650
+Clock speed: 875
+...
+
+So for example, an entry would look like this:
+        gridseed@6D85278F5650:clock=875
+
+
 ---
 ---
 
 
 This code is provided entirely free of charge by the programmer in his spare
 This code is provided entirely free of charge by the programmer in his spare

+ 6 - 5
README.FPGA

@@ -110,10 +110,11 @@ a cost of 1% in overall hashrate so this feature is disabled by default. It
 is only recommended you enable this if you are mining with a Mini Rig on
 is only recommended you enable this if you are mining with a Mini Rig on
 P2Pool.
 P2Pool.
 
 
-BFGMiner also bundles a bitforce-firmware-flash utility on Linux. Using this,
-you can change the bitstream firmware on BitForce Singles. It is untested with
-other devices. Use at your own risk! Windows users may use Butterfly Labs
-EasyMiner to change firmware.
+BitFORCE FPGA Single units can have their bitstream modified using the
+bitforce-firmware-flash utility on Linux, which can be obtained from:
+    https://github.com/luke-jr/bitforce-fpga-firmware-flash
+It is untested with other devices. Use at your own risk! Windows users may use
+Butterfly Labs EasyMiner to change firmware.
 
 
 To compile:
 To compile:
  make bitforce-firmware-flash
  make bitforce-firmware-flash
@@ -129,7 +130,7 @@ it may have worked successfully anyway.
 Test mining on it to be sure if it worked or not.
 Test mining on it to be sure if it worked or not.
 
 
 You need to give BFGMiner about 10 minutes mining with the BFL to be sure of
 You need to give BFGMiner about 10 minutes mining with the BFL to be sure of
-the Mh/s value reported with the changed firmware - and the MH/s reported will
+the Mh/s value reported with the changed firmware - and the Mh/s reported will
 be less than the firmware speed since you lose work on every block change.
 be less than the firmware speed since you lose work on every block change.
 
 
 
 

+ 14 - 2
README.RPC

@@ -163,7 +163,9 @@ The list of requests - a (*) means it requires privileged access - and replies:
                               Failover-Only=true/false, <- failover-only setting
                               Failover-Only=true/false, <- failover-only setting
                               ScanTime=N, <- --scan-time setting
                               ScanTime=N, <- --scan-time setting
                               Queue=N, <- --queue setting
                               Queue=N, <- --queue setting
-                              Expiry=N| <- --expiry setting
+                              Expiry=N, <- --expiry setting
+                              Coinbase-Sig=X, <- extra coinbase data in blocks
+                              ConfigFileN=X| <- filename of configs loaded
 
 
  summary       SUMMARY        The status summary of the miner
  summary       SUMMARY        The status summary of the miner
                               e.g. Elapsed=NNN,Found Blocks=N,Getworks=N,...|
                               e.g. Elapsed=NNN,Found Blocks=N,Getworks=N,...|
@@ -436,6 +438,9 @@ api-example.py - a Python script to access the API.
  by default it sends a 'summary' request to the miner at 127.0.0.1:4028
  by default it sends a 'summary' request to the miner at 127.0.0.1:4028
  If you specify a command it will send that request instead.
  If you specify a command it will send that request instead.
 
 
+api-example.rb - a Ruby script to access the API.
+  usage: ruby api-example.rb command[:parameter] [HOST [PORT]]
+
 If you are using Node.js, you can also use the miner-rpc package and script:
 If you are using Node.js, you can also use the miner-rpc package and script:
 https://www.npmjs.org/package/miner-rpc
 https://www.npmjs.org/package/miner-rpc
 
 
@@ -444,7 +449,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.1
+API V3.2 (BFGMiner v4.1.0)
+
+Modified API command:
+ 'config' - add 'ConfigFile'N
+
+---------
+
+API V3.1 (BFGMiner v4.0.0)
 
 
 Multiple report request command with '+' e.g. summary+devs
 Multiple report request command with '+' e.g. summary+devs
 
 

+ 10 - 2
README.scrypt

@@ -99,7 +99,15 @@ all you will need to set.
 
 
 
 
 Optional parameters to tune:
 Optional parameters to tune:
-threads, thread-concurrency, lookup-gap
+kernel, threads, thread-concurrency, lookup-gap
+
+kernel:
+This selects the OpenCL code to use. By default, the kernel named "scrypt" will
+be used. BFGMiner also includes optimised versions from Zuikkis and Pavel
+Semjanov, which you can specify by filename:
+    --set-device OCL:kernel=zuikkis
+    --set-device OCL:kernel=psw
+Note that Zuikkis' version requires the default lookup-gap of 2.
 
 
 thread-concurrency:
 thread-concurrency:
 This tunes the optimal size of work that scrypt can do. It is internally tuned
 This tunes the optimal size of work that scrypt can do. It is internally tuned
@@ -133,7 +141,7 @@ SUMMARY: Worth playing with once everything else has been tried but will
 probably do nothing.
 probably do nothing.
 
 
 vectors=XX
 vectors=XX
-Vectors are NOT used by the scrypt mining kernel.
+Vectors are NOT used by scrypt mining kernels.
 SUMMARY: Does nothing.
 SUMMARY: Does nothing.
 
 
 
 

+ 1 - 1
adl.c

@@ -1,6 +1,6 @@
 /*
 /*
  * Copyright 2011-2013 Con Kolivas
  * Copyright 2011-2013 Con Kolivas
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free

+ 2 - 2
api-example.c

@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright 2011 Kano
- * Copyright 2013 Luke Dashjr
+ * Copyright 2011-2012 Andrew Smith
+ * Copyright 2012-2013 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free

+ 38 - 0
api-example.rb

@@ -0,0 +1,38 @@
+#!/usr/bin/env ruby
+
+# Copyright 2014 James Hilliard
+#
+# 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.
+
+require 'socket'
+require 'json'
+
+api_command = ARGV[0].split(":")
+
+if ARGV.length == 3
+	api_ip = ARGV[1]
+	api_port = ARGV[2]
+elsif ARGV.length == 2
+	api_ip = ARGV[1]
+	api_port = 4028
+else
+	api_ip = "127.0.0.1"
+	api_port = 4028
+end
+
+s = TCPSocket.open(api_ip, api_port)
+
+if api_command.count == 2
+	s.write({ :command => api_command[0], :parameter => api_command[1]}.to_json)
+else
+	s.write({ :command => api_command[0]}.to_json)
+end
+
+response = s.read.strip
+response = JSON.parse(response)
+
+puts response
+s.close

+ 74 - 40
api.c

@@ -1,7 +1,7 @@
 /*
 /*
- * Copyright 2011-2013 Andrew Smith
- * Copyright 2011-2013 Con Kolivas
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2011-2014 Andrew Smith
+ * Copyright 2011-2014 Con Kolivas
+ * Copyright 2012-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -16,6 +16,7 @@
 
 
 #include "config.h"
 #include "config.h"
 
 
+#include <math.h>
 #include <stdio.h>
 #include <stdio.h>
 #include <ctype.h>
 #include <ctype.h>
 #include <stdlib.h>
 #include <stdlib.h>
@@ -34,6 +35,7 @@
 #include "util.h"
 #include "util.h"
 #include "driver-cpu.h" /* for algo_names[], TODO: re-factor dependency */
 #include "driver-cpu.h" /* for algo_names[], TODO: re-factor dependency */
 #include "driver-opencl.h"
 #include "driver-opencl.h"
+#include "version.h"
 
 
 #define HAVE_AN_FPGA 1
 #define HAVE_AN_FPGA 1
 
 
@@ -1017,8 +1019,14 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
 				sprintf(buf, "%.15f", *((double *)(root->data)));
 				sprintf(buf, "%.15f", *((double *)(root->data)));
 				break;
 				break;
 			case API_DIFF:
 			case API_DIFF:
-				sprintf(buf, "%.8f", *((double *)(root->data)));
+			{
+				const double *fp = root->data;
+				if (fmod(*fp, 1.))
+					sprintf(buf, "%.8f", *fp);
+				else
+					sprintf(buf, "%.0f", *fp);
 				break;
 				break;
+			}
 			case API_BOOL:
 			case API_BOOL:
 				sprintf(buf, "%s", *((bool *)(root->data)) ? TRUESTR : FALSESTR);
 				sprintf(buf, "%s", *((bool *)(root->data)) ? TRUESTR : FALSESTR);
 				break;
 				break;
@@ -1268,9 +1276,9 @@ static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __
 	struct driver_registration *reg, *regtmp;
 	struct driver_registration *reg, *regtmp;
 	int pgacount = 0;
 	int pgacount = 0;
 	char *adlinuse = (char *)NO;
 	char *adlinuse = (char *)NO;
+	int i;
 #ifdef HAVE_ADL
 #ifdef HAVE_ADL
 	const char *adl = YES;
 	const char *adl = YES;
-	int i;
 
 
 	for (i = 0; i < nDevs; i++) {
 	for (i = 0; i < nDevs; i++) {
 		struct opencl_device_data * const data = gpus[i].device_data;
 		struct opencl_device_data * const data = gpus[i].device_data;
@@ -1321,6 +1329,14 @@ static void minerconfig(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __
 #if BLKMAKER_VERSION > 0
 #if BLKMAKER_VERSION > 0
 	root = api_add_string(root, "Coinbase-Sig", opt_coinbase_sig, true);
 	root = api_add_string(root, "Coinbase-Sig", opt_coinbase_sig, true);
 #endif
 #endif
+	
+	struct bfg_loaded_configfile *configfile;
+	i = 0;
+	LL_FOREACH(bfg_loaded_configfiles, configfile)
+	{
+		snprintf(buf, sizeof(buf), "ConfigFile%d", i++);
+		root = api_add_string(root, buf, configfile->filename, false);
+	}
 
 
 	root = print_data(root, buf, isjson, false);
 	root = print_data(root, buf, isjson, false);
 	io_add(io_data, buf);
 	io_add(io_data, buf);
@@ -1421,7 +1437,7 @@ static void devdetail_an(struct io_data *io_data, struct cgpu_info *cgpu, bool i
 	root = api_add_int(root, "Target Temperature", &cgpu->targettemp, false);
 	root = api_add_int(root, "Target Temperature", &cgpu->targettemp, false);
 	root = api_add_int(root, "Cutoff Temperature", &cgpu->cutofftemp, false);
 	root = api_add_int(root, "Cutoff Temperature", &cgpu->cutofftemp, false);
 
 
-	if (cgpu->drv->get_api_extra_device_detail)
+	if ((per_proc || cgpu->procs <= 1) && cgpu->drv->get_api_extra_device_detail)
 		root = api_add_extra(root, cgpu->drv->get_api_extra_device_detail(cgpu));
 		root = api_add_extra(root, cgpu->drv->get_api_extra_device_detail(cgpu));
 
 
 	root = print_data(root, buf, isjson, precom);
 	root = print_data(root, buf, isjson, precom);
@@ -1884,6 +1900,9 @@ static void poolstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m
 			case POOL_ENABLED:
 			case POOL_ENABLED:
 				if (pool->idle)
 				if (pool->idle)
 					status = (char *)DEAD;
 					status = (char *)DEAD;
+				else
+				if (pool->failover_only)
+					status = "Failover";
 				else
 				else
 					status = (char *)ALIVE;
 					status = (char *)ALIVE;
 				break;
 				break;
@@ -2309,7 +2328,7 @@ static void switchpool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
 	}
 	}
 
 
 	pool = pools[id];
 	pool = pools[id];
-	pool->enabled = POOL_ENABLED;
+	pool->failover_only = false;
 	cg_runlock(&control_lock);
 	cg_runlock(&control_lock);
 	switch_pools(pool);
 	switch_pools(pool);
 
 
@@ -2422,14 +2441,13 @@ static void enablepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
 	}
 	}
 
 
 	pool = pools[id];
 	pool = pools[id];
-	if (pool->enabled == POOL_ENABLED) {
+	if (pool->enabled == POOL_ENABLED && !pool->failover_only) {
 		message(io_data, MSG_ALRENAP, id, NULL, isjson);
 		message(io_data, MSG_ALRENAP, id, NULL, isjson);
 		return;
 		return;
 	}
 	}
 
 
-	pool->enabled = POOL_ENABLED;
-	if (pool->prio < current_pool()->prio)
-		switch_pools(pool);
+	pool->failover_only = false;
+	enable_pool(pool);
 
 
 	message(io_data, MSG_ENAPOOL, id, NULL, isjson);
 	message(io_data, MSG_ENAPOOL, id, NULL, isjson);
 }
 }
@@ -2532,9 +2550,7 @@ static void disablepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, ch
 		return;
 		return;
 	}
 	}
 
 
-	pool->enabled = POOL_DISABLED;
-	if (pool == current_pool())
-		switch_pools(NULL);
+	disable_pool(pool, POOL_DISABLED);
 
 
 	message(io_data, MSG_DISPOOL, id, NULL, isjson);
 	message(io_data, MSG_DISPOOL, id, NULL, isjson);
 }
 }
@@ -2576,7 +2592,6 @@ static void removepool(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
 		return;
 		return;
 	}
 	}
 
 
-	pool->enabled = POOL_DISABLED;
 	rpc_url = escape_string(pool->rpc_url, isjson);
 	rpc_url = escape_string(pool->rpc_url, isjson);
 	if (rpc_url != pool->rpc_url)
 	if (rpc_url != pool->rpc_url)
 		dofree = true;
 		dofree = true;
@@ -3510,6 +3525,25 @@ static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson)
 		       (long)bytes_len(&io_data->data));
 		       (long)bytes_len(&io_data->data));
 }
 }
 
 
+static
+void _tidyup_socket(SOCKETTYPE * const sockp)
+{
+	if (*sockp != INVSOCK) {
+		shutdown(*sockp, SHUT_RDWR);
+		CLOSESOCKET(*sockp);
+		*sockp = INVSOCK;
+		free(sockp);
+	}
+}
+
+static
+void tidyup_socket(void * const arg)
+{
+	mutex_lock(&quit_restart_lock);
+	_tidyup_socket(arg);
+	mutex_unlock(&quit_restart_lock);
+}
+
 static void tidyup(__maybe_unused void *arg)
 static void tidyup(__maybe_unused void *arg)
 {
 {
 	mutex_lock(&quit_restart_lock);
 	mutex_lock(&quit_restart_lock);
@@ -3518,12 +3552,7 @@ static void tidyup(__maybe_unused void *arg)
 
 
 	bye = true;
 	bye = true;
 
 
-	if (*apisock != INVSOCK) {
-		shutdown(*apisock, SHUT_RDWR);
-		CLOSESOCKET(*apisock);
-		*apisock = INVSOCK;
-		free(apisock);
-	}
+	_tidyup_socket(apisock);
 
 
 	if (ipaccess != NULL) {
 	if (ipaccess != NULL) {
 		free(ipaccess);
 		free(ipaccess);
@@ -3839,7 +3868,7 @@ static void mcast()
 	struct sockaddr_in came_from;
 	struct sockaddr_in came_from;
 	struct timeval bindstart;
 	struct timeval bindstart;
 	const char *binderror;
 	const char *binderror;
-	SOCKETTYPE mcast_sock;
+	SOCKETTYPE *mcastsock;
 	SOCKETTYPE reply_sock;
 	SOCKETTYPE reply_sock;
 	socklen_t came_from_siz;
 	socklen_t came_from_siz;
 	char *connectaddr;
 	char *connectaddr;
@@ -3862,10 +3891,14 @@ static void mcast()
 		quit(1, "Invalid Multicast Address");
 		quit(1, "Invalid Multicast Address");
 	grp.imr_interface.s_addr = INADDR_ANY;
 	grp.imr_interface.s_addr = INADDR_ANY;
 
 
-	mcast_sock = socket(AF_INET, SOCK_DGRAM, 0);
-
+	mcastsock = malloc(sizeof(*mcastsock));
+	*mcastsock = INVSOCK;
+	pthread_cleanup_push(tidyup_socket, mcastsock);
+	
+	*mcastsock = bfg_socket(AF_INET, SOCK_DGRAM, 0);
+	
 	int optval = 1;
 	int optval = 1;
-	if (SOCKETFAIL(setsockopt(mcast_sock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval)))) {
+	if (SOCKETFAIL(setsockopt(*mcastsock, SOL_SOCKET, SO_REUSEADDR, (void *)(&optval), sizeof(optval)))) {
 		applog(LOG_ERR, "API mcast setsockopt SO_REUSEADDR failed (%s)%s", SOCKERRMSG, MUNAVAILABLE);
 		applog(LOG_ERR, "API mcast setsockopt SO_REUSEADDR failed (%s)%s", SOCKERRMSG, MUNAVAILABLE);
 		goto die;
 		goto die;
 	}
 	}
@@ -3879,7 +3912,7 @@ static void mcast()
 	bound = 0;
 	bound = 0;
 	timer_set_now(&bindstart);
 	timer_set_now(&bindstart);
 	while (bound == 0) {
 	while (bound == 0) {
-		if (SOCKETFAIL(bind(mcast_sock, (struct sockaddr *)(&listen), sizeof(listen)))) {
+		if (SOCKETFAIL(bind(*mcastsock, (struct sockaddr *)(&listen), sizeof(listen)))) {
 			binderror = SOCKERRMSG;
 			binderror = SOCKERRMSG;
 			if (timer_elapsed(&bindstart, NULL) > 61)
 			if (timer_elapsed(&bindstart, NULL) > 61)
 				break;
 				break;
@@ -3894,7 +3927,7 @@ static void mcast()
 		goto die;
 		goto die;
 	}
 	}
 
 
-	if (SOCKETFAIL(setsockopt(mcast_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)(&grp), sizeof(grp)))) {
+	if (SOCKETFAIL(setsockopt(*mcastsock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)(&grp), sizeof(grp)))) {
 		applog(LOG_ERR, "API mcast join failed (%s)%s", SOCKERRMSG, MUNAVAILABLE);
 		applog(LOG_ERR, "API mcast join failed (%s)%s", SOCKERRMSG, MUNAVAILABLE);
 		goto die;
 		goto die;
 	}
 	}
@@ -3911,10 +3944,10 @@ static void mcast()
 
 
 		count++;
 		count++;
 		came_from_siz = sizeof(came_from);
 		came_from_siz = sizeof(came_from);
-		if (SOCKETFAIL(rep = recvfrom(mcast_sock, buf, sizeof(buf) - 1,
+		if (SOCKETFAIL(rep = recvfrom(*mcastsock, buf, sizeof(buf) - 1,
 						0, (struct sockaddr *)(&came_from), &came_from_siz))) {
 						0, (struct sockaddr *)(&came_from), &came_from_siz))) {
 			applog(LOG_DEBUG, "API mcast failed count=%d (%s) (%d)",
 			applog(LOG_DEBUG, "API mcast failed count=%d (%s) (%d)",
-					count, SOCKERRMSG, (int)mcast_sock);
+					count, SOCKERRMSG, (int)*mcastsock);
 			continue;
 			continue;
 		}
 		}
 
 
@@ -3943,7 +3976,7 @@ static void mcast()
 							&buf[expect_code_len], reply_port);
 							&buf[expect_code_len], reply_port);
 
 
 				came_from.sin_port = htons(reply_port);
 				came_from.sin_port = htons(reply_port);
-				reply_sock = socket(AF_INET, SOCK_DGRAM, 0);
+				reply_sock = bfg_socket(AF_INET, SOCK_DGRAM, 0);
 
 
 				snprintf(replybuf, sizeof(replybuf),
 				snprintf(replybuf, sizeof(replybuf),
 							"cgm-%s-%d-%s",
 							"cgm-%s-%d-%s",
@@ -3961,6 +3994,7 @@ static void mcast()
 								replybuf, (int)rep, (int)reply_sock);
 								replybuf, (int)rep, (int)reply_sock);
 				}
 				}
 
 
+				shutdown(reply_sock, SHUT_RDWR);
 				CLOSESOCKET(reply_sock);
 				CLOSESOCKET(reply_sock);
 			}
 			}
 		} else
 		} else
@@ -3968,8 +4002,8 @@ static void mcast()
 	}
 	}
 
 
 die:
 die:
-
-	CLOSESOCKET(mcast_sock);
+	;  // statement in case pthread_cleanup_pop doesn't start with one
+	pthread_cleanup_pop(true);
 }
 }
 
 
 static void *mcast_thread(void *userdata)
 static void *mcast_thread(void *userdata)
@@ -4048,16 +4082,16 @@ void api(int api_thr_id)
 
 
 		if (ips == 0) {
 		if (ips == 0) {
 			applog(LOG_WARNING, "API not running (no valid IPs specified)%s", UNAVAILABLE);
 			applog(LOG_WARNING, "API not running (no valid IPs specified)%s", UNAVAILABLE);
-			return;
+			pthread_exit(NULL);
 		}
 		}
 	}
 	}
 
 
-	*apisock = socket(AF_INET, SOCK_STREAM, 0);
+	*apisock = bfg_socket(AF_INET, SOCK_STREAM, 0);
 	if (*apisock == INVSOCK) {
 	if (*apisock == INVSOCK) {
 		applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
 		applog(LOG_ERR, "API1 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
-		return;
+		pthread_exit(NULL);
 	}
 	}
-
+	
 	memset(&serv, 0, sizeof(serv));
 	memset(&serv, 0, sizeof(serv));
 
 
 	serv.sin_family = AF_INET;
 	serv.sin_family = AF_INET;
@@ -4066,7 +4100,7 @@ void api(int api_thr_id)
 		serv.sin_addr.s_addr = inet_addr(localaddr);
 		serv.sin_addr.s_addr = inet_addr(localaddr);
 		if (serv.sin_addr.s_addr == (in_addr_t)INVINETADDR) {
 		if (serv.sin_addr.s_addr == (in_addr_t)INVINETADDR) {
 			applog(LOG_ERR, "API2 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
 			applog(LOG_ERR, "API2 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
-			return;
+			pthread_exit(NULL);
 		}
 		}
 	}
 	}
 
 
@@ -4104,13 +4138,12 @@ void api(int api_thr_id)
 
 
 	if (bound == 0) {
 	if (bound == 0) {
 		applog(LOG_ERR, "API bind to port %d failed (%s)%s", port, binderror, UNAVAILABLE);
 		applog(LOG_ERR, "API bind to port %d failed (%s)%s", port, binderror, UNAVAILABLE);
-		return;
+		pthread_exit(NULL);
 	}
 	}
 
 
 	if (SOCKETFAIL(listen(*apisock, QUEUE))) {
 	if (SOCKETFAIL(listen(*apisock, QUEUE))) {
 		applog(LOG_ERR, "API3 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
 		applog(LOG_ERR, "API3 initialisation failed (%s)%s", SOCKERRMSG, UNAVAILABLE);
-		CLOSESOCKET(*apisock);
-		return;
+		pthread_exit(NULL);
 	}
 	}
 
 
 	if (opt_api_allow)
 	if (opt_api_allow)
@@ -4297,6 +4330,7 @@ inochi:
 					send_result(io_data, c, isjson);
 					send_result(io_data, c, isjson);
 			}
 			}
 		}
 		}
+		shutdown(c, SHUT_RDWR);
 		CLOSESOCKET(c);
 		CLOSESOCKET(c);
 	}
 	}
 die:
 die:

+ 6 - 1
autogen.sh

@@ -1,5 +1,5 @@
 #!/bin/sh -e
 #!/bin/sh -e
-# Written by Luke Dashjr in 2012
+# Written by Luke Dashjr in 2012-2014
 # This program is released under the terms of the Creative Commons "CC0 1.0 Universal" license and/or copyright waiver.
 # This program is released under the terms of the Creative Commons "CC0 1.0 Universal" license and/or copyright waiver.
 
 
 bs_dir="$(dirname "$0")"
 bs_dir="$(dirname "$0")"
@@ -23,3 +23,8 @@ echo 'Running autoreconf -if...'
 	rm -f aclocal.m4 ltmain.sh
 	rm -f aclocal.m4 ltmain.sh
 	autoreconf -if ${AC_FLAGS}
 	autoreconf -if ${AC_FLAGS}
 )
 )
+
+echo 'Updating version.h...'
+if ./gen-version.sh >version.h.new; then
+	cmp version.h version.h.new && rm version.h.new || mv version.h.new version.h
+fi

+ 0 - 108
bitforce-firmware-flash.c

@@ -1,108 +0,0 @@
-/*
- * Copyright 2012 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.
- */
-
-#define _BSD_SOURCE
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <libgen.h>
-#include <arpa/inet.h>
-
-#define BFL_FILE_MAGIC   "BFLDATA"
-#define BFL_UPLOAD_MAGIC "NGH-STREAM"
-
-#define myassert(expr, n, ...) \
-do {  \
-	if (!(expr)) {  \
-		fprintf(stderr, __VA_ARGS__);  \
-		return n;  \
-	}  \
-} while(0)
-
-#define ERRRESP(buf)  buf, (buf[strlen(buf)-1] == '\n' ? "" : "\n")
-
-#define WAITFOROK(n, msg) \
-do {  \
-	myassert(fgets(buf, sizeof(buf), BFL), n, "Error reading response from " msg "\n");  \
-	myassert(!strcmp(buf, "OK\n"), n, "Invalid response from " msg ": %s%s", ERRRESP(buf));  \
-} while(0)
-
-int main(int argc, char**argv)
-{
-	myassert(argc == 3, 1, "Usage: %s <serialdev> <firmware.bfl>\n", argv[0]);
-	setbuf(stdout, NULL);
-	
-	// Check filename
-	char *FWname = basename(strdup(argv[2]));
-	size_t FWnameLen = strlen(FWname);
-	myassert(FWnameLen <= 255, 0x0f, "Firmware filename '%s' is too long\n", FWname);
-	uint8_t n8 = FWnameLen;
-	
-	// Open and check firmware file
-	FILE *FW = fopen(argv[2], "r");
-	myassert(FW, 0x10, "Failed to open '%s' for reading\n", argv[2]);
-	char buf[0x20];
-	myassert(1 == fread(buf, 7, 1, FW), 0x10, "Failed to read from '%s'\n", argv[2]);
-	myassert(!memcmp(buf, BFL_FILE_MAGIC, sizeof(BFL_FILE_MAGIC)-1), 0x11, "'%s' doesn't look like a BFL firmware\n", argv[2]);
-	myassert(!fseek(FW, 0, SEEK_END), 0x12, "Failed to find end of '%s'\n", argv[2]);
-	long FWlen = ftell(FW);
-	myassert(FWlen > 0, 0x12, "Couldn't get size of '%s'\n", argv[2]);
-	myassert(!fseek(FW, 7, SEEK_SET), 0x12, "Failed to rewind firmware file after getting size\n");
-	FWlen -= 7;
-	printf("Firmware file looks OK :)\n");
-	
-	// Open device
-	FILE *BFL = fopen(argv[1], "r+");
-	myassert(BFL, 0x20, "Failed to open '%s' for read/write\n", argv[1]);
-	myassert(!setvbuf(BFL, NULL, _IOFBF, 1032), 0x21, "Failed to setup buffer for device");
-	
-	// ZAX: Start firmware upload
-	printf("Starting firmware upload... ");
-	myassert(1 == fwrite("ZAX", 3, 1, BFL), 0x22, "Failed to issue ZAX command\n");
-	WAITFOROK(0x22, "ZAX");
-	
-	// Firmware upload header
-	myassert(1 == fwrite(BFL_UPLOAD_MAGIC, sizeof(BFL_UPLOAD_MAGIC)-1, 1, BFL), 0x23, "Failed to send firmware upload header (magic)\n");
-	uint32_t n32 = htonl(FWlen - FWlen / 6);
-	myassert(1 == fwrite(&n32, sizeof(n32), 1, BFL), 0x23, "Failed to send firmware upload header (size)\n");
-	myassert(1 == fwrite("\0\0", 2        , 1, BFL), 0x23, "Failed to send firmware upload header (padding 1)\n");
-	myassert(1 == fwrite(&n8, sizeof(n8)  , 1, BFL), 0x23, "Failed to send firmware upload header (filename length)\n");
-	myassert(1 == fwrite(FWname, n8       , 1, BFL), 0x23, "Failed to send firmware upload header (filename)\n");
-	myassert(1 == fwrite("\0>>>>>>>>", 9  , 1, BFL), 0x23, "Failed to send firmware upload header (padding 2)\n");
-	WAITFOROK(0x23, "firmware upload header");
-	printf("OK, sending...\n");
-	
-	// Actual firmware upload
-	long i, j;
-	for (i = 0, j = 0; i < FWlen; ++i) {
-		myassert(1 == fread(&n8, sizeof(n8), 1, FW), 0x30, "Error reading data from firmware file\n");
-		if (5 == i % 6)
-			continue;
-		n8 ^= 0x2f;
-		myassert(1 == fwrite(&n8, sizeof(n8), 1, BFL), 0x31, "Error sending data to device\n");
-		if (!(++j % 0x400)) {
-			myassert(1 == fwrite(">>>>>>>>", 8, 1, BFL), 0x32, "Error sending block-finish to device\n");
-			printf("\r%5.2f%% complete", (double)i * 100. / (double)FWlen);
-			WAITFOROK(0x32, "block-finish");
-		}
-	}
-	printf("\r100%% complete :)\n");
-	myassert(1 == fwrite(">>>>>>>>", 8, 1, BFL), 0x3f, "Error sending upload-finished to device\n");
-	myassert(fgets(buf, sizeof(buf), BFL), 0x3f, "Error reading response from upload-finished\n");
-	myassert(!strcmp(buf, "DONE\n"), 0x3f, "Invalid response from upload-finished: %s%s", ERRRESP(buf));
-
-	// ZBX: Finish programming
-	printf("Waiting for device... ");
-	myassert(1 == fwrite("ZBX", 3, 1, BFL), 0x40, "Failed to issue ZBX command\n");
-	WAITFOROK(0x40, "ZBX");
-	printf("All done! Try mining to test the flash succeeded.\n");
-
-	return 0;
-}

+ 1 - 1
ccan-upstream

@@ -1 +1 @@
-Subproject commit 7471ecd79174306ee976a4ecc09cc2b9ebb4b501
+Subproject commit 8b0bdb090e2882aa431e89f4bc7aa4736e9e2838

+ 137 - 45
configure.ac

@@ -1,9 +1,10 @@
-dnl * Copyright 2012-2013 Luke Dashjr
+dnl * Copyright 2011-2014 Luke Dashjr
 dnl * Copyright 2011-2013 Con Kolivas
 dnl * Copyright 2011-2013 Con Kolivas
 dnl * Copyright 2010-2011 Jeff Garzik
 dnl * Copyright 2010-2011 Jeff Garzik
 dnl * Copyright 2012 Xiangfu
 dnl * Copyright 2012 Xiangfu
 dnl * Copyright 2011 Rusty Russell
 dnl * Copyright 2011 Rusty Russell
 dnl * Copyright 2011 Mark Crichton
 dnl * Copyright 2011 Mark Crichton
+dnl * Copyright 2013-2014 Nate Woolls
 dnl *
 dnl *
 dnl * This program is free software; you can redistribute it and/or modify it
 dnl * This program is free software; you can redistribute it and/or modify it
 dnl * under the terms of the GNU General Public License as published by the Free
 dnl * under the terms of the GNU General Public License as published by the Free
@@ -12,8 +13,8 @@ dnl * any later version.  See COPYING for more details.
 
 
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
-m4_define([v_maj], [3])
-m4_define([v_min], [99])
+m4_define([v_maj], [4])
+m4_define([v_min], [7])
 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])
@@ -127,6 +128,7 @@ need_lowl_vcom=no
 need_lowlevel=no
 need_lowlevel=no
 need_lowl_ftdi=no
 need_lowl_ftdi=no
 need_lowl_hid=no
 need_lowl_hid=no
+need_lowl_mswin=no
 need_lowl_pci=no
 need_lowl_pci=no
 need_lowl_spi=no
 need_lowl_spi=no
 need_lowl_usb=no
 need_lowl_usb=no
@@ -181,6 +183,7 @@ case $target in
     use_udevrules=false
     use_udevrules=false
     ;;
     ;;
 	*-*-darwin*)
 	*-*-darwin*)
+		LDFLAGS="$LDFLAGS -framework IOKit -framework CoreFoundation"
 		have_macho=true
 		have_macho=true
     use_udevrules=false
     use_udevrules=false
 		;;
 		;;
@@ -240,6 +243,32 @@ AC_ARG_ENABLE([other-drivers],
 )
 )
 
 
 
 
+broad_udevrules=false
+AC_ARG_ENABLE([broad-udevrules],
+	[AC_HELP_STRING([--enable-broad-udevrules],[Include udev rules for ambiguous devices which may not be miners])],
+	[
+		if test "x$enableval" = "xyes"; then
+			broad_udevrules=true
+		fi
+	]
+)
+
+use_udevrules_group=true
+udevrules_group="video"
+AC_ARG_WITH([udevrules-group],
+	[AC_HELP_STRING([--with-udevrules-group=groupname],[Configure mining devices to be owned by a specific group (default `video')])],
+	[
+		if test "x$withval" = "xno"; then
+			use_udevrules_group=false
+		else
+			udevrules_group="$withval"
+		fi
+	]
+)
+AM_CONDITIONAL([USE_UDEVRULES_GROUP], [$use_udevrules_group])
+AC_SUBST([UDEVRULES_GROUP], [$udevrules_group])
+
+
 algolist="$algolist scrypt"
 algolist="$algolist scrypt"
 AC_ARG_ENABLE([scrypt],
 AC_ARG_ENABLE([scrypt],
 	[AC_HELP_STRING([--enable-scrypt],[Compile support for scrypt mining (default disabled)])],
 	[AC_HELP_STRING([--enable-scrypt],[Compile support for scrypt mining (default disabled)])],
@@ -436,6 +465,10 @@ if test "x$bitforce" = xyes; then
 		need_lowl_pci=yes
 		need_lowl_pci=yes
 	fi
 	fi
 	need_lowl_vcom=yes
 	need_lowl_vcom=yes
+	driverlist="$driverlist bitforce:mswin/need_lowl_mswin"
+	if test x$have_win32 = xtrue; then
+		need_lowl_mswin=yes
+	fi
 	has_fpga=yes
 	has_fpga=yes
 	has_asic=yes
 	has_asic=yes
 	have_udevrules=true
 	have_udevrules=true
@@ -476,9 +509,34 @@ fi
 if test "x$dualminer" = "xyes"; then
 if test "x$dualminer" = "xyes"; then
 	AC_DEFINE([USE_DUALMINER], [1], [Defined to 1 if DualMiner support is wanted])
 	AC_DEFINE([USE_DUALMINER], [1], [Defined to 1 if DualMiner support is wanted])
 	need_gc3355=yes
 	need_gc3355=yes
+	$broad_udevrules && have_udevrules=true
 fi
 fi
 AM_CONDITIONAL([USE_DUALMINER], [test x$dualminer = xyes])
 AM_CONDITIONAL([USE_DUALMINER], [test x$dualminer = xyes])
 
 
+driverlist="$driverlist zeusminer"
+AC_ARG_ENABLE([zeusminer],
+	[AC_HELP_STRING([--disable-zeusminer],[Compile support for ZeusMiner (default enabled with scrypt)])],
+	[zeusminer=$enableval],
+	[zeusminer=$ddauto])
+if test "x$zeusminer" = "xno"; then
+	true
+elif test "x$icarus$scrypt" = "xyesyes"; then
+	zeusminer=yes
+elif test "x$zeusminer" = "xauto"; then
+	zeusminer=no
+elif test "x$scrypt" = "xno"; then
+	AC_MSG_ERROR([You explicitly enabled ZeusMiner, but did not enable scrypt])
+elif test "x$icarus" = "xno"; then
+	AC_MSG_ERROR([You explicitly disabled Icarus and explicitly enabled ZeusMiner])
+fi
+if test "x$zeusminer" = "xyes"; then
+	AC_DEFINE([USE_ZEUSMINER], [1], [Defined to 1 if ZeusMiner support is wanted])
+	need_lowl_vcom=yes
+	has_asic=yes
+	$broad_udevrules && have_udevrules=true
+fi
+AM_CONDITIONAL([USE_ZEUSMINER], [test x$zeusminer = xyes])
+
 driverlist="$driverlist gridseed"
 driverlist="$driverlist gridseed"
 AC_ARG_ENABLE([gridseed],
 AC_ARG_ENABLE([gridseed],
 	[AC_HELP_STRING([--disable-gridseed],[Compile support for GridSeed (default enabled with scrypt)])],
 	[AC_HELP_STRING([--disable-gridseed],[Compile support for GridSeed (default enabled with scrypt)])],
@@ -492,6 +550,7 @@ if test "x$gridseed" = "xyes"; then
 	need_gc3355=yes
 	need_gc3355=yes
 	need_lowl_vcom=yes
 	need_lowl_vcom=yes
 	has_asic=yes
 	has_asic=yes
+	$broad_udevrules && have_udevrules=true
 fi
 fi
 AM_CONDITIONAL([USE_GRIDSEED], [test x$gridseed = xyes])
 AM_CONDITIONAL([USE_GRIDSEED], [test x$gridseed = xyes])
 
 
@@ -507,10 +566,27 @@ if test "x$avalon" = xyes; then
 	AC_DEFINE([USE_AVALON], [1], [Defined to 1 if Avalon support is wanted])
 	AC_DEFINE([USE_AVALON], [1], [Defined to 1 if Avalon support is wanted])
 	need_lowl_vcom=yes
 	need_lowl_vcom=yes
 	has_asic=yes
 	has_asic=yes
+	$broad_udevrules && have_udevrules=true
 fi
 fi
 AM_CONDITIONAL([HAS_AVALON], [test x$avalon = xyes])
 AM_CONDITIONAL([HAS_AVALON], [test x$avalon = xyes])
 
 
 
 
+driverlist="$driverlist avalonmm"
+AC_ARG_ENABLE([avalonmm],
+	[AC_HELP_STRING([--disable-avalonmm],[Compile support for Avalon2/3 (default enabled)])],
+	[avalonmm=$enableval],
+	[avalonmm=$ddyes]
+	)
+if test "x$avalonmm" = xyes; then
+	AC_DEFINE([USE_AVALONMM], [1], [Defined to 1 if Avalon2/3 support is wanted])
+	need_lowl_vcom=yes
+	need_work2d=yes
+	has_asic=yes
+	$broad_udevrules && have_udevrules=true
+fi
+AM_CONDITIONAL([USE_AVALONMM], [test x$avalonmm = xyes])
+
+
 driverlist="$driverlist knc"
 driverlist="$driverlist knc"
 AC_ARG_ENABLE([knc],
 AC_ARG_ENABLE([knc],
 	[AC_HELP_STRING([--enable-knc],[Compile support for KnC (default disabled)])],
 	[AC_HELP_STRING([--enable-knc],[Compile support for KnC (default disabled)])],
@@ -520,7 +596,7 @@ AC_ARG_ENABLE([knc],
 if test "x$knc" = xyes; then
 if test "x$knc" = xyes; then
 	AC_CHECK_HEADERS([linux/i2c-dev-user.h])
 	AC_CHECK_HEADERS([linux/i2c-dev-user.h])
 	AC_CHECK_DECL([i2c_smbus_read_word_data],[true],[
 	AC_CHECK_DECL([i2c_smbus_read_word_data],[true],[
-		AC_MSG_ERROR([linux/i2c-dev.h header from i2c-tools (NOT linux headers) is required for knc driver])
+		AC_MSG_ERROR([linux/i2c-dev.h header from i2c-tools/libi2c-dev (NOT linux headers) is required for knc driver])
 	],[
 	],[
 		#include <stddef.h>
 		#include <stddef.h>
 		#ifdef HAVE_LINUX_I2C_DEV_USER_H
 		#ifdef HAVE_LINUX_I2C_DEV_USER_H
@@ -853,6 +929,7 @@ if test "x$bfx" = xyes; then
 	AC_DEFINE([USE_BFX], [1], [Defined to 1 if BFx2 support is wanted])
 	AC_DEFINE([USE_BFX], [1], [Defined to 1 if BFx2 support is wanted])
 	need_lowl_ftdi=yes
 	need_lowl_ftdi=yes
 	has_asic=yes
 	has_asic=yes
+	$broad_udevrules && have_udevrules=true
 fi
 fi
 AM_CONDITIONAL([USE_BFX], [test x$bfx = xyes])
 AM_CONDITIONAL([USE_BFX], [test x$bfx = xyes])
 
 
@@ -1046,6 +1123,20 @@ fi
 AM_CONDITIONAL([USE_HASHFAST], [test x$hashfast = xyes])
 AM_CONDITIONAL([USE_HASHFAST], [test x$hashfast = xyes])
 
 
 
 
+driverlist="$driverlist jingtian"
+AC_ARG_ENABLE([jingtian],
+	[AC_HELP_STRING([--enable-jingtian],[Compile support for JingTian (default disabled)])],
+	[jingtian=$enableval],
+	[jingtian=$ddno]
+	)
+if test "x$jingtian" = "xyes"; then
+	AC_DEFINE([USE_JINGTIAN], [1], [Defined to 1 if JingTian support is wanted])
+	need_lowl_spi=yes
+	has_asic=yes
+fi
+AM_CONDITIONAL([USE_JINGTIAN], [test x$jingtian = xyes])
+
+
 driverlist="$driverlist metabank"
 driverlist="$driverlist metabank"
 AC_ARG_ENABLE([metabank],
 AC_ARG_ENABLE([metabank],
 	[AC_HELP_STRING([--enable-metabank],[Compile support for Metabank (default disabled)])],
 	[AC_HELP_STRING([--enable-metabank],[Compile support for Metabank (default disabled)])],
@@ -1061,6 +1152,34 @@ fi
 AM_CONDITIONAL([HAS_METABANK], [test x$metabank = xyes])
 AM_CONDITIONAL([HAS_METABANK], [test x$metabank = xyes])
 
 
 
 
+driverlist="$driverlist minergate"
+AC_ARG_ENABLE([minergate],
+	[AC_HELP_STRING([--enable-minergate],[Compile support for Spondoolies minergate interface (default disabled)])],
+	[minergate=$enableval],
+	[minergate=$ddno]
+	)
+if test "x$minergate" = "xyes"; then
+	AC_DEFINE([USE_MINERGATE], [1], [Defined to 1 if Spondoolies minergate interface support is wanted])
+	has_asic=yes
+fi
+AM_CONDITIONAL([USE_MINERGATE], [test x$minergate = xyes])
+
+
+driverlist="$driverlist rockminer"
+AC_ARG_ENABLE([rockminer],
+	[AC_HELP_STRING([--disable-rockminer],[Compile support for RockMiner (default enabled)])],
+	[rockminer=$enableval],
+	[rockminer=$ddyes]
+)
+if test "x$rockminer" = xyes; then
+	AC_DEFINE([USE_ROCKMINER], [1], [Defined to 1 if RockMiner support is wanted])
+	need_lowl_vcom=yes
+	has_asic=yes
+	have_udevrules=true
+fi
+AM_CONDITIONAL([USE_ROCKMINER], [test x$rockminer = xyes])
+
+
 if test "x$need_lowl_vcom" != "xno"; then
 if test "x$need_lowl_vcom" != "xno"; then
 	# Lowlevel VCOM doesn't need libusb, but it can take advantage of it to reattach drivers
 	# Lowlevel VCOM doesn't need libusb, but it can take advantage of it to reattach drivers
 	if test "x$libusb" != xno; then
 	if test "x$libusb" != xno; then
@@ -1147,6 +1266,12 @@ if test x$need_lowl_hid = xyes; then
 	need_lowlevel=yes
 	need_lowlevel=yes
 fi
 fi
 
 
+lowllist="$lowllist mswin/need_lowl_mswin"
+if test x$need_lowl_mswin = xyes; then
+	AC_DEFINE([NEED_BFG_LOWL_MSWIN], [1], [Defined to 1 if lowlevel mswin drivers are being used])
+	need_lowlevel=yes
+fi
+
 lowllist="$lowllist pci/need_lowl_pci"
 lowllist="$lowllist pci/need_lowl_pci"
 if test x$need_lowl_pci = xyes; then
 if test x$need_lowl_pci = xyes; then
 	AC_DEFINE([NEED_BFG_LOWL_PCI], [1], [Defined to 1 if lowlevel PCI drivers are being used])
 	AC_DEFINE([NEED_BFG_LOWL_PCI], [1], [Defined to 1 if lowlevel PCI drivers are being used])
@@ -1160,6 +1285,7 @@ if test x$need_lowl_pci = xyes; then
 		AC_DEFINE([USE_VFIO], [1], [Defined to 1 if lowlevel PCI drivers should support VFIO])
 		AC_DEFINE([USE_VFIO], [1], [Defined to 1 if lowlevel PCI drivers should support VFIO])
 	fi
 	fi
 fi
 fi
+AM_CONDITIONAL([USE_VFIO], [test x$need_lowl_pci$vfio = xyesyes])
 
 
 lowllist="$lowllist usb/need_lowl_usb"
 lowllist="$lowllist usb/need_lowl_usb"
 if test x$need_lowl_usb = xyes; then
 if test x$need_lowl_usb = xyes; then
@@ -1285,44 +1411,8 @@ else
 fi
 fi
 
 
 
 
-maybe_ldconfig=
-AC_ARG_WITH([system-libblkmaker], [AC_HELP_STRING([--with-system-libblkmaker], [Use system libblkmaker rather than bundled one (default disabled)])],[true],[with_system_libblkmaker=no])
-if test "x$with_system_libblkmaker" = "xyes"; then
-	PKG_CHECK_MODULES([libblkmaker],[libblkmaker_jansson-0.1],[
-		true
-	],[
-		AC_MSG_ERROR([Could not find system libblkmaker])
-	])
-else
-	save_LDFLAGS="$LDFLAGS"
-	LDFLAGS="$LDFLAGS -Wl,-zorigin"
-	origin_LDFLAGS=
-	AC_MSG_CHECKING([whether the linker recognizes the -zorigin option])
-	AC_TRY_LINK([],[],[
-		AC_MSG_RESULT([yes])
-		origin_LDFLAGS=',-zorigin'
-	],[
-		AC_MSG_RESULT([no])
-	])
-	LDFLAGS="$save_LDFLAGS"
-	
-	libblkmaker_CFLAGS='-Ilibblkmaker'
-	libblkmaker_LDFLAGS='-Llibblkmaker/.libs -Wl,-rpath,\$$ORIGIN/libblkmaker/.libs'"$origin_LDFLAGS"
-	libblkmaker_LIBS='-lblkmaker_jansson-0.1 -lblkmaker-0.1'
-	AC_CONFIG_SUBDIRS([libblkmaker])
-	_ROOTPATH=$PATH$PATH_SEPARATOR`echo $PATH | sed s/bin/sbin/g`
-	possible_ldconfigs="${target}-ldconfig"
-	if test "x$cross_compiling" != "xyes"; then
-		possible_ldconfigs="${possible_ldconfigs} ldconfig"
-	fi
-	AC_CHECK_PROGS([LDCONFIG],[${possible_ldconfigs}],[],[$_ROOTPATH])
-	if test "x$LDCONFIG" != "x"; then
-		maybe_ldconfig=" && $LDCONFIG"
-	fi
-fi
-AC_SUBST(libblkmaker_CFLAGS)
-AC_SUBST(libblkmaker_LDFLAGS)
-AC_SUBST(libblkmaker_LIBS)
+BFG_BUNDLED_LIB([libbase58],[libbase58],[auto],[libbase58],[base58],[],[--disable-tool --disable-static --enable-shared])
+BFG_BUNDLED_LIB([libblkmaker],[libblkmaker_jansson-0.1],[no],[libblkmaker],[blkmaker_jansson-0.1 blkmaker-0.1],[libbase58])
 
 
 
 
 $have_udevrules || use_udevrules=false
 $have_udevrules || use_udevrules=false
@@ -1346,13 +1436,13 @@ if $use_udevrules; then
 fi
 fi
 
 
 
 
-AM_CONDITIONAL([NEED_LIBBLKMAKER], [test x$with_system_libblkmaker != xyes])
 AM_CONDITIONAL([NEED_BFG_BINLOADER], [test x$need_binloader = xyes])
 AM_CONDITIONAL([NEED_BFG_BINLOADER], [test x$need_binloader = xyes])
 AM_CONDITIONAL([NEED_DYNCLOCK], [test x$need_dynclock = xyes])
 AM_CONDITIONAL([NEED_DYNCLOCK], [test x$need_dynclock = xyes])
 AM_CONDITIONAL([USE_GC3355], [test x$need_gc3355 = xyes])
 AM_CONDITIONAL([USE_GC3355], [test x$need_gc3355 = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_VCOM], [test x$need_lowl_vcom = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_VCOM], [test x$need_lowl_vcom = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_FTDI], [test x$need_lowl_ftdi = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_FTDI], [test x$need_lowl_ftdi = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_HID], [test x$need_lowl_hid = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_HID], [test x$need_lowl_hid = xyes])
+AM_CONDITIONAL([NEED_BFG_LOWL_MSWIN], [test x$need_lowl_mswin = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_PCI], [test x$need_lowl_pci = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_PCI], [test x$need_lowl_pci = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_SPI], [test x$need_lowl_spi = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_SPI], [test x$need_lowl_spi = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWLEVEL], [test x$need_lowlevel = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWLEVEL], [test x$need_lowlevel = xyes])
@@ -1368,6 +1458,7 @@ AM_CONDITIONAL([HAVE_WIN_DDKUSB], [test x$found_ddkusb = xtrue])
 AM_CONDITIONAL([HAS_FPGA], [test x$has_fpga != xno])
 AM_CONDITIONAL([HAS_FPGA], [test x$has_fpga != xno])
 AM_CONDITIONAL([HAS_ASIC], [test x$has_asic != xno])
 AM_CONDITIONAL([HAS_ASIC], [test x$has_asic != xno])
 AM_CONDITIONAL([USE_UDEVRULES], [$use_udevrules])
 AM_CONDITIONAL([USE_UDEVRULES], [$use_udevrules])
+AM_CONDITIONAL([BROAD_UDEVRULES], [$broad_udevrules])
 
 
 dnl Find YASM
 dnl Find YASM
 has_yasm=false
 has_yasm=false
@@ -1756,6 +1847,7 @@ if $use_udevrules; then
 fi
 fi
 
 
 AC_OUTPUT
 AC_OUTPUT
+BFG_CUSTOM_SUBDIRS_OUTPUT
 
 
 
 
 wordfilter ()
 wordfilter ()
@@ -1768,8 +1860,8 @@ echo "------------------------------------------------------------------------"
 echo "$PACKAGE $VERSION configuration options summary"
 echo "$PACKAGE $VERSION configuration options summary"
 echo "------------------------------------------------------------------------"
 echo "------------------------------------------------------------------------"
 echo
 echo
-echo "  CFLAGS...............: "`wordfilter "$CPPFLAGS $AUTOSCAN_CPPFLAGS $NCURSES_CPPFLAGS $PTHREAD_FLAGS $CFLAGS $LIBUSB_CFLAGS $JANSSON_CFLAGS $PTHREAD_FLAGS $libblkmaker_CFLAGS $hidapi_CFLAGS"`
-echo "  LDFLAGS..............: "`wordfilter "$LDFLAGS $AUTOSCAN_LIBS $PTHREAD_FLAGS $libblkmaker_LDFLAGS $PTHREAD_LIBS $LIBS $DLOPEN_FLAGS $LIBCURL_LIBS $JANSSON_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $UDEV_LIBS $LIBUSB_LIBS $RT_LIBS $sensors_LIBS $libblkmaker_LIBS"`
+echo "  CFLAGS...............: "`wordfilter "$CPPFLAGS $AUTOSCAN_CPPFLAGS $NCURSES_CPPFLAGS $PTHREAD_FLAGS $CFLAGS $LIBUSB_CFLAGS $JANSSON_CFLAGS $PTHREAD_FLAGS $libbase58_CFLAGS $libblkmaker_CFLAGS $hidapi_CFLAGS"`
+echo "  LDFLAGS..............: "`wordfilter "$LDFLAGS $AUTOSCAN_LIBS $PTHREAD_FLAGS $PTHREAD_LIBS $LIBS $DLOPEN_FLAGS $LIBCURL_LIBS $JANSSON_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $UDEV_LIBS $LIBUSB_LIBS $RT_LIBS $sensors_LIBS $libbase58_LIBS $libblkmaker_LIBS"`
 echo "  Installation.prefix..: $prefix"
 echo "  Installation.prefix..: $prefix"
 echo
 echo
 echo "${lowllist_print}" | tr '~' '\n'
 echo "${lowllist_print}" | tr '~' '\n'

+ 92 - 0
debian/changelog

@@ -1,3 +1,95 @@
+bfgminer (4.7.0-0precise1) precise; urgency=low
+
+  * avalonmm: Guess sensible defaults when user does not specify clock/voltage.
+  * minergate: New driver supporting the Spondoolies SP10.
+  * Stratum: Support for mining.set_extranonce extension; put "#xnsub" at the end of the pool URI to enable.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Sun, 17 Aug 2014 02:08:49 -0000
+
+bfgminer (4.6.0-0precise1) precise; urgency=low
+
+  * avalonmm: New driver for both Avalon2 and Avalon3 rigs.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Sat, 02 Aug 2014 03:10:10 -0000
+
+bfgminer (4.5.0-0precise1) precise; urgency=low
+
+  * bitforce: A new setup-vfio shell script is included to simplify configuring VFIO for Monarchs on PCIe.
+  * cairnsmore, icarus, zeusminer: Per-core mining statistics support.
+  * gridseed: Ability to set clock speed via Manage TUI.
+  * hashfast: Include chip/core address in RPC procdetails.
+  * hashfast: Implement ability to change clock setting at runtime.
+  * rockminer: Allow setting clock 300-2560 as long as prefixed by "unsafe:".
+  * zeusminer: Support for the GAW War Machine.
+  * zeusminer: Ability to set clock speed via Manage TUI.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Sat, 26 Jul 2014 16:26:25 -0000
+
+bfgminer (4.4.0-0precise1) precise; urgency=low
+
+  * getwork and stratum proxy drivers: Proxy-share difficulty is now adjustable using --set pxy:diff=N and/or --set pxy@username:diff=N
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Mon, 07 Jul 2014 16:34:42 -0000
+
+bfgminer (4.3.0-0precise1) precise; urgency=low
+
+  * URI parameter #getcbaddr to request coinbase address from bitcoind or compatible servers for solo mining.
+  * When running on systems with a configured Bitcoin Core server, it is automatically configured as a final failover and used for local block submission (GBT pools only) to reduce the risk of a stale block.
+  * bitforce: Implement some last-minute Monarch interface changes.
+  * zeusminer: New driver for these scrypt ASIC devices.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Mon, 30 Jun 2014 14:55:06 -0000
+
+bfgminer (4.2.0-0precise1) precise; urgency=low
+
+  * rockminer: New driver for ROCKMINER R-BOX.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Wed, 11 Jun 2014 03:03:50 -0000
+
+bfgminer (4.1.0-0precise1) precise; urgency=low
+
+  * Stratum: Fix recovery of dead pools.
+  * gridseed: 80-chip G-Blade support.
+  * Stratum: Support for authenticated TLS with the CA model, using #tlsca URI parameter.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Fri, 06 Jun 2014 02:35:20 -0000
+
+bfgminer (4.0.0-0precise1) precise; urgency=low
+
+  * Various options (specifically, --temp-cutoff, --temp-target, and the various --<driver>-options) have been migrated to the --set-device interface.
+  * Automatic hotplug support for Linux and Windows.
+  * TUI: Redesigned pool information line to include share difficulties in multipool modes and timestamp of the last explicit work update (which are no longer logged).
+  * Forbid cross-domain server redirection by default, unless pool URI has #redirect in it.
+  * Stratum: Unauthenticated TLS support.
+  * Stratum: Improve support for stratum-compliant scrypt servers, while still cleanly handling the expectations of many broken servers.
+  * bifury: Support for OneStringMiner and Hex*Fury (see README.ASIC for notes about boards with buggy firmware).
+  * bitfury: Detect gen2 chips and report hashrate correctly.
+  * bfx: New driver for BFx2 Bitfury USB stick miners.
+  * bitforce: Support for Monarch 28nm cards, including PCI-Express support on Linux (see README.ASIC for setup instructions).
+  * drillbit: Add support for protocol version 4 devices.
+  * dualminer: New driver, supporting both SHA256d and scrypt ASIC mining.
+  * gridseed: New driver, supporting only scrypt ASIC mining.
+  * hashbusteravalon: New driver for Avalon2-based HashBuster devices, such as the HashBuster Alpha.
+  * hashfast: Display of temperature and voltage, as well as setting clock frequency at startup.
+  * icarus & cairnsmore: Since Block Erupters are far more popular, and less unprofitable, the erupter driver is now preferred over icarus and cairnsmore drivers. This means you must change -S all to -S icarus:all or -S cairnsmore:all.
+  * knc: Added a use_dcdc setting that can be used on Nov batch units to avoid triggering DCDC problems (--set knc:use_dcdc=no).
+  * nanofury: Support for new, multi-chip NF2 and NF6 units.
+  * RPC: cpu* and gpu* commands have all been deprecated; CPUs and GPUs are now accessible using pga* and proc* commands just like everything else.
+  * Stratum proxy: Support for GBT upstream pools, as well as scrypt algorithm.
+  * getwork proxy: Support for scrypt and included in Win64 binaries.
+  * opencl: Major updating of code to use set-device interfaces.
+  * opencl: Support for loading kernels by filename, provided they use a known interface. Loading most scrypt kernel should just work, and most SHA2 kernels can be enabled by adding a single comment to the CL source.
+  * opencl: Support for new "xintensity" unit by using --set-device OCL:intensity=x5 (for example).
+  * opencl: Raise max scrypt GPU intensity to 31, and enabled driver by default for scrypt.
+  * opencl: Add some optimised scrypt kernels by zuikkis and psw.
+  * scrypt: Fixed nonce-based (third) hashrate, and display sub-one share difficulties.
+  * Default log interval (and first hashrate rolling average) increased from 5 seconds to 20 seconds to make it more useful.
+  * Benchmark mode refactored to work for both SHA256d and scrypt, and with the third hashrate.
+  * Many uncommon options (including CPU and GPU mining related ones) have had their "shorthand" forms deprecated. A future release will remove (and perhaps redefine) these shorthands entirely.
+  * Bundled a start-bfgminer.sh shell script for *nix which will start/restart BFGMiner in a screen session, and can safely be used in init/cron tasks.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Mon, 26 May 2014 19:47:18 -0000
+
 bfgminer (3.10.0-0precise1) precise; urgency=low
 bfgminer (3.10.0-0precise1) precise; urgency=low
 
 
   * Support for AntMiner U1, Drillbit, and HashFast devices.
   * Support for AntMiner U1, Drillbit, and HashFast devices.

+ 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: 3.10.0
+Standards-Version: 4.7.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

+ 26 - 1
deviceapi.c

@@ -1,8 +1,9 @@
 /*
 /*
- * Copyright 2011-2013 Luke Dashjr
+ * Copyright 2011-2014 Luke Dashjr
  * Copyright 2011-2012 Con Kolivas
  * Copyright 2011-2012 Con Kolivas
  * Copyright 2012-2013 Andrew Smith
  * Copyright 2012-2013 Andrew Smith
  * Copyright 2010 Jeff Garzik
  * Copyright 2010 Jeff Garzik
+ * Copyright 2014 Nate Woolls
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -239,7 +240,11 @@ void minerloop_scanhash(struct thr_info *mythr)
 			* it is not in the driver code. */
 			* it is not in the driver code. */
 			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 			timer_set_now(&tv_start);
 			timer_set_now(&tv_start);
+
+			/* api->scanhash should scan the work for valid nonces
+			 * until max_nonce is reached or thr_info->work_restart */
 			hashes = api->scanhash(mythr, work, work->blk.nonce + max_nonce);
 			hashes = api->scanhash(mythr, work, work->blk.nonce + max_nonce);
+
 			timer_set_now(&tv_end);
 			timer_set_now(&tv_end);
 			pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
 			pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
 			pthread_testcancel();
 			pthread_testcancel();
@@ -269,6 +274,10 @@ disabled:
 				mt_disable(mythr);
 				mt_disable(mythr);
 			
 			
 			timersub(&tv_end, &work->tv_work_start, &tv_worktime);
 			timersub(&tv_end, &work->tv_work_start, &tv_worktime);
+
+		/* The inner do-while loop will exit unless the device is capable of
+		 * scanning a specific nonce range (currently CPU and GPU drivers)
+		 * See abandon_work comments for more details */
 		} while (!abandon_work(work, &tv_worktime, cgpu->max_hashes));
 		} while (!abandon_work(work, &tv_worktime, cgpu->max_hashes));
 		free_work(work);
 		free_work(work);
 	}
 	}
@@ -689,6 +698,9 @@ redo:
 			reduce_timeout_to(&tv_timeout, &mythr->tv_watchdog);
 			reduce_timeout_to(&tv_timeout, &mythr->tv_watchdog);
 		}
 		}
 		
 		
+		// HACK: Some designs set the main thr tv_poll from secondary thrs
+		reduce_timeout_to(&tv_timeout, &cgpu->thr[0]->tv_poll);
+		
 		do_notifier_select(thr, &tv_timeout);
 		do_notifier_select(thr, &tv_timeout);
 	}
 	}
 }
 }
@@ -1083,3 +1095,16 @@ void close_device_fd(struct thr_info * const thr)
 		applog(LOG_DEBUG, "%"PRIpreprv": Closed device fd", proc->proc_repr);
 		applog(LOG_DEBUG, "%"PRIpreprv": Closed device fd", proc->proc_repr);
 	}
 	}
 }
 }
+
+
+struct cgpu_info *device_proc_by_id(const struct cgpu_info * const dev, const int procid)
+{
+	struct cgpu_info *proc = (void*)dev;
+	for (int i = 0; i < procid; ++i)
+	{
+		proc = proc->next_proc;
+		if (unlikely((!proc) || proc->device != dev))
+			return NULL;
+	}
+	return proc;
+}

+ 6 - 0
deviceapi.h

@@ -110,6 +110,12 @@ extern FILE *open_bitstream(const char *dname, const char *filename);
 
 
 extern void close_device_fd(struct thr_info *);
 extern void close_device_fd(struct thr_info *);
 
 
+#define for_each_managed_proc(procvar, dev)  \
+	for (struct cgpu_info *procvar = dev; procvar; procvar = procvar->next_proc)
+#define for_each_logical_proc(procvar, dev)  \
+	for (struct cgpu_info *procvar = dev; procvar && procvar->device == (dev); procvar = procvar->next_proc)
+extern struct cgpu_info *device_proc_by_id(const struct cgpu_info *dev, int procid);
+
 #define set_on_all_procs(dev, attr, nv)  do{  \
 #define set_on_all_procs(dev, attr, nv)  do{  \
 	for (struct cgpu_info *_proc = dev; _proc; _proc = _proc->next_proc)  \
 	for (struct cgpu_info *_proc = dev; _proc; _proc = _proc->next_proc)  \
 		_proc->attr = nv;  \
 		_proc->attr = nv;  \

+ 641 - 0
driver-aan.c

@@ -0,0 +1,641 @@
+/*
+ * Copyright 2014 Luke Dashjr
+ * Copyright 2013 Zefir Kurtisi
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "deviceapi.h"
+#include "driver-aan.h"
+#include "logging.h"
+#include "lowl-spi.h"
+#include "miner.h"
+#include "util.h"
+
+#define AAN_DEFAULT_NONCE_PDIFF  8
+
+// WARNING: Do not just change this without fixing aan_freq2pll!
+#define AAN_MAX_FREQ  6132
+
+#define AAN_PROBE_TIMEOUT_US  3750000
+#define AAN_INIT_TIMEOUT_US   5000000
+#define AAN_READ_INTERVAL_US   100000
+
+#define AAN_REGISTER_SIZE  6
+
+enum aan_cmd {
+	AAN_BIST_START           = 0x01,
+	AAN_BIST_FIX             = 0x03,
+	AAN_RESET                = 0x04,
+	AAN_WRITE_JOB            = 0x07,
+	AAN_READ_RESULT          = 0x08,
+	AAN_WRITE_REG            = 0x09,
+	AAN_READ_REG             = 0x0a,
+	AAN_READ_REG_RESP        = 0x1a,
+};
+
+static
+unsigned aan_pll2freq(const uint16_t pll)
+{
+	const uint8_t pll_postdiv = (pll >> 0xe);
+	const uint8_t pll_prediv = (pll >> 9) & 0x1f;
+	const uint16_t pll_fbdiv = pll & 0x1ff;
+	return (12 * pll_fbdiv) / pll_prediv / (1 << (pll_postdiv - 1));
+}
+
+static
+uint16_t aan_freq2pll(unsigned freq)
+{
+retry: ;
+	uint8_t postdiv = 3, prediv = 3;
+	uint16_t fbdiv = freq / 3;
+	if (fbdiv * 3 == freq)
+		prediv = 1;
+	else
+		fbdiv = freq;
+	if (!(fbdiv & 3))
+	{
+		fbdiv >>= 2;
+		postdiv = 1;
+	}
+	else
+	if (!(fbdiv & 1))
+	{
+		fbdiv >>= 1;
+		postdiv = 2;
+	}
+	if (fbdiv > 0x1ff)
+	{
+		--freq;
+		goto retry;
+	}
+	const uint16_t pll = (((postdiv << 5) | prediv) << 9) | fbdiv;
+	return pll;
+}
+
+static
+void _test_aan_pll(const unsigned expect, const uint8_t postdiv, const uint8_t prediv, const uint16_t fbdiv)
+{
+	const uint16_t pll = (((postdiv << 5) | prediv) << 9) | fbdiv;
+	const unsigned got = aan_pll2freq(pll);
+	if (got != expect)
+		applog(LOG_WARNING, "%s test failed for %4u(%x,%02x,%3d): got %4u", "aan_pll2freq", expect, postdiv, prediv, fbdiv, got);
+}
+
+static
+void _test_aan_pll2(const unsigned freq)
+{
+	const uint16_t pll = aan_freq2pll(freq);
+	const unsigned got = aan_pll2freq(pll);
+	if (got / 12 != freq / 12)
+	{
+		const uint8_t postdiv = (pll >> 0xe);
+		const uint8_t prediv = (pll >> 9) & 0x1f;
+		const uint16_t fbdiv = pll & 0x1ff;
+		applog(LOG_WARNING, "%s test failed for %4u: got %4u(%x,%02x,%3d)", "aan_freq2pll", freq, got, postdiv, prediv, fbdiv);
+	}
+}
+
+void test_aan_pll(void)
+{
+	_test_aan_pll(1000, 0b01,0b00011,0b011111010);
+	_test_aan_pll( 950, 0b10,0b00011,0b111011011);
+	_test_aan_pll( 900, 0b01,0b00001,0b001001011);
+	_test_aan_pll( 850, 0b10,0b00011,0b110101001);
+	_test_aan_pll( 800, 0b01,0b00011,0b011001000);
+	_test_aan_pll( 750, 0b10,0b00001,0b001111101);
+	_test_aan_pll( 700, 0b01,0b00011,0b010101111);
+	_test_aan_pll( 650, 0b10,0b00011,0b101000101);
+	_test_aan_pll( 600, 0b01,0b00001,0b000110010);
+	_test_aan_pll( 550, 0b10,0b00011,0b100010011);
+	_test_aan_pll( 500, 0b10,0b00011,0b011111010);
+	_test_aan_pll( 100, 0b11,0b00011,0b001100100);
+	for (unsigned i = 1; i <= AAN_MAX_FREQ; ++i)
+		_test_aan_pll2(i);
+}
+
+static void aan_spi_parse_rx(struct spi_port *);
+
+static
+void aan_spi_cmd_queue(struct spi_port * const spi, const uint8_t cmd, const uint8_t chip, const void * const data, const size_t datalen)
+{
+	const struct aan_hooks * const hooks = spi->userp;
+	const uint8_t cmdbuf[2] = {cmd, chip};
+	hooks->precmd(spi);
+	spi_emit_buf(spi, cmdbuf, sizeof(cmdbuf));
+	if (datalen)
+		spi_emit_buf(spi, data, datalen);
+}
+
+static
+bool aan_spi_txrx(struct spi_port * const spi)
+{
+	if (unlikely(!spi_txrx(spi)))
+		return false;
+	
+	aan_spi_parse_rx(spi);
+	return true;
+}
+
+static
+bool aan_spi_cmd_send(struct spi_port * const spi, const uint8_t cmd, const uint8_t chip, const void * const data, const size_t datalen)
+{
+	aan_spi_cmd_queue(spi, cmd, chip, data, datalen);
+	return aan_spi_txrx(spi);
+}
+
+static
+bool aan_spi_cmd_resp(struct spi_port * const spi, const uint8_t cmd, const uint8_t chip, const struct timeval * const tvp_timeout)
+{
+	const uint8_t cmdbuf[2] = {cmd, chip};
+	
+	uint8_t * const rx = spi_getrxbuf(spi);
+	while (true)
+	{
+		spi_emit_nop(spi, 2);
+		if (unlikely(!spi_txrx(spi)))
+			return false;
+		if (!memcmp(rx, cmdbuf, 2))
+			break;
+		aan_spi_parse_rx(spi);
+		if (unlikely(tvp_timeout && timer_passed(tvp_timeout, NULL)))
+			return false;
+	}
+	spi_clear_buf(spi);
+	
+	return true;
+}
+
+static
+bool aan_spi_cmd(struct spi_port * const spi, const uint8_t cmd, const uint8_t chip, const void * const data, const size_t datalen, const struct timeval * const tvp_timeout)
+{
+	if (!aan_spi_cmd_send(spi, cmd, chip, data, datalen))
+		return false;
+	if (!aan_spi_cmd_resp(spi, cmd, chip, tvp_timeout))
+		return false;
+	return true;
+}
+
+bool aan_read_reg_direct(struct spi_port * const spi, const uint8_t chip, void * const out_buf, const struct timeval * const tvp_timeout)
+{
+	if (!aan_spi_cmd_send(spi, AAN_READ_REG, chip, NULL, 0))
+		return false;
+	if (!aan_spi_cmd_resp(spi, AAN_READ_REG_RESP, chip, tvp_timeout))
+		return false;
+	
+	spi_emit_nop(spi, AAN_REGISTER_SIZE);
+	if (!spi_txrx(spi))
+		applogr(false, LOG_DEBUG, "%s: %s failed", __func__, "spi_txrx");
+	
+	uint8_t * const rx = spi_getrxbuf(spi);
+	memcpy(out_buf, rx, AAN_REGISTER_SIZE);
+	
+	return true;
+}
+
+static inline
+bool aan_read_reg(struct spi_port * const spi, const uint8_t chip, void * const out_buf, const struct timeval * const tvp_timeout)
+{
+	const struct aan_hooks * const hooks = spi->userp;
+	return hooks->read_reg(spi, chip, out_buf, tvp_timeout);
+}
+
+int aan_detect_spi(int * const out_chipcount, struct spi_port * const * const spi_a, const int spi_n)
+{
+	struct timeval tv_timeout;
+	timer_set_delay_from_now(&tv_timeout, AAN_PROBE_TIMEOUT_US);
+	
+	int state[spi_n];
+	int completed = 0;
+	
+	for (int i = 0; i < spi_n; ++i)
+	{
+		struct spi_port * const spi = spi_a[i];
+		aan_spi_cmd_send(spi, state[i] = AAN_RESET, AAN_ALL_CHIPS, NULL, 0);
+		out_chipcount[i] = -1;
+	}
+	
+	do {
+		for (int i = 0; i < spi_n; ++i)
+		{
+			if (state[i] == -1)
+				continue;
+			struct spi_port * const spi = spi_a[i];
+			spi_emit_nop(spi, 2);
+			if (unlikely(!spi_txrx(spi)))
+			{
+spifail:
+				state[i] = -1;
+				continue;
+			}
+			uint8_t * const rx = spi_getrxbuf(spi);
+			if (rx[0] == state[i] && rx[1] == AAN_ALL_CHIPS)
+			{
+				switch (state[i])
+				{
+					case AAN_RESET:
+						applog(LOG_DEBUG, "%s: Reset complete", spi->repr);
+						spi_clear_buf(spi);
+						aan_spi_cmd_send(spi, state[i] = AAN_BIST_START, AAN_ALL_CHIPS, NULL, 0);
+						spi_emit_nop(spi, 2);
+						break;
+					case AAN_BIST_START:
+						if (unlikely(!spi_txrx(spi)))
+							goto spifail;
+						out_chipcount[i] = rx[1];
+						state[i] = -1;
+						++completed;
+						applog(LOG_DEBUG, "%s: BIST_START complete (%d chips)", spi->repr, rx[1]);
+						break;
+				}
+				spi_clear_buf(spi);
+				continue;
+			}
+			aan_spi_parse_rx(spi);
+		}
+	} while (completed < spi_n && likely(!timer_passed(&tv_timeout, NULL)));
+	
+	applog(LOG_DEBUG, "%s completed for %d out of %d SPI ports", __func__, completed, spi_n);
+	
+	return completed;
+}
+
+bool aan_init(struct thr_info * const master_thr)
+{
+	struct cgpu_info * const master_dev = master_thr->cgpu, *dev = NULL;
+	struct aan_board_data *board = NULL;
+	struct timeval tv_timeout, tv_now;
+	int chipid = 0;
+	for_each_managed_proc(proc, master_dev)
+	{
+		struct spi_port * const spi = proc->device_data;
+		struct thr_info * const thr = proc->thr[0];
+		
+		if (dev != proc->device)
+		{
+			dev = proc->device;
+			chipid = 0;
+			timer_set_now(&tv_now);
+			board = malloc(sizeof(*board));
+			*board = (struct aan_board_data){
+				.master_dev = master_dev,
+				.spi = spi,
+				.tv_next_poll = tv_now,
+			};
+			spi->cgpu = dev;
+			
+			while (true)
+			{
+				timer_set_delay(&tv_timeout, &tv_now, AAN_INIT_TIMEOUT_US);
+				if (aan_spi_cmd(spi, AAN_BIST_FIX, AAN_ALL_CHIPS, NULL, 0, &tv_timeout))
+					break;
+				applog(LOG_ERR, "%s: Failed to %s", proc->dev_repr, "BIST_FIX");
+			}
+		}
+		
+		proc->device_data = board;
+		struct aan_chip_data * const chip = malloc(sizeof(*chip));
+		thr->cgpu_data = chip;
+		thr->queue_full = true;
+		*chip = (struct aan_chip_data){
+			.chipid = ++chipid,
+			.desired_nonce_pdiff = AAN_DEFAULT_NONCE_PDIFF,
+			.desired_pllreg = 0x87a9,  // 850 MHz
+		};
+		
+		cgpu_set_defaults(proc);
+	}
+	master_thr->tv_poll = tv_now;
+	
+	return true;
+}
+
+static
+bool aan_spi_send_work(struct spi_port * const spi, const uint8_t chipid, const uint8_t jobid, const struct work * const work)
+{
+	uint8_t buf[0x38];
+	
+	swab256(&buf[0], work->midstate);
+	swap32yes(&buf[0x20], &work->data[0x40], 3);
+	memset(&buf[0x2c], 0, 4);         // start nonce
+	uint32_t compressed_target = (uint32_t)(0x10000 / work->nonce_diff) | (/*exponent*/ 0x1d << 24);
+	pk_u32le(buf, 0x30, compressed_target);
+	memset(&buf[0x34], 0xff, 4);      // end nonce
+	
+	return aan_spi_cmd_send(spi, AAN_WRITE_JOB | (jobid << 4), chipid, buf, sizeof(buf));
+}
+
+static bool set_work(struct cgpu_info *, uint8_t, struct work *);
+
+bool aan_queue_append(struct thr_info * const thr, struct work * const work)
+{
+	struct cgpu_info *proc = thr->cgpu;
+	struct aan_chip_data * const chip = thr->cgpu_data;
+	struct cgpu_info *dev = proc->device;
+	struct aan_board_data *board = dev->device_data;
+	struct cgpu_info * const master_dev = board->master_dev;
+	struct aan_board_data * const master_board = master_dev->device_data;
+	
+	applog(LOG_DEBUG, "%s: queue_append queues_empty=%d", proc->proc_repr, master_board->queues_empty-1);
+	
+	work->nonce_diff = work->work_difficulty;
+	if (work->nonce_diff > chip->desired_nonce_pdiff)
+		work->nonce_diff = chip->desired_nonce_pdiff;
+	chip->current_nonce_pdiff = work->nonce_diff;
+	
+	if (set_work(dev, proc->proc_id + 1, work))
+		hashes_done2(thr, 0x100000000, NULL);
+	
+	thr->queue_full = true;
+	if (!--master_board->queues_empty)
+	{
+		struct thr_info * const master_thr = master_dev->thr[0];
+		
+		// Reactivate polling
+		dev = NULL;
+		for_each_managed_proc(proc, master_dev)
+		{
+			if (dev == proc->device)
+				continue;
+			dev = proc->device;
+			board = dev->device_data;
+			
+			reduce_timeout_to(&master_thr->tv_poll, &board->tv_next_poll);
+		}
+	}
+	return true;
+}
+
+void aan_queue_flush(struct thr_info * const thr)
+{
+	// TODO
+}
+
+struct cgpu_info *aan_proc_for_chipid(struct cgpu_info * const dev, const int chipid)
+{
+	struct cgpu_info *proc = dev;
+	for (int i = 1; i < chipid; ++i)
+	{
+		proc = proc->next_proc;
+		if (unlikely((!proc) || proc->device != dev))
+		{
+badchipid:
+			inc_hw_errors_only(dev->thr[0]);
+			applogr(NULL, LOG_ERR, "%s: Chip number %d out of range", dev->dev_repr, chipid);
+		}
+	}
+	if (unlikely(!chipid))
+		goto badchipid;
+	return proc;
+}
+
+static
+void aan_spi_parse_rx(struct spi_port * const spi)
+{
+	spi_clear_buf(spi);
+}
+
+#define MAX_POLL_NUM   20
+
+/* set work for given chip, returns true if a nonce range was finished */
+static
+bool set_work(struct cgpu_info * const dev, const uint8_t chip_id, struct work * const work)
+{
+	struct aan_board_data * const board = dev->device_data;
+	struct spi_port * const spi = board->spi;
+	
+	struct cgpu_info * const proc = aan_proc_for_chipid(dev, chip_id);
+	struct thr_info * const thr = proc->thr[0];
+	struct aan_chip_data * const chip = thr->cgpu_data;
+	bool retval = false;
+	
+	++chip->last_jobid;
+	chip->last_jobid &= 3;
+
+	if (chip->works[chip->last_jobid] != NULL)
+	{
+		free_work(chip->works[chip->last_jobid]);
+		chip->works[chip->last_jobid] = NULL;
+		retval = true;
+	}
+	
+	if (!aan_spi_send_work(spi, chip_id, chip->last_jobid + 1, work))
+	{
+		free_work(work);
+		applog(LOG_ERR, "%"PRIpreprv": Failed to set work %d", proc->proc_repr, chip->last_jobid + 1);
+	}
+	else
+		chip->works[chip->last_jobid] = work;
+	spi_clear_buf(spi);
+	
+	return retval;
+}
+
+/* check for pending results in a chain, returns false if output queue empty */
+static
+bool get_nonce(struct cgpu_info * const dev, uint8_t * const nonce, uint8_t * const chip, uint8_t * const job_id)
+{
+	struct aan_board_data * const board = dev->device_data;
+	struct spi_port * const spi = board->spi;
+	
+	int pollLen = MAX_POLL_NUM * dev->procs;
+	if (pollLen <= 0)
+		pollLen = MAX_POLL_NUM;
+	
+	if (!aan_spi_cmd_send(spi, AAN_READ_RESULT, AAN_ALL_CHIPS, NULL, 0))
+		return false;
+	
+	for (int i = 0; i < pollLen; ++i)
+	{
+		spi_clear_buf(spi);
+		spi_emit_nop(spi, 2);
+		if (!spi_txrx(spi))
+			applogr(false, LOG_ERR, "%s: SPI error in get_nonce", dev->dev_repr);
+		uint8_t * const spi_rx = spi_getrxbuf(spi);
+		if (spi_rx[0] == AAN_READ_RESULT && spi_rx[1] == 0x00)
+			applogr(false, LOG_DEBUG, "%s: Output queue empty", dev->dev_repr);
+		if ((spi_rx[0] & 0x0f) == AAN_READ_RESULT && spi_rx[1] != 0)
+		{
+			*job_id = spi_rx[0] >> 4;
+			*chip = spi_rx[1];
+			
+			spi_emit_nop(spi, 2);
+			if (!spi_txrx(spi))
+				applogr(false, LOG_ERR, "SPI Err(%s):get_nonce", dev->dev_repr);
+			memcpy(nonce, spi_rx, 4);
+			
+			applog(LOG_DEBUG, "%s: Got nonce for chip %d / job_id %d", dev->dev_repr, *chip, *job_id);
+			
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+static
+void aan_scanwork(struct cgpu_info * const dev, struct thr_info * const master_thr)
+{
+	struct aan_board_data * const board = dev->device_data;
+	struct spi_port * const spi = board->spi;
+	
+	uint32_t nonce;
+	uint8_t chip_id;
+	uint8_t job_id;
+	bool work_updated = false;
+	
+	if (!timer_passed(&board->tv_next_poll, NULL))
+		goto out;
+	
+	while (get_nonce(dev, (uint8_t*)&nonce, &chip_id, &job_id))
+	{
+		nonce = bswap_32(nonce);
+		work_updated = true;
+		struct cgpu_info * const proc = aan_proc_for_chipid(dev, chip_id);
+		if (!proc)
+			continue;
+		struct thr_info * const thr = proc->thr[0];
+		struct aan_chip_data * const chip = thr->cgpu_data;
+		if (job_id < 1 || job_id > 4)
+		{
+badjob:
+			inc_hw_errors3(thr, NULL, &nonce, chip->current_nonce_pdiff);
+			continue;
+		}
+		struct work * const work = chip->works[job_id - 1];
+		if (!work)
+			goto badjob;
+		submit_nonce(thr, work, nonce);
+	}
+	
+	/* check for completed works */
+	for_each_logical_proc(proc, dev)
+	{
+		struct thr_info * const thr = proc->thr[0];
+		struct aan_chip_data * const chip = thr->cgpu_data;
+		const int i = proc->proc_id;
+		uint8_t reg[AAN_REGISTER_SIZE];
+		
+		if (!aan_read_reg(spi, i + 1, reg, NULL))
+		{
+			applog(LOG_ERR, "%"PRIpreprv": Failed to read reg", proc->proc_repr);
+			continue;
+		}
+		const uint16_t pllreg = upk_u16be(reg, 0);
+		chip->current_pllreg = pllreg;
+		if (pllreg != chip->desired_pllreg)
+		{
+			// Wait for chip to idle before changing register
+			if (!(reg[3] & 3))
+			{
+				applog(LOG_DEBUG, "%"PRIpreprv": Asserting PLL change: %04x->%04x", proc->proc_repr, pllreg, chip->desired_pllreg);
+				uint8_t regset[AAN_REGISTER_SIZE];
+				memcpy(&regset[2], &reg[2], AAN_REGISTER_SIZE - 2);
+				pk_u16be(regset, 0, chip->desired_pllreg);
+				aan_spi_cmd_send(spi, AAN_WRITE_REG, chip->chipid, regset, AAN_REGISTER_SIZE);
+			}
+		}
+		else
+		if ((reg[3] & 2) != 2)
+		{
+			struct cgpu_info * const master_dev = board->master_dev;
+			struct aan_board_data * const master_board = master_dev->device_data;
+			
+			work_updated = true;
+			thr->queue_full = false;
+			++master_board->queues_empty;
+			applog(LOG_DEBUG, "%s: queue_full=false queues_empty=%d", proc->proc_repr, master_board->queues_empty);
+		}
+	}
+	
+	if (!work_updated)
+		timer_set_delay_from_now(&board->tv_next_poll, AAN_READ_INTERVAL_US);
+
+out:
+	reduce_timeout_to(&master_thr->tv_poll, &board->tv_next_poll);
+}
+
+void aan_poll(struct thr_info * const master_thr)
+{
+	struct cgpu_info * const master_dev = master_thr->cgpu, *dev = NULL;
+	struct aan_board_data * const master_board = master_dev->device_data;
+	
+	timer_unset(&master_thr->tv_poll);
+	
+	for_each_managed_proc(proc, master_dev)
+	{
+		if (dev == proc->device)
+			continue;
+		dev = proc->device;
+		
+		aan_scanwork(dev, master_thr);
+	}
+	
+	if (master_board->queues_empty)
+		// Avoid polling when we have queues to fill
+		timer_unset(&master_thr->tv_poll);
+}
+
+const char *aan_set_clock(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	struct thr_info * const thr = proc->thr[0];
+	struct aan_chip_data * const chip = thr->cgpu_data;
+	
+	if (newvalue[0] == 'x')
+	{
+		char *p;
+		chip->desired_pllreg = strtol(&newvalue[1], &p, 0x10);
+		if (p != &newvalue[5])
+			return "Invalid hex PLL data";
+	}
+	else
+	{
+		const int nv = atoi(newvalue);
+		if (nv <= 0 || nv > AAN_MAX_FREQ)
+			return "Invalid clock frequency";
+		chip->desired_pllreg = aan_freq2pll(nv);
+	}
+	
+	return NULL;
+}
+
+const char *aan_set_diff(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	struct thr_info * const thr = proc->thr[0];
+	struct aan_chip_data * const chip = thr->cgpu_data;
+	
+	const double nv = atof(newvalue);
+	if (nv <= 0)
+		return "Invalid difficulty";
+	
+	chip->desired_nonce_pdiff = nv;
+	
+	return NULL;
+}
+
+struct api_data *aan_api_device_status(struct cgpu_info * const proc)
+{
+	struct thr_info * const thr = proc->thr[0];
+	struct aan_chip_data * const chip = thr->cgpu_data;
+	struct api_data *root = NULL;
+	
+	double mhz = aan_pll2freq(chip->current_pllreg);
+	root = api_add_freq(root, "Frequency", &mhz, true);
+	
+	return root;
+}
+
+const struct bfg_set_device_definition aan_set_device_funcs[] = {
+	{"clock", aan_set_clock, "clock frequency (MHz)"},
+	{"diff", aan_set_diff, "desired nonce difficulty"},
+	{NULL},
+};

+ 50 - 0
driver-aan.h

@@ -0,0 +1,50 @@
+#ifndef BFG_DRIVER_AAN
+#define BFG_DRIVER_AAN
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "lowl-spi.h"
+#include "miner.h"
+
+#define AAN_ALL_CHIPS  0
+#define AAN_MAX_JOBID  4
+
+struct aan_hooks {
+	void (*precmd)(struct spi_port *);
+	bool (*read_reg)(struct spi_port *, uint8_t chip, void *out_buf, const struct timeval *tvp_timeout);
+};
+
+struct aan_board_data {
+	struct spi_port *spi;
+	struct timeval tv_next_poll;
+	struct cgpu_info *master_dev;
+	
+	// Master board only
+	int queues_empty;
+};
+
+struct aan_chip_data {
+	uint8_t chipid;
+	int8_t last_jobid;
+	struct work *works[AAN_MAX_JOBID];
+	float desired_nonce_pdiff;
+	float current_nonce_pdiff;
+	uint16_t desired_pllreg;
+	uint16_t current_pllreg;
+};
+
+extern int aan_detect_spi(int *out_chipcount, struct spi_port * const *spi_a, int spi_n);
+extern bool aan_read_reg_direct(struct spi_port *, uint8_t chip, void *out_buf, const struct timeval *tvp_timeout);
+extern bool aan_init(struct thr_info *);
+extern bool aan_queue_append(struct thr_info *, struct work *);
+extern void aan_queue_flush(struct thr_info *);
+extern struct cgpu_info *aan_proc_for_chipid(struct cgpu_info *, int chipid);
+extern void aan_poll(struct thr_info *);
+
+extern const char *aan_set_diff(struct cgpu_info *, const char *optname, const char *newvalue, char *replybuf, enum bfg_set_device_replytype *);
+extern const struct bfg_set_device_definition aan_set_device_funcs[];
+
+extern struct api_data *aan_api_device_status(struct cgpu_info *);
+
+#endif

+ 2 - 2
driver-antminer.c

@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
- * Copyright 2013 Nate Woolls
+ * Copyright 2013-2014 Luke Dashjr
+ * Copyright 2013-2014 Nate Woolls
  * Copyright 2013 Lingchao Xu
  * Copyright 2013 Lingchao Xu
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it

+ 16 - 3
driver-avalon.c

@@ -1,8 +1,8 @@
 /*
 /*
  * Copyright 2012-2013 Xiangfu
  * Copyright 2012-2013 Xiangfu
  * Copyright 2013 Con Kolivas <kernel@kolivas.org>
  * Copyright 2013 Con Kolivas <kernel@kolivas.org>
- * Copyright 2012-2013 Luke Dashjr
- * Copyright 2012 Andrew Smith
+ * Copyright 2012-2014 Luke Dashjr
+ * Copyright 2012-2013 Andrew Smith
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -513,6 +513,18 @@ static void avalon_clear_readbuf(int fd)
 	} while (ret > 0);
 	} while (ret > 0);
 }
 }
 
 
+static
+void avalon_zero_stats(struct cgpu_info * const cgpu)
+{
+	struct avalon_info *info = cgpu->device_data;
+	
+	info->temp_max = 0;
+	info->no_matching_work = 0;
+	
+	for (int i = 0; i < info->miner_count; ++i)
+		info->matching_work[i] = 0;
+}
+
 static bool avalon_detect_one(const char *devpath)
 static bool avalon_detect_one(const char *devpath)
 {
 {
 	struct avalon_info *info;
 	struct avalon_info *info;
@@ -573,7 +585,7 @@ static bool avalon_detect_one(const char *devpath)
 			    AVALON_TIME_FACTOR) / (float)info->miner_count;
 			    AVALON_TIME_FACTOR) / (float)info->miner_count;
 
 
 	info->fan_pwm = AVALON_DEFAULT_FAN_MIN_PWM;
 	info->fan_pwm = AVALON_DEFAULT_FAN_MIN_PWM;
-	info->temp_max = 0;
+	avalon_zero_stats(avalon);
 	/* This is for check the temp/fan every 3~4s */
 	/* This is for check the temp/fan every 3~4s */
 	info->temp_history_count = (4 / (float)((float)info->timeout * ((float)1.67/0x32))) + 1;
 	info->temp_history_count = (4 / (float)((float)info->timeout * ((float)1.67/0x32))) + 1;
 	if (info->temp_history_count <= 0)
 	if (info->temp_history_count <= 0)
@@ -987,6 +999,7 @@ struct device_drv avalon_drv = {
 	.minerloop = hash_queued_work,
 	.minerloop = hash_queued_work,
 	.queue_full = avalon_fill,
 	.queue_full = avalon_fill,
 	.scanwork = avalon_scanhash,
 	.scanwork = avalon_scanhash,
+	.zero_stats = avalon_zero_stats,
 	.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,

+ 1 - 0
driver-avalon.h

@@ -1,6 +1,7 @@
 /*
 /*
  * Copyright 2013 Avalon project
  * Copyright 2013 Avalon project
  * Copyright 2013 Con Kolivas
  * Copyright 2013 Con Kolivas
+ * Copyright 2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free

+ 952 - 0
driver-avalonmm.c

@@ -0,0 +1,952 @@
+/*
+ * Copyright 2014 Luke Dashjr
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <utlist.h>
+
+#include "deviceapi.h"
+#include "logging.h"
+#include "lowlevel.h"
+#include "lowl-vcom.h"
+#include "miner.h"
+#include "util.h"
+#include "work2d.h"
+
+#define AVALONMM_MAX_MODULES  4
+#define AVALONMM_MAX_COINBASE_SIZE  (6 * 1024)
+#define AVALONMM_MAX_MERKLES  20
+#define AVALONMM_MAX_NONCE_DIFF  0x20
+
+// Must be a power of two
+#define AVALONMM_CACHED_JOBS  2
+
+#define AVALONMM_NONCE_OFFSET  0x180
+
+BFG_REGISTER_DRIVER(avalonmm_drv)
+static const struct bfg_set_device_definition avalonmm_set_device_funcs[];
+
+#define AVALONMM_PKT_DATA_SIZE  0x20
+#define AVALONMM_PKT_SIZE  (AVALONMM_PKT_DATA_SIZE + 7)
+
+enum avalonmm_cmd {
+	AMC_DETECT     = 0x0a,
+	AMC_NEW_JOB    = 0x0b,
+	AMC_JOB_ID     = 0x0c,
+	AMC_COINBASE   = 0x0d,
+	AMC_MERKLES    = 0x0e,
+	AMC_BLKHDR     = 0x0f,
+	AMC_POLL       = 0x10,
+	AMC_TARGET     = 0x11,
+	AMC_START      = 0x13,
+};
+
+enum avalonmm_reply {
+	AMR_NONCE      = 0x17,
+	AMR_STATUS     = 0x18,
+	AMR_DETECT_ACK = 0x19,
+};
+
+static
+bool avalonmm_write_cmd(const int fd, const enum avalonmm_cmd cmd, const void *data, size_t datasz)
+{
+	uint8_t packets = ((datasz + AVALONMM_PKT_DATA_SIZE - 1) / AVALONMM_PKT_DATA_SIZE) ?: 1;
+	uint8_t pkt[AVALONMM_PKT_SIZE] = {'A', 'V', cmd, 1, packets};
+	uint16_t crc;
+	ssize_t r;
+	while (true)
+	{
+		size_t copysz = AVALONMM_PKT_DATA_SIZE;
+		if (datasz < copysz)
+		{
+			copysz = datasz;
+			memset(&pkt[5 + copysz], '\0', AVALONMM_PKT_DATA_SIZE - copysz);
+		}
+		if (copysz)
+			memcpy(&pkt[5], data, copysz);
+		crc = crc16xmodem(&pkt[5], AVALONMM_PKT_DATA_SIZE);
+		pk_u16be(pkt, 5 + AVALONMM_PKT_DATA_SIZE, crc);
+		r = write(fd, pkt, sizeof(pkt));
+		if (opt_dev_protocol)
+		{
+			char hex[(sizeof(pkt) * 2) + 1];
+			bin2hex(hex, pkt, sizeof(pkt));
+			applog(LOG_DEBUG, "DEVPROTO fd=%d SEND: %s => %d", fd, hex, (int)r);
+		}
+		if (sizeof(pkt) != r)
+			return false;
+		datasz -= copysz;
+		if (!datasz)
+			break;
+		data += copysz;
+		++pkt[3];
+	}
+	return true;
+}
+
+static
+ssize_t avalonmm_read(const int fd, const int logprio, enum avalonmm_reply *out_reply, void * const bufp, size_t bufsz)
+{
+	uint8_t *buf = bufp;
+	uint8_t pkt[AVALONMM_PKT_SIZE];
+	uint8_t packets = 0, got = 0;
+	uint16_t good_crc, actual_crc;
+	ssize_t r;
+	while (true)
+	{
+		r = serial_read(fd, pkt, sizeof(pkt));
+		if (opt_dev_protocol)
+		{
+			if (r >= 0)
+			{
+				char hex[(r * 2) + 1];
+				bin2hex(hex, pkt, r);
+				applog(LOG_DEBUG, "DEVPROTO fd=%d RECV: %s", fd, hex);
+			}
+			else
+				applog(LOG_DEBUG, "DEVPROTO fd=%d RECV (%d)", fd, (int)r);
+		}
+		if (r != sizeof(pkt))
+			return -1;
+		if (memcmp(pkt, "AV", 2))
+			applogr(-1, logprio, "%s: bad header", __func__);
+		good_crc = crc16xmodem(&pkt[5], AVALONMM_PKT_DATA_SIZE);
+		actual_crc = upk_u16le(pkt, 5 + AVALONMM_PKT_DATA_SIZE);
+		if (good_crc != actual_crc)
+			applogr(-1, logprio, "%s: bad CRC (good=%04x actual=%04x)", __func__, good_crc, actual_crc);
+		*out_reply = pkt[2];
+		if (!got)
+		{
+			if (pkt[3] != 1)
+				applogr(-1, logprio, "%s: first packet is not index 1", __func__);
+			++got;
+			packets = pkt[4];
+		}
+		else
+		{
+			if (pkt[3] != ++got)
+				applogr(-1, logprio, "%s: packet %d is not index %d", __func__, got, got);
+			if (pkt[4] != packets)
+				applogr(-1, logprio, "%s: packet %d total packet count is %d rather than original value of %d", __func__, got, pkt[4], packets);
+		}
+		if (bufsz)
+		{
+			if (likely(bufsz > AVALONMM_PKT_DATA_SIZE))
+			{
+				memcpy(buf, &pkt[5], AVALONMM_PKT_DATA_SIZE);
+				bufsz -= AVALONMM_PKT_DATA_SIZE;
+				buf += AVALONMM_PKT_DATA_SIZE;
+			}
+			else
+			{
+				memcpy(buf, &pkt[5], bufsz);
+				bufsz = 0;
+			}
+		}
+		if (got == packets)
+			break;
+	}
+	return (((ssize_t)got) * AVALONMM_PKT_DATA_SIZE);
+}
+
+struct avalonmm_init_data {
+	int module_id;
+	uint32_t mmversion;
+};
+
+static
+bool avalonmm_detect_one(const char * const devpath)
+{
+	uint8_t buf[AVALONMM_PKT_DATA_SIZE] = {0};
+	enum avalonmm_reply reply;
+	const int fd = serial_open(devpath, 115200, 1, true);
+	struct cgpu_info *prev_cgpu = NULL;
+	if (fd == -1)
+		applogr(false, LOG_DEBUG, "%s: Failed to open %s", __func__, devpath);
+	
+	for (int i = 0; i < AVALONMM_MAX_MODULES; ++i)
+	{
+		pk_u32be(buf, AVALONMM_PKT_DATA_SIZE - 4, i);
+		avalonmm_write_cmd(fd, AMC_DETECT, buf, AVALONMM_PKT_DATA_SIZE);
+	}
+	
+	while (avalonmm_read(fd, LOG_DEBUG, &reply, buf, AVALONMM_PKT_DATA_SIZE) > 0)
+	{
+		if (reply != AMR_DETECT_ACK)
+			continue;
+		
+		int moduleno = upk_u32be(buf, AVALONMM_PKT_DATA_SIZE - 4);
+		uint32_t mmversion;
+		{
+			char mmver[5];
+			memcpy(mmver, buf, 4);
+			mmver[4] = '\0';
+			mmversion = atol(mmver);
+		}
+		
+		if (!prev_cgpu)
+		{
+			if (serial_claim_v(devpath, &avalonmm_drv))
+			{
+				serial_close(fd);
+				return false;
+			}
+		}
+		
+		struct avalonmm_init_data * const initdata = malloc(sizeof(*initdata));
+		*initdata = (struct avalonmm_init_data){
+			.module_id = moduleno,
+			.mmversion = mmversion,
+		};
+		
+		struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
+		*cgpu = (struct cgpu_info){
+			.drv = &avalonmm_drv,
+			.device_path = prev_cgpu ? prev_cgpu->device_path : strdup(devpath),
+			.device_data = initdata,
+			.set_device_funcs = avalonmm_set_device_funcs,
+			.deven = DEV_ENABLED,
+			.procs = 1,
+			.threads = prev_cgpu ? 0 : 1,
+		};
+		
+		add_cgpu_slave(cgpu, prev_cgpu);
+		prev_cgpu = cgpu;
+	}
+	
+	serial_close(fd);
+	
+	return prev_cgpu;
+}
+
+static
+bool avalonmm_lowl_probe(const struct lowlevel_device_info * const info)
+{
+	return vcom_lowl_probe_wrapper(info, avalonmm_detect_one);
+}
+
+struct avalonmm_job {
+	struct stratum_work swork;
+	uint32_t jobid;
+	struct timeval tv_prepared;
+	double nonce_diff;
+};
+
+struct avalonmm_chain_state {
+	uint32_t xnonce1;
+	struct avalonmm_job *jobs[AVALONMM_CACHED_JOBS];
+	uint32_t next_jobid;
+	
+	uint32_t fan_desired;
+	uint32_t clock_desired;
+	uint32_t voltcfg_desired;
+};
+
+struct avalonmm_module_state {
+	uint32_t module_id;
+	uint32_t mmversion;
+	uint16_t temp[2];
+	uint16_t fan[2];
+	uint32_t clock_actual;
+	uint32_t voltcfg_actual;
+};
+
+static
+uint16_t avalonmm_voltage_config_from_dmvolts(uint32_t dmvolts)
+{
+	return ((uint16_t)bitflip8((0x78 - dmvolts / 125) << 1 | 1)) << 8;
+}
+
+// Potentially lossy!
+static
+uint32_t avalonmm_dmvolts_from_voltage_config(uint32_t voltcfg)
+{
+	return (0x78 - (bitflip8(voltcfg >> 8) >> 1)) * 125;
+}
+
+static
+uint32_t avalonmm_fan_config_from_percent(uint8_t percent)
+{
+	return (0x3ff - percent * 0x3ff / 100);
+}
+
+static
+uint8_t avalonmm_fan_percent_from_config(uint32_t cfg)
+{
+	return (0x3ff - cfg) * 100 / 0x3ff;
+}
+
+static struct cgpu_info *avalonmm_dev_for_module_id(struct cgpu_info *, uint32_t);
+static bool avalonmm_poll_once(struct cgpu_info *, int64_t *);
+
+static
+bool avalonmm_init(struct thr_info * const master_thr)
+{
+	struct cgpu_info * const master_dev = master_thr->cgpu, *dev = NULL;
+	struct avalonmm_init_data * const master_initdata = master_dev->device_data;
+	const char * const devpath = master_dev->device_path;
+	const int fd = serial_open(devpath, 115200, 1, true);
+	uint8_t buf[AVALONMM_PKT_DATA_SIZE] = {0};
+	int64_t module_id;
+	
+	master_dev->device_fd = fd;
+	if (unlikely(fd == -1))
+		applogr(false, LOG_ERR, "%s: Failed to initialise", master_dev->dev_repr);
+	
+	struct avalonmm_chain_state * const chain = malloc(sizeof(*chain));
+	*chain = (struct avalonmm_chain_state){
+		.fan_desired = avalonmm_fan_config_from_percent(90),
+	};
+	
+	switch (master_initdata->mmversion)
+	{
+		case 2014:
+			chain->voltcfg_desired = avalonmm_voltage_config_from_dmvolts(10000);
+			break;
+		default:
+			chain->voltcfg_desired = avalonmm_voltage_config_from_dmvolts(6625);
+	}
+	
+	work2d_init();
+	if (!reserve_work2d_(&chain->xnonce1))
+	{
+		applog(LOG_ERR, "%s: Failed to reserve 2D work", master_dev->dev_repr);
+		free(chain);
+		serial_close(fd);
+		return false;
+	}
+	
+	for_each_managed_proc(proc, master_dev)
+	{
+		if (dev == proc->device)
+			continue;
+		dev = proc->device;
+		
+		struct thr_info * const thr = proc->thr[0];
+		struct avalonmm_init_data * const initdata = dev->device_data;
+		
+		struct avalonmm_module_state * const module = malloc(sizeof(*module));
+		*module = (struct avalonmm_module_state){
+			.module_id = initdata->module_id,
+			.mmversion = initdata->mmversion,
+		};
+		
+		free(initdata);
+		proc->device_data = chain;
+		thr->cgpu_data = module;
+	}
+	
+	dev = NULL;
+	for_each_managed_proc(proc, master_dev)
+	{
+		cgpu_set_defaults(proc);
+		proc->status = LIFE_INIT2;
+	}
+	
+	if (!chain->clock_desired)
+	{
+		// Get a reasonable default frequency
+		dev = master_dev;
+		struct thr_info * const thr = dev->thr[0];
+		struct avalonmm_module_state * const module = thr->cgpu_data;
+		
+resend:
+		pk_u32be(buf, AVALONMM_PKT_DATA_SIZE - 4, module->module_id);
+		avalonmm_write_cmd(fd, AMC_POLL, buf, AVALONMM_PKT_DATA_SIZE);
+		
+		while (avalonmm_poll_once(master_dev, &module_id))
+		{
+			if (module_id != module->module_id)
+				continue;
+			
+			if (module->clock_actual)
+			{
+				chain->clock_desired = module->clock_actual;
+				break;
+			}
+			else
+				goto resend;
+		}
+		
+		if (!chain->clock_desired)
+		{
+			switch (module->mmversion)
+			{
+				case 2014:
+					chain->clock_desired = 1500;
+					break;
+				case 3314:
+					chain->clock_desired = 450;
+					break;
+			}
+		}
+	}
+	
+	if (likely(chain->clock_desired))
+		applog(LOG_DEBUG, "%s: Frequency is initialised with %d MHz", master_dev->dev_repr, chain->clock_desired);
+	else
+		applogr(false, LOG_ERR, "%s: No frequency detected, please use --set %s@%s:clock=MHZ", master_dev->dev_repr, master_dev->drv->dname, devpath);
+	
+	return true;
+}
+
+static
+bool avalonmm_send_swork(const int fd, struct avalonmm_chain_state * const chain, const struct stratum_work * const swork, uint32_t jobid, double *out_nonce_diff)
+{
+	uint8_t buf[AVALONMM_PKT_DATA_SIZE];
+	bytes_t coinbase = BYTES_INIT;
+	
+	int coinbase_len = bytes_len(&swork->coinbase);
+	if (coinbase_len > AVALONMM_MAX_COINBASE_SIZE)
+		return false;
+	
+	if (swork->merkles > AVALONMM_MAX_MERKLES)
+		return false;
+	
+	pk_u32be(buf,    0, coinbase_len);
+	
+	const size_t xnonce2_offset = swork->nonce2_offset + work2d_pad_xnonce_size(swork) + work2d_xnonce1sz;
+	pk_u32be(buf,    4, xnonce2_offset);
+	
+	pk_u32be(buf,    8, 4);  // extranonce2 size, but only 4 is supported - smaller sizes are handled by limiting the range
+	pk_u32be(buf, 0x0c, 0x24);  // merkle_offset, always 0x24 for Bitcoin
+	pk_u32be(buf, 0x10, swork->merkles);
+	pk_u32be(buf, 0x14, 1);  // diff? poorly defined
+	pk_u32be(buf, 0x18, 0);  // pool number - none of its business
+	if (!avalonmm_write_cmd(fd, AMC_NEW_JOB, buf, 0x1c))
+		return false;
+	
+	double nonce_diff = target_diff(swork->target);
+	if (nonce_diff >= AVALONMM_MAX_NONCE_DIFF)
+		set_target_to_pdiff(buf, nonce_diff = AVALONMM_MAX_NONCE_DIFF);
+	else
+		memcpy(buf, swork->target, 0x20);
+	*out_nonce_diff = nonce_diff;
+	if (!avalonmm_write_cmd(fd, AMC_TARGET, buf, 0x20))
+		return false;
+	
+	pk_u32be(buf, 0, jobid);
+	if (!avalonmm_write_cmd(fd, AMC_JOB_ID, buf, 4))
+		return false;
+	
+	// Need to add extranonce padding and extranonce2
+	bytes_cpy(&coinbase, &swork->coinbase);
+	uint8_t *cbp = bytes_buf(&coinbase);
+	cbp += swork->nonce2_offset;
+	work2d_pad_xnonce(cbp, swork, false);
+	cbp += work2d_pad_xnonce_size(swork);
+	memcpy(cbp, &chain->xnonce1, work2d_xnonce1sz);
+	cbp += work2d_xnonce1sz;
+	if (!avalonmm_write_cmd(fd, AMC_COINBASE, bytes_buf(&coinbase), bytes_len(&coinbase)))
+		return false;
+	
+	if (!avalonmm_write_cmd(fd, AMC_MERKLES, bytes_buf(&swork->merkle_bin), bytes_len(&swork->merkle_bin)))
+		return false;
+	
+	uint8_t header_bin[0x80];
+	memcpy(&header_bin[   0], swork->header1, 0x24);
+	memset(&header_bin[0x24], '\0', 0x20);  // merkle root
+	pk_u32be(header_bin, 0x44, swork->ntime);
+	memcpy(&header_bin[0x48], swork->diffbits, 4);
+	memset(&header_bin[0x4c], '\0', 4);  // nonce
+	memcpy(&header_bin[0x50], bfg_workpadding_bin, 0x30);
+	if (!avalonmm_write_cmd(fd, AMC_BLKHDR, header_bin, sizeof(header_bin)))
+		return false;
+	
+	// Avalon MM cannot handle xnonce2_size other than 4, and works in big endian, so we use a range to ensure the following bytes match
+	const int fixed_mm_xnonce2_bytes = (work2d_xnonce2sz >= 4) ? 0 : (4 - work2d_xnonce2sz);
+	uint8_t mm_xnonce2_start[4];
+	uint32_t xnonce2_range;
+	memset(mm_xnonce2_start, '\0', 4);
+	cbp += work2d_xnonce2sz;
+	for (int i = 1; i <= fixed_mm_xnonce2_bytes; ++i)
+		mm_xnonce2_start[fixed_mm_xnonce2_bytes - i] = cbp++[0];
+	if (fixed_mm_xnonce2_bytes > 0)
+		xnonce2_range = (1 << (8 * work2d_xnonce2sz)) - 1;
+	else
+		xnonce2_range = 0xffffffff;
+	
+	pk_u32be(buf, 0, chain->fan_desired);
+	pk_u32be(buf, 4, chain->voltcfg_desired);
+	pk_u32be(buf, 8, chain->clock_desired);
+	memcpy(&buf[0xc], mm_xnonce2_start, 4);
+	pk_u32be(buf, 0x10, xnonce2_range);
+	if (!avalonmm_write_cmd(fd, AMC_START, buf, 0x14))
+		return false;
+	
+	return true;
+}
+
+static
+void avalonmm_free_job(struct avalonmm_job * const mmjob)
+{
+	stratum_work_clean(&mmjob->swork);
+	free(mmjob);
+}
+
+static
+bool avalonmm_update_swork_from_pool(struct cgpu_info * const master_dev, struct pool * const pool)
+{
+	struct avalonmm_chain_state * const chain = master_dev->device_data;
+	const int fd = master_dev->device_fd;
+	struct avalonmm_job *mmjob = malloc(sizeof(*mmjob));
+	*mmjob = (struct avalonmm_job){
+		.jobid = chain->next_jobid,
+	};
+	cg_rlock(&pool->data_lock);
+	stratum_work_cpy(&mmjob->swork, &pool->swork);
+	cg_runlock(&pool->data_lock);
+	timer_set_now(&mmjob->tv_prepared);
+	mmjob->swork.data_lock_p = NULL;
+	if (!avalonmm_send_swork(fd, chain, &mmjob->swork, mmjob->jobid, &mmjob->nonce_diff))
+	{
+		avalonmm_free_job(mmjob);
+		return false;
+	}
+	applog(LOG_DEBUG, "%s: Upload of job id %08lx complete", master_dev->dev_repr, (unsigned long)mmjob->jobid);
+	++chain->next_jobid;
+	
+	struct avalonmm_job **jobentry = &chain->jobs[mmjob->jobid % AVALONMM_CACHED_JOBS];
+	if (*jobentry)
+		avalonmm_free_job(*jobentry);
+	*jobentry = mmjob;
+	
+	return true;
+}
+
+static
+struct cgpu_info *avalonmm_dev_for_module_id(struct cgpu_info * const master_dev, const uint32_t module_id)
+{
+	struct cgpu_info *dev = NULL;
+	for_each_managed_proc(proc, master_dev)
+	{
+		if (dev == proc->device)
+			continue;
+		dev = proc->device;
+		
+		struct thr_info * const thr = dev->thr[0];
+		struct avalonmm_module_state * const module = thr->cgpu_data;
+		
+		if (module->module_id == module_id)
+			return dev;
+	}
+	return NULL;
+}
+
+static
+bool avalonmm_poll_once(struct cgpu_info * const master_dev, int64_t *out_module_id)
+{
+	struct avalonmm_chain_state * const chain = master_dev->device_data;
+	const int fd = master_dev->device_fd;
+	uint8_t buf[AVALONMM_PKT_DATA_SIZE];
+	enum avalonmm_reply reply;
+	
+	*out_module_id = -1;
+	
+	if (avalonmm_read(fd, LOG_ERR, &reply, buf, sizeof(buf)) < 0)
+		return false;
+	
+	switch (reply)
+	{
+		case AMR_DETECT_ACK:
+			break;
+		
+		case AMR_STATUS:
+		{
+			const uint32_t module_id = upk_u32be(buf, AVALONMM_PKT_DATA_SIZE - 4);
+			struct cgpu_info * const dev = avalonmm_dev_for_module_id(master_dev, module_id);
+			
+			if (unlikely(!dev))
+			{
+				struct thr_info * const master_thr = master_dev->thr[0];
+				applog(LOG_ERR, "%s: %s for unknown module id %lu", master_dev->dev_repr, "Status", (unsigned long)module_id);
+				inc_hw_errors_only(master_thr);
+				break;
+			}
+			
+			*out_module_id = module_id;
+			
+			struct thr_info * const thr = dev->thr[0];
+			struct avalonmm_module_state * const module = thr->cgpu_data;
+			
+			module->temp[0] = upk_u16be(buf,    0);
+			module->temp[1] = upk_u16be(buf,    2);
+			module->fan [0] = upk_u16be(buf,    4);
+			module->fan [1] = upk_u16be(buf,    6);
+			module->clock_actual = upk_u32be(buf, 8);
+			module->voltcfg_actual = upk_u32be(buf, 0x0c);
+			
+			dev->temp = max(module->temp[0], module->temp[1]);
+			
+			break;
+		}
+		case AMR_NONCE:
+		{
+			const int fixed_mm_xnonce2_bytes = (work2d_xnonce2sz >= 4) ? 0 : (4 - work2d_xnonce2sz);
+			const uint8_t * const backward_xnonce2 = &buf[8 + fixed_mm_xnonce2_bytes];
+			const uint32_t nonce = upk_u32be(buf, 0x10) - AVALONMM_NONCE_OFFSET;
+			const uint32_t jobid = upk_u32be(buf, 0x14);
+			const uint32_t module_id = upk_u32be(buf, AVALONMM_PKT_DATA_SIZE - 4);
+			struct cgpu_info * const dev = avalonmm_dev_for_module_id(master_dev, module_id);
+			
+			if (unlikely(!dev))
+			{
+				struct thr_info * const master_thr = master_dev->thr[0];
+				applog(LOG_ERR, "%s: %s for unknown module id %lu", master_dev->dev_repr, "Nonce", (unsigned long)module_id);
+				inc_hw_errors_only(master_thr);
+				break;
+			}
+			
+			*out_module_id = module_id;
+			
+			struct thr_info * const thr = dev->thr[0];
+			
+			bool invalid_jobid = false;
+			if (unlikely((uint32_t)(chain->next_jobid - AVALONMM_CACHED_JOBS) > chain->next_jobid))
+				// Jobs wrap around
+				invalid_jobid = (jobid < chain->next_jobid - AVALONMM_CACHED_JOBS && jobid >= chain->next_jobid);
+			else
+				invalid_jobid = (jobid < chain->next_jobid - AVALONMM_CACHED_JOBS || jobid >= chain->next_jobid);
+			struct avalonmm_job * const mmjob = chain->jobs[jobid % AVALONMM_CACHED_JOBS];
+			if (unlikely(invalid_jobid || !mmjob))
+			{
+				applog(LOG_ERR, "%s: Bad job id %08lx", dev->dev_repr, (unsigned long)jobid);
+				inc_hw_errors_only(thr);
+				break;
+			}
+			
+			uint8_t xnonce2[work2d_xnonce2sz];
+			for (int i = 0; i < work2d_xnonce2sz; ++i)
+				xnonce2[i] = backward_xnonce2[(work2d_xnonce2sz - 1) - i];
+			
+			work2d_submit_nonce(thr, &mmjob->swork, &mmjob->tv_prepared, xnonce2, chain->xnonce1, nonce, mmjob->swork.ntime, NULL, mmjob->nonce_diff);
+			hashes_done2(thr, mmjob->nonce_diff * 0x100000000, NULL);
+			break;
+		}
+	}
+	
+	return true;
+}
+
+static
+void avalonmm_poll(struct cgpu_info * const master_dev, int n)
+{
+	int64_t dummy;
+	while (n > 0)
+	{
+		if (avalonmm_poll_once(master_dev, &dummy))
+			--n;
+	}
+}
+
+static
+struct thr_info *avalonmm_should_disable(struct cgpu_info * const master_dev)
+{
+	for_each_managed_proc(proc, master_dev)
+	{
+		struct thr_info * const thr = proc->thr[0];
+		if (thr->pause || proc->deven != DEV_ENABLED)
+			return thr;
+	}
+	return NULL;
+}
+
+static
+void avalonmm_minerloop(struct thr_info * const master_thr)
+{
+	struct cgpu_info * const master_dev = master_thr->cgpu;
+	const int fd = master_dev->device_fd;
+	struct pool *nextpool = current_pool(), *pool = NULL;
+	uint8_t buf[AVALONMM_PKT_DATA_SIZE] = {0};
+	
+	while (likely(!master_dev->shutdown))
+	{
+		if (avalonmm_should_disable(master_dev))
+		{
+			struct thr_info *thr;
+			while ( (thr = avalonmm_should_disable(master_dev)) )
+			{
+				if (!thr->_mt_disable_called)
+					if (avalonmm_write_cmd(fd, AMC_NEW_JOB, NULL, 0))
+					{
+						for_each_managed_proc(proc, master_dev)
+						{
+							struct thr_info * const thr = proc->thr[0];
+							mt_disable_start(thr);
+						}
+					}
+				notifier_read(thr->notifier);
+			}
+			for_each_managed_proc(proc, master_dev)
+			{
+				struct thr_info * const thr = proc->thr[0];
+				mt_disable_finish(thr);
+			}
+		}
+		
+		master_thr->work_restart = false;
+		if (!pool_has_usable_swork(nextpool))
+			; // FIXME
+		else
+		if (avalonmm_update_swork_from_pool(master_dev, nextpool))
+			pool = nextpool;
+		
+		while (likely(!(master_thr->work_restart || ((nextpool = current_pool()) != pool && pool_has_usable_swork(nextpool)) || avalonmm_should_disable(master_dev))))
+		{
+			cgsleep_ms(10);
+			
+			struct cgpu_info *dev = NULL;
+			for_each_managed_proc(proc, master_dev)
+			{
+				if (dev == proc->device)
+					continue;
+				dev = proc->device;
+				
+				struct thr_info * const thr = dev->thr[0];
+				struct avalonmm_module_state * const module = thr->cgpu_data;
+				
+				pk_u32be(buf, AVALONMM_PKT_DATA_SIZE - 4, module->module_id);
+				
+				avalonmm_write_cmd(fd, AMC_POLL, buf, AVALONMM_PKT_DATA_SIZE);
+				avalonmm_poll(master_dev, 1);
+			}
+		}
+	}
+}
+
+static
+const char *avalonmm_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 cgpu_info * const dev = proc->device;
+	struct avalonmm_chain_state * const chain = dev->device_data;
+	
+	const int nv = atoi(newvalue);
+	if (nv < 0)
+		return "Invalid clock";
+	
+	chain->clock_desired = nv;
+	
+	return NULL;
+}
+
+static
+const char *avalonmm_set_fan(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 avalonmm_chain_state * const chain = dev->device_data;
+	
+	const int nv = atoi(newvalue);
+	if (nv < 0 || nv > 100)
+		return "Invalid fan speed";
+	
+	chain->fan_desired = avalonmm_fan_config_from_percent(nv);
+	
+	return NULL;
+}
+
+static
+const char *avalonmm_set_voltage(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	struct cgpu_info * const dev = proc->device;
+	struct avalonmm_chain_state * const chain = dev->device_data;
+	
+	const long val = atof(newvalue) * 10000;
+	if (val < 0 || val > 15000)
+		return "Invalid voltage value";
+	
+	chain->voltcfg_desired = avalonmm_voltage_config_from_dmvolts(val);
+	
+	return NULL;
+}
+
+static const struct bfg_set_device_definition avalonmm_set_device_funcs[] = {
+	{"clock", avalonmm_set_clock, "clock frequency"},
+	{"fan", avalonmm_set_fan, "fan speed (0-100 percent)"},
+	{"voltage", avalonmm_set_voltage, "voltage (0 to 1.5 volts)"},
+	{NULL},
+};
+
+static
+struct api_data *avalonmm_api_extra_device_detail(struct cgpu_info * const proc)
+{
+	struct cgpu_info * const dev = proc->device;
+	struct avalonmm_chain_state * const chain = dev->device_data;
+	struct thr_info * const thr = dev->thr[0];
+	struct avalonmm_module_state * const module = thr->cgpu_data;
+	struct api_data *root = NULL;
+	
+	root = api_add_uint32(root, "Module Id", &module->module_id, false);
+	root = api_add_uint32(root, "ExtraNonce1", &chain->xnonce1, false);
+	
+	return root;
+}
+
+static
+struct api_data *avalonmm_api_extra_device_status(struct cgpu_info * const proc)
+{
+	struct cgpu_info * const dev = proc->device;
+	struct avalonmm_chain_state * const chain = dev->device_data;
+	struct thr_info * const thr = dev->thr[0];
+	struct avalonmm_module_state * const module = thr->cgpu_data;
+	struct api_data *root = NULL;
+	char buf[0x10];
+	
+	strcpy(buf, "Temperature");
+	for (int i = 0; i < 2; ++i)
+	{
+		if (module->temp[i])
+		{
+			float temp = module->temp[i];
+			buf[0xb] = '0' + i;
+			root = api_add_temp(root, buf, &temp, true);
+		}
+	}
+	
+	{
+		uint8_t fan_percent = avalonmm_fan_percent_from_config(chain->fan_desired);
+		root = api_add_uint8(root, "Fan Percent", &fan_percent, true);
+	}
+	
+	strcpy(buf, "Fan RPM ");
+	for (int i = 0; i < 2; ++i)
+	{
+		if (module->fan[i])
+		{
+			buf[8] = '0' + i;
+			root = api_add_uint16(root, buf, &module->fan[i], false);
+		}
+	}
+	
+	if (module->clock_actual)
+	{
+		double freq = module->clock_actual;
+		root = api_add_freq(root, "Frequency", &freq, true);
+	}
+	
+	if (module->voltcfg_actual)
+	{
+		float volts = avalonmm_dmvolts_from_voltage_config(module->voltcfg_actual);
+		volts /= 10000;
+		root = api_add_volts(root, "Voltage", &volts, true);
+	}
+	
+	return root;
+}
+
+#ifdef HAVE_CURSES
+static
+void avalonmm_wlogprint_status(struct cgpu_info * const proc)
+{
+	struct cgpu_info * const dev = proc->device;
+	struct avalonmm_chain_state * const chain = dev->device_data;
+	struct thr_info * const thr = dev->thr[0];
+	struct avalonmm_module_state * const module = thr->cgpu_data;
+	
+	wlogprint("ExtraNonce1:%0*lx  ModuleId:%lu\n", work2d_xnonce1sz * 2, (unsigned long)chain->xnonce1, (unsigned long)module->module_id);
+	
+	if (module->temp[0] && module->temp[1])
+	{
+		wlogprint("Temperatures: %uC %uC", (unsigned)module->temp[0], (unsigned)module->temp[1]);
+		if (module->fan[0] || module->fan[1])
+			wlogprint("  ");
+	}
+	unsigned fan_percent = avalonmm_fan_percent_from_config(chain->fan_desired);
+	if (module->fan[0])
+	{
+		if (module->fan[1])
+			wlogprint("Fans: %u RPM, %u RPM (%u%%)", (unsigned)module->fan[0], (unsigned)module->fan[1], fan_percent);
+		else
+			wlogprint("Fan: %u RPM (%u%%)", (unsigned)module->fan[0], fan_percent);
+	}
+	else
+	if (module->fan[1])
+		wlogprint("Fan: %u RPM (%u%%)", (unsigned)module->fan[1], fan_percent);
+	else
+		wlogprint("Fan: %u%%", fan_percent);
+	wlogprint("\n");
+	
+	if (module->clock_actual)
+		wlogprint("Clock speed: %lu\n", (unsigned long)module->clock_actual);
+	
+	if (module->voltcfg_actual)
+	{
+		const uint32_t dmvolts = avalonmm_dmvolts_from_voltage_config(module->voltcfg_actual);
+		wlogprint("Voltage: %u.%04u V\n", (unsigned)(dmvolts / 10000), (unsigned)(dmvolts % 10000));
+	}
+}
+
+static
+void avalonmm_tui_wlogprint_choices(struct cgpu_info * const proc)
+{
+	wlogprint("[C]lock speed ");
+	wlogprint("[F]an speed ");
+	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";
+}
+
+static
+const char *avalonmm_tui_handle_choice(struct cgpu_info * const proc, const int input)
+{
+	switch (input)
+	{
+		case 'c': case 'C':
+			return avalonmm_tui_wrapper(proc, avalonmm_set_clock  , "Set clock speed (Avalon2: 1500; Avalon3: 450)");
+		
+		case 'f': case 'F':
+			return avalonmm_tui_wrapper(proc, avalonmm_set_fan    , "Set fan speed (0-100 percent)");
+		
+		case 'v': case 'V':
+			return avalonmm_tui_wrapper(proc, avalonmm_set_voltage, "Set voltage (Avalon2: 1.0; Avalon3: 0.6625)");
+	}
+	return NULL;
+}
+#endif
+
+struct device_drv avalonmm_drv = {
+	.dname = "avalonmm",
+	.name = "AVM",
+	
+	.lowl_probe = avalonmm_lowl_probe,
+	
+	.thread_init = avalonmm_init,
+	.minerloop = avalonmm_minerloop,
+	
+	.get_api_extra_device_detail = avalonmm_api_extra_device_detail,
+	.get_api_extra_device_status = avalonmm_api_extra_device_status,
+	
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = avalonmm_wlogprint_status,
+	.proc_tui_wlogprint_choices = avalonmm_tui_wlogprint_choices,
+	.proc_tui_handle_choice = avalonmm_tui_handle_choice,
+#endif
+};

+ 1 - 0
driver-bfx.c

@@ -131,6 +131,7 @@ bool bfx_lowl_probe(const struct lowlevel_device_info * const info)
 		if (info->lowl != &lowl_usb)
 		if (info->lowl != &lowl_usb)
 			applog(LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not ft232r!",
 			applog(LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not ft232r!",
 			       __func__, product, serial);
 			       __func__, product, serial);
+		bfg_probe_result_flags = BPR_WRONG_DEVTYPE;
 		return false;
 		return false;
 	}
 	}
 	
 	

+ 91 - 55
driver-bifury.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -9,6 +9,8 @@
 
 
 #include "config.h"
 #include "config.h"
 
 
+#include <ctype.h>
+#include <limits.h>
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdio.h>
@@ -25,9 +27,8 @@
 #include "miner.h"
 #include "miner.h"
 #include "util.h"
 #include "util.h"
 
 
-#define BIFURY_MAX_QUEUED 0x10
-
 BFG_REGISTER_DRIVER(bifury_drv)
 BFG_REGISTER_DRIVER(bifury_drv)
+static const struct bfg_set_device_definition bifury_set_device_funcs[];
 
 
 const char bifury_init_cmds[] = "flush\ntarget ffffffff\nmaxroll 0\n";
 const char bifury_init_cmds[] = "flush\ntarget ffffffff\nmaxroll 0\n";
 
 
@@ -69,11 +70,13 @@ parse:
 
 
 struct bifury_state {
 struct bifury_state {
 	bytes_t buf;
 	bytes_t buf;
-	uint32_t last_work_id;
+	work_device_id_t last_work_id;
 	int needwork;
 	int needwork;
 	bool has_needwork;
 	bool has_needwork;
 	uint8_t *osc6_bits;
 	uint8_t *osc6_bits;
 	bool send_clock;
 	bool send_clock;
+	unsigned max_queued;
+	bool free_after_job;
 };
 };
 
 
 static
 static
@@ -82,6 +85,27 @@ bool bifury_lowl_match(const struct lowlevel_device_info * const info)
 	return lowlevel_match_product(info, "bi\xe2\x80\xa2""fury");
 	return lowlevel_match_product(info, "bi\xe2\x80\xa2""fury");
 }
 }
 
 
+const char *bifury_init_chips(struct cgpu_info * const proc, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	int *procs_p = proc->device_data;
+	
+	if (!setting || !*setting)
+		return "missing setting";
+	
+	const int val = atoi(setting);
+	if (val < 1)
+		return "invalid setting";
+	
+	*procs_p = val;
+	
+	return NULL;
+}
+
+static const struct bfg_set_device_definition bifury_set_device_funcs_probe[] = {
+	{"chips", bifury_init_chips, NULL},
+	{NULL},
+};
+
 static
 static
 bool bifury_detect_one(const char * const devpath)
 bool bifury_detect_one(const char * const devpath)
 {
 {
@@ -155,10 +179,13 @@ bool bifury_detect_one(const char * const devpath)
 	if (serial_claim_v(devpath, &bifury_drv))
 	if (serial_claim_v(devpath, &bifury_drv))
 		return false;
 		return false;
 	
 	
+	drv_set_defaults(&bifury_drv, bifury_set_device_funcs_probe, &chips, devpath, detectone_meta_info.serial, 1);
+	
 	cgpu = malloc(sizeof(*cgpu));
 	cgpu = malloc(sizeof(*cgpu));
 	*cgpu = (struct cgpu_info){
 	*cgpu = (struct cgpu_info){
 		.drv = &bifury_drv,
 		.drv = &bifury_drv,
 		.device_path = strdup(devpath),
 		.device_path = strdup(devpath),
+		.set_device_funcs = bifury_set_device_funcs,
 		.deven = DEV_ENABLED,
 		.deven = DEV_ENABLED,
 		.procs = chips,
 		.procs = chips,
 		.threads = 1,
 		.threads = 1,
@@ -245,6 +272,8 @@ bool bifury_thread_init(struct thr_info *master_thr)
 	*state = (struct bifury_state){
 	*state = (struct bifury_state){
 		.buf = BYTES_INIT,
 		.buf = BYTES_INIT,
 		.osc6_bits = malloc(sizeof(*state->osc6_bits) * dev->procs),
 		.osc6_bits = malloc(sizeof(*state->osc6_bits) * dev->procs),
+		.max_queued = dev->procs * 5 + 6,
+		.free_after_job = true,
 	};
 	};
 	for (int i = 0; i < dev->procs; ++i)
 	for (int i = 0; i < dev->procs; ++i)
 		state->osc6_bits[i] = 54;
 		state->osc6_bits[i] = 54;
@@ -304,7 +333,7 @@ bool bifury_queue_append(struct thr_info * const thr, struct work *work)
 		return false;
 		return false;
 	}
 	}
 	HASH_ADD(hh, master_thr->work_list, device_id, sizeof(work->device_id), work);
 	HASH_ADD(hh, master_thr->work_list, device_id, sizeof(work->device_id), work);
-	int prunequeue = HASH_COUNT(master_thr->work_list) - BIFURY_MAX_QUEUED;
+	int prunequeue = HASH_COUNT(master_thr->work_list) - state->max_queued;
 	if (prunequeue > 0)
 	if (prunequeue > 0)
 	{
 	{
 		struct work *tmp;
 		struct work *tmp;
@@ -334,19 +363,6 @@ void bifury_queue_flush(struct thr_info * const thr)
 	bifury_set_queue_full(dev, dev->procs);
 	bifury_set_queue_full(dev, dev->procs);
 }
 }
 
 
-static
-const struct cgpu_info *device_proc_by_id(const struct cgpu_info * const dev, int procid)
-{
-	const struct cgpu_info *proc = dev;
-	for (int i = 0; i < procid; ++i)
-	{
-		proc = proc->next_proc;
-		if (unlikely(!proc))
-			return NULL;
-	}
-	return proc;
-}
-
 static
 static
 void bifury_handle_cmd(struct cgpu_info * const dev, const char * const cmd)
 void bifury_handle_cmd(struct cgpu_info * const dev, const char * const cmd)
 {
 {
@@ -363,7 +379,6 @@ void bifury_handle_cmd(struct cgpu_info * const dev, const char * const cmd)
 		const uint32_t jobid = strtoll(&p[1], &p, 0x10);
 		const uint32_t jobid = strtoll(&p[1], &p, 0x10);
 		const uint32_t ntime = strtoll(&p[1], &p, 0x10);
 		const uint32_t ntime = strtoll(&p[1], &p, 0x10);
 		const int chip = atoi(&p[1]);
 		const int chip = atoi(&p[1]);
-		nonce = le32toh(nonce);
 		const struct cgpu_info *proc = device_proc_by_id(dev, chip);
 		const struct cgpu_info *proc = device_proc_by_id(dev, chip);
 		if (unlikely(!proc))
 		if (unlikely(!proc))
 			proc = dev;
 			proc = dev;
@@ -374,6 +389,7 @@ void bifury_handle_cmd(struct cgpu_info * const dev, const char * const cmd)
 		{
 		{
 			const uint32_t work_ntime = be32toh(*(uint32_t*)&work->data[68]);
 			const uint32_t work_ntime = be32toh(*(uint32_t*)&work->data[68]);
 			submit_noffset_nonce(thr, work, nonce, ntime - work_ntime);
 			submit_noffset_nonce(thr, work, nonce, ntime - work_ntime);
+			hashes_done2(thr, 0x100000000, NULL);
 		}
 		}
 		else
 		else
 		if (!jobid)
 		if (!jobid)
@@ -410,16 +426,14 @@ void bifury_handle_cmd(struct cgpu_info * const dev, const char * const cmd)
 		HASH_FIND(hh, master_thr->work_list, &jobid, sizeof(jobid), work);
 		HASH_FIND(hh, master_thr->work_list, &jobid, sizeof(jobid), work);
 		if (likely(work))
 		if (likely(work))
 		{
 		{
-			if (likely(proc))
-			{
-				thr = proc->thr[0];
-				hashes_done2(thr, 0xbd000000, NULL);
-			}
-			else
+			if (unlikely(!proc))
 				applog(LOG_DEBUG, "%s: Unknown chip id: %s",
 				applog(LOG_DEBUG, "%s: Unknown chip id: %s",
 				       dev->dev_repr, cmd);
 				       dev->dev_repr, cmd);
-			HASH_DEL(master_thr->work_list, work);
-			free_work(work);
+			if (state->free_after_job)
+			{
+				HASH_DEL(master_thr->work_list, work);
+				free_work(work);
+			}
 		}
 		}
 		else
 		else
 			applog(LOG_WARNING, "%s: Unknown job id: %s",
 			applog(LOG_WARNING, "%s: Unknown job id: %s",
@@ -503,38 +517,54 @@ struct api_data *bifury_api_device_status(struct cgpu_info * const proc)
 	return root;
 	return root;
 }
 }
 
 
-char *bifury_set_device(struct cgpu_info * const proc, char * const option, char * const setting, char * const replybuf)
+const char *bifury_set_osc6_bits(struct cgpu_info * const proc, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
 {
 {
 	struct bifury_state * const state = proc->device_data;
 	struct bifury_state * const state = proc->device_data;
 	
 	
-	if (!strcasecmp(option, "help"))
-	{
-		sprintf(replybuf, "osc6_bits: range 33-63 (slow to fast)");
-		return replybuf;
-	}
+	if (!setting || !*setting)
+		return "missing setting";
 	
 	
-	if (!strcasecmp(option, "osc6_bits"))
-	{
-		if (!setting || !*setting)
-		{
-			sprintf(replybuf, "missing setting");
-			return replybuf;
-		}
-		const uint8_t val = atoi(setting);
-		if (val < 33 || val > 63)
-		{
-			sprintf(replybuf, "invalid setting");
-			return replybuf;
-		}
-		
-		state->osc6_bits[proc->proc_id] = val;
-		state->send_clock = true;
-		
-		return NULL;
-	}
+	const int val = atoi(setting);
+	if (val < 33 || val > 63)
+		return "invalid setting";
+	
+	state->osc6_bits[proc->proc_id] = val;
+	state->send_clock = true;
 	
 	
-	sprintf(replybuf, "Unknown option: %s", option);
-	return replybuf;
+	return NULL;
+}
+
+const char *bifury_set_max_queued(struct cgpu_info * const proc, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	struct bifury_state * const state = proc->device_data;
+	
+	if (!setting || !*setting)
+		return "missing setting";
+	
+	const long val = strtol(setting, NULL, 0);
+	if (val < 1 || val > UINT_MAX)
+		return "invalid setting";
+	
+	state->max_queued = val;
+	
+	return NULL;
+}
+
+const char *bifury_set_free_after_job(struct cgpu_info * const proc, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	struct bifury_state * const state = proc->device_data;
+	
+	if (!setting || !*setting)
+		return "missing setting";
+	
+	char *end;
+	const bool val = bfg_strtobool(setting, &end, 0);
+	if (end[0] && !isspace(end[0]))
+		return "invalid setting";
+	
+	state->free_after_job = val;
+	
+	return NULL;
 }
 }
 
 
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
@@ -572,6 +602,13 @@ void bifury_wlogprint_status(struct cgpu_info * const proc)
 }
 }
 #endif
 #endif
 
 
+static const struct bfg_set_device_definition bifury_set_device_funcs[] = {
+	{"max_queued", bifury_set_max_queued, NULL},
+	{"free_after_job", bifury_set_free_after_job, NULL},
+	{"osc6_bits", bifury_set_osc6_bits, "range 33-63 (slow to fast)"},
+	{NULL},
+};
+
 struct device_drv bifury_drv = {
 struct device_drv bifury_drv = {
 	.dname = "bifury",
 	.dname = "bifury",
 	.name = "BIF",
 	.name = "BIF",
@@ -589,7 +626,6 @@ struct device_drv bifury_drv = {
 	.poll = bifury_poll,
 	.poll = bifury_poll,
 	
 	
 	.get_api_extra_device_status = bifury_api_device_status,
 	.get_api_extra_device_status = bifury_api_device_status,
-	.set_device = bifury_set_device,
 	
 	
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 	.proc_wlogprint_status = bifury_wlogprint_status,
 	.proc_wlogprint_status = bifury_wlogprint_status,

+ 457 - 109
driver-bitforce.c

@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright 2012-2013 Luke Dashjr
- * Copyright 2012 Con Kolivas
+ * Copyright 2012-2014 Luke Dashjr
+ * Copyright 2012-2013 Con Kolivas
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -25,6 +25,9 @@
 #include "deviceapi.h"
 #include "deviceapi.h"
 #include "miner.h"
 #include "miner.h"
 #include "lowlevel.h"
 #include "lowlevel.h"
+#ifdef NEED_BFG_LOWL_MSWIN
+#include "lowl-mswin.h"
+#endif
 #include "lowl-pci.h"
 #include "lowl-pci.h"
 #include "lowl-vcom.h"
 #include "lowl-vcom.h"
 #include "util.h"
 #include "util.h"
@@ -32,6 +35,8 @@
 #define BFL_PCI_VENDOR_ID 0x1cf9
 #define BFL_PCI_VENDOR_ID 0x1cf9
 
 
 #define BITFORCE_SLEEP_MS 500
 #define BITFORCE_SLEEP_MS 500
+#define BITFORCE_VCOM_TIMEOUT_DSEC     250
+#define BITFORCE_VCOM_TIMEOUT_DSEC_ZCX  10
 #define BITFORCE_TIMEOUT_S 7
 #define BITFORCE_TIMEOUT_S 7
 #define BITFORCE_TIMEOUT_MS (BITFORCE_TIMEOUT_S * 1000)
 #define BITFORCE_TIMEOUT_MS (BITFORCE_TIMEOUT_S * 1000)
 #define BITFORCE_LONG_TIMEOUT_S 25
 #define BITFORCE_LONG_TIMEOUT_S 25
@@ -79,8 +84,10 @@ enum bitforce_style {
 struct bitforce_lowl_interface {
 struct bitforce_lowl_interface {
 	bool (*open)(struct cgpu_info *);
 	bool (*open)(struct cgpu_info *);
 	void (*close)(struct cgpu_info *);
 	void (*close)(struct cgpu_info *);
+	ssize_t (*read)(void *, size_t, struct cgpu_info *);
 	void (*gets)(char *, size_t, struct cgpu_info *);
 	void (*gets)(char *, size_t, struct cgpu_info *);
 	ssize_t (*write)(struct cgpu_info *, const void *, ssize_t);
 	ssize_t (*write)(struct cgpu_info *, const void *, ssize_t);
+	bool (*set_timeout)(struct cgpu_info* , uint8_t);
 };
 };
 
 
 struct bitforce_data {
 struct bitforce_data {
@@ -88,6 +95,7 @@ struct bitforce_data {
 	bool is_open;
 	bool is_open;
 	struct lowl_pci_handle *lph;
 	struct lowl_pci_handle *lph;
 	uint8_t lasttag;
 	uint8_t lasttag;
+	uint8_t lasttag_read;
 	bytes_t getsbuf;
 	bytes_t getsbuf;
 	int xlink_id;
 	int xlink_id;
 	unsigned char next_work_ob[70];  // Data aligned for 32-bit access
 	unsigned char next_work_ob[70];  // Data aligned for 32-bit access
@@ -114,6 +122,7 @@ struct bitforce_data {
 	float temp[2];
 	float temp[2];
 	long *volts;
 	long *volts;
 	int volts_count;
 	int volts_count;
+	unsigned max_queueid;
 	
 	
 	bool probed;
 	bool probed;
 	bool supports_fanspeed;
 	bool supports_fanspeed;
@@ -125,7 +134,7 @@ bool bitforce_vcom_open(struct cgpu_info * const dev)
 {
 {
 	struct bitforce_data * const devdata = dev->device_data;
 	struct bitforce_data * const devdata = dev->device_data;
 	const char * const devpath = dev->device_path;
 	const char * const devpath = dev->device_path;
-	dev->device_fd = serial_open(devpath, 0, 250, true);
+	dev->device_fd = serial_open(devpath, 0, BITFORCE_VCOM_TIMEOUT_DSEC, true);
 	devdata->is_open = (dev->device_fd != -1);
 	devdata->is_open = (dev->device_fd != -1);
 	return devdata->is_open;
 	return devdata->is_open;
 }
 }
@@ -142,14 +151,34 @@ void bitforce_vcom_close(struct cgpu_info * const dev)
 	}
 	}
 }
 }
 
 
+static
+ssize_t bitforce_vcom_read(void * const buf_p, size_t bufLen, struct cgpu_info * const dev)
+{
+	uint8_t *buf = buf_p;
+	const int fd = dev->device_fd;
+	ssize_t rv, ret = 0;
+	while (bufLen > 0)
+	{
+		rv = read(fd, buf, bufLen);
+		if (rv <= 0)
+		{
+			if (ret > 0)
+				return ret;
+			return rv;
+		}
+		buf += rv;
+		bufLen -= rv;
+		ret += rv;
+	}
+	return ret;
+}
+
 static
 static
 void bitforce_vcom_gets(char *buf, size_t bufLen, struct cgpu_info * const dev)
 void bitforce_vcom_gets(char *buf, size_t bufLen, struct cgpu_info * const dev)
 {
 {
 	const int fd = dev->device_fd;
 	const int fd = dev->device_fd;
-	do {
-		buf[0] = '\0';
-		--bufLen;
-	} while (likely(bufLen && read(fd, buf, 1) == 1 && (buf++)[0] != '\n'));
+	while (likely(bufLen > 1 && read(fd, buf, 1) == 1 && (buf++)[0] != '\n'))
+	{}
 
 
 	buf[0] = '\0';
 	buf[0] = '\0';
 }
 }
@@ -164,11 +193,20 @@ ssize_t bitforce_vcom_write(struct cgpu_info * const dev, const void *buf, ssize
 		return bufLen;
 		return bufLen;
 }
 }
 
 
+static
+bool bitforce_vcom_set_timeout(struct cgpu_info * const dev, const uint8_t timeout)
+{
+	const int fd = dev->device_fd;
+	return vcom_set_timeout(fd, timeout);
+}
+
 static struct bitforce_lowl_interface bfllif_vcom = {
 static struct bitforce_lowl_interface bfllif_vcom = {
 	.open = bitforce_vcom_open,
 	.open = bitforce_vcom_open,
 	.close = bitforce_vcom_close,
 	.close = bitforce_vcom_close,
+	.read = bitforce_vcom_read,
 	.gets = bitforce_vcom_gets,
 	.gets = bitforce_vcom_gets,
 	.write = bitforce_vcom_write,
 	.write = bitforce_vcom_write,
+	.set_timeout = bitforce_vcom_set_timeout,
 };
 };
 
 
 #ifdef NEED_BFG_LOWL_PCI
 #ifdef NEED_BFG_LOWL_PCI
@@ -185,6 +223,8 @@ bool bitforce_pci_open(struct cgpu_info * const dev)
 	if (!devdata->lph)
 	if (!devdata->lph)
 		return false;
 		return false;
 	devdata->lasttag = (lowl_pci_get_word(devdata->lph, 2, 2) >> 16) & 0xff;
 	devdata->lasttag = (lowl_pci_get_word(devdata->lph, 2, 2) >> 16) & 0xff;
+	devdata->lasttag_read = 0;
+	bytes_reset(&devdata->getsbuf);
 	devdata->is_open = true;
 	devdata->is_open = true;
 	return devdata->is_open;
 	return devdata->is_open;
 }
 }
@@ -201,15 +241,21 @@ void bitforce_pci_close(struct cgpu_info * const dev)
 }
 }
 
 
 static
 static
-void bitforce_pci_gets(char * const buf, size_t bufLen, struct cgpu_info * const dev)
+void _bitforce_pci_read(struct cgpu_info * const dev)
 {
 {
 	struct bitforce_data * const devdata = dev->device_data;
 	struct bitforce_data * const devdata = dev->device_data;
 	const uint32_t looking_for = (uint32_t)devdata->lasttag << 0x10;
 	const uint32_t looking_for = (uint32_t)devdata->lasttag << 0x10;
 	uint32_t resp;
 	uint32_t resp;
 	bytes_t *b = &devdata->getsbuf;
 	bytes_t *b = &devdata->getsbuf;
 	
 	
-	if (!bytes_len(&devdata->getsbuf))
+	if (devdata->lasttag != devdata->lasttag_read)
 	{
 	{
+		if (unlikely(bytes_len(b)))
+		{
+			applog(LOG_WARNING, "%s: %ld bytes remaining in read buffer at new command", dev->dev_repr, (long)bytes_len(&devdata->getsbuf));
+			bytes_reset(b);
+		}
+		
 		while (((resp = lowl_pci_get_word(devdata->lph, 2, 2)) & 0xff0000) != looking_for)
 		while (((resp = lowl_pci_get_word(devdata->lph, 2, 2)) & 0xff0000) != looking_for)
 			cgsleep_ms(1);
 			cgsleep_ms(1);
 		
 		
@@ -220,8 +266,38 @@ void bitforce_pci_gets(char * const buf, size_t bufLen, struct cgpu_info * const
 		void * const buf = bytes_preappend(b, resp + LOWL_PCI_GET_DATA_PADDING);
 		void * const buf = bytes_preappend(b, resp + LOWL_PCI_GET_DATA_PADDING);
 		if (lowl_pci_read_data(devdata->lph, buf, resp, 1, 0))
 		if (lowl_pci_read_data(devdata->lph, buf, resp, 1, 0))
 			bytes_postappend(b, resp);
 			bytes_postappend(b, resp);
+		
+		devdata->lasttag_read = devdata->lasttag;
 	}
 	}
+}
+
+static
+ssize_t bitforce_pci_read(void * const buf, const size_t bufLen, struct cgpu_info * const dev)
+{
+	struct bitforce_data * const devdata = dev->device_data;
+	bytes_t *b = &devdata->getsbuf;
 	
 	
+	_bitforce_pci_read(dev);
+	ssize_t datalen = bytes_len(b);
+	if (datalen <= 0)
+		return datalen;
+	
+	if (datalen > bufLen)
+		datalen = bufLen;
+	
+	memcpy(buf, bytes_buf(b), datalen);
+	bytes_shift(b, datalen);
+	
+	return datalen;
+}
+
+static
+void bitforce_pci_gets(char * const buf, size_t bufLen, struct cgpu_info * const dev)
+{
+	struct bitforce_data * const devdata = dev->device_data;
+	bytes_t *b = &devdata->getsbuf;
+	
+	_bitforce_pci_read(dev);
 	ssize_t linelen = (bytes_find(b, '\n') + 1) ?: bytes_len(b);
 	ssize_t linelen = (bytes_find(b, '\n') + 1) ?: bytes_len(b);
 	if (linelen > --bufLen)
 	if (linelen > --bufLen)
 		linelen = bufLen;
 		linelen = bufLen;
@@ -253,6 +329,7 @@ ssize_t bitforce_pci_write(struct cgpu_info * const dev, const void * const bufp
 static struct bitforce_lowl_interface bfllif_pci = {
 static struct bitforce_lowl_interface bfllif_pci = {
 	.open = bitforce_pci_open,
 	.open = bitforce_pci_open,
 	.close = bitforce_pci_close,
 	.close = bitforce_pci_close,
+	.read = bitforce_pci_read,
 	.gets = bitforce_pci_gets,
 	.gets = bitforce_pci_gets,
 	.write = bitforce_pci_write,
 	.write = bitforce_pci_write,
 };
 };
@@ -279,15 +356,44 @@ bool bitforce_open(struct cgpu_info * const proc)
 }
 }
 
 
 static
 static
-void bitforce_gets(char * const buf, const size_t bufLen, struct cgpu_info * const proc)
+ssize_t bitforce_read(struct cgpu_info * const proc, void * const buf, const size_t bufLen)
 {
 {
 	struct cgpu_info * const dev = proc->device;
 	struct cgpu_info * const dev = proc->device;
 	struct bitforce_data * const devdata = dev->device_data;
 	struct bitforce_data * const devdata = dev->device_data;
+	ssize_t rv;
 	
 	
-	if (unlikely(!devdata->is_open))
-		return;
+	if (likely(devdata->is_open))
+	{
+		if (bufLen == 0)
+			rv = 0;
+		else
+			rv = devdata->lowlif->read(buf, bufLen, dev);
+	}
+	else
+		rv = -1;
+	
+	if (unlikely(opt_dev_protocol))
+	{
+		size_t datalen = (rv > 0) ? rv : 0;
+		char hex[(rv * 2) + 1];
+		bin2hex(hex, buf, datalen);
+		applog(LOG_DEBUG, "DEVPROTO: %s: READ(%lu): %s",
+		       dev->dev_repr, (unsigned long)bufLen, hex);
+	}
+	
+	return rv;
+}
+
+static
+void bitforce_gets(char * const buf, const size_t bufLen, struct cgpu_info * const proc)
+{
+	struct cgpu_info * const dev = proc->device;
+	struct bitforce_data * const devdata = dev->device_data;
 	
 	
-	devdata->lowlif->gets(buf, bufLen, dev);
+	if (likely(devdata->is_open))
+		devdata->lowlif->gets(buf, bufLen, dev);
+	else
+		buf[0] = '\0';
 	
 	
 	if (unlikely(opt_dev_protocol))
 	if (unlikely(opt_dev_protocol))
 		applog(LOG_DEBUG, "DEVPROTO: %s: GETS: %s", dev->dev_repr, buf);
 		applog(LOG_DEBUG, "DEVPROTO: %s: GETS: %s", dev->dev_repr, buf);
@@ -379,23 +485,37 @@ void bitforce_cmd2(struct cgpu_info * const proc, void *buf, size_t bufsz, const
 	bitforce_gets(buf, bufsz, proc);
 	bitforce_gets(buf, bufsz, proc);
 }
 }
 
 
+static
+void bitforce_zgx(struct cgpu_info * const proc, void *buf, size_t bufsz)
+{
+	struct cgpu_info * const dev = proc->device;
+	struct bitforce_data * const devdata = dev->device_data;
+	
+	if (devdata->is_open && devdata->lowlif->set_timeout)
+	{
+		devdata->lowlif->set_timeout(dev, BITFORCE_VCOM_TIMEOUT_DSEC_ZCX);
+		bitforce_cmd1b(proc, buf, bufsz, "ZGX", 3);
+		devdata->lowlif->set_timeout(dev, BITFORCE_VCOM_TIMEOUT_DSEC);
+	}
+	else
+		bitforce_cmd1b(proc, buf, bufsz, "ZGX", 3);
+}
+
 struct bitforce_init_data {
 struct bitforce_init_data {
 	struct bitforce_lowl_interface *lowlif;
 	struct bitforce_lowl_interface *lowlif;
 	enum bitforce_style style;
 	enum bitforce_style style;
 	long devmask;
 	long devmask;
 	int *parallels;
 	int *parallels;
+	unsigned queue_depth;
+	unsigned long scan_interval_ms;
+	unsigned max_queueid;
 };
 };
 
 
 static
 static
 int bitforce_chips_to_plan_for(int parallel, int chipcount) {
 int bitforce_chips_to_plan_for(int parallel, int chipcount) {
 	if (parallel < 1)
 	if (parallel < 1)
 		return parallel;
 		return parallel;
-	if (chipcount > 15) return 32;
-	if (chipcount >  7) return 16;
-	if (chipcount >  3) return  8;
-	if (chipcount >  1) return  4;
-	if (chipcount     ) return  2;
-	                    return  1;
+	return upper_power_of_two_u32(chipcount);
 }
 }
 
 
 static
 static
@@ -404,10 +524,31 @@ bool bitforce_lowl_match(const struct lowlevel_device_info * const info)
 #ifdef NEED_BFG_LOWL_PCI
 #ifdef NEED_BFG_LOWL_PCI
 	if (info->lowl == &lowl_pci)
 	if (info->lowl == &lowl_pci)
 		return info->vid == BFL_PCI_VENDOR_ID;
 		return info->vid == BFL_PCI_VENDOR_ID;
+#endif
+#ifdef NEED_BFG_LOWL_MSWIN
+	if (lowl_mswin_match_guid(info, &WIN_GUID_DEVINTERFACE_MonarchKMDF))
+		return true;
 #endif
 #endif
 	return lowlevel_match_product(info, "BitFORCE", "SHA256");
 	return lowlevel_match_product(info, "BitFORCE", "SHA256");
 }
 }
 
 
+char *bitforce_copy_name(char * const pdevbuf)
+{
+	char *s;
+	if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>"))))
+	{
+		s[0] = '\0';
+		s = strdup(&pdevbuf[7]);
+	}
+	else
+	{
+		for (s = &pdevbuf[strlen(pdevbuf)]; isspace(*--s); )
+			*s = '\0';
+		s = strdup(pdevbuf);
+	}
+	return s;
+}
+
 static
 static
 bool bitforce_detect_oneof(const char * const devpath, struct bitforce_lowl_interface * const lowlif)
 bool bitforce_detect_oneof(const char * const devpath, struct bitforce_lowl_interface * const lowlif)
 {
 {
@@ -440,7 +581,7 @@ bool bitforce_detect_oneof(const char * const devpath, struct bitforce_lowl_inte
 		return false;
 		return false;
 	}
 	}
 
 
-	bitforce_cmd1b(&dummy_cgpu, pdevbuf, sizeof(pdevbuf), "ZGX", 3);
+	bitforce_zgx(&dummy_cgpu, pdevbuf, sizeof(pdevbuf));
 	if (unlikely(!pdevbuf[0])) {
 	if (unlikely(!pdevbuf[0])) {
 		applog(LOG_DEBUG, "BFL: Error reading/timeout (ZGX)");
 		applog(LOG_DEBUG, "BFL: Error reading/timeout (ZGX)");
 		bitforce_close(&dummy_cgpu);
 		bitforce_close(&dummy_cgpu);
@@ -460,10 +601,14 @@ bool bitforce_detect_oneof(const char * const devpath, struct bitforce_lowl_inte
 	}
 	}
 	
 	
 	applog(LOG_DEBUG, "Found BitForce device on %s", devpath);
 	applog(LOG_DEBUG, "Found BitForce device on %s", devpath);
+	
+	s = bitforce_copy_name(pdevbuf);
+	
 	initdata = malloc(sizeof(*initdata));
 	initdata = malloc(sizeof(*initdata));
 	*initdata = (struct bitforce_init_data){
 	*initdata = (struct bitforce_init_data){
 		.lowlif = lowlif,
 		.lowlif = lowlif,
 		.style = BFS_FPGA,
 		.style = BFS_FPGA,
+		.queue_depth = BITFORCE_MAX_QUEUED_MAX,
 	};
 	};
 	bitforce_cmd1b(&dummy_cgpu, pdevbuf, sizeof(pdevbuf), "ZCX", 3);
 	bitforce_cmd1b(&dummy_cgpu, pdevbuf, sizeof(pdevbuf), "ZCX", 3);
 	for (int i = 0; (!pdevbuf[0]) && i < 4; ++i)
 	for (int i = 0; (!pdevbuf[0]) && i < 4; ++i)
@@ -482,6 +627,12 @@ bool bitforce_detect_oneof(const char * const devpath, struct bitforce_lowl_inte
 		if (!strncasecmp(pdevbuf, "PROCESSOR ", 10))
 		if (!strncasecmp(pdevbuf, "PROCESSOR ", 10))
 			maxchipno = max(maxchipno, atoi(&pdevbuf[10]));
 			maxchipno = max(maxchipno, atoi(&pdevbuf[10]));
 		else
 		else
+		if (!strncasecmp(pdevbuf, "CHANNEL", 7))
+			maxchipno = max(maxchipno, atoi(&pdevbuf[7]));
+		else
+		if (!strncasecmp(pdevbuf, "CORTEX-", 7))
+			maxchipno = max(maxchipno, strtol(&pdevbuf[7], NULL, 0x10));
+		else
 		if (!strncasecmp(pdevbuf, "DEVICES IN CHAIN:", 17))
 		if (!strncasecmp(pdevbuf, "DEVICES IN CHAIN:", 17))
 			procs = atoi(&pdevbuf[17]);
 			procs = atoi(&pdevbuf[17]);
 		else
 		else
@@ -496,10 +647,19 @@ bool bitforce_detect_oneof(const char * const devpath, struct bitforce_lowl_inte
 		else
 		else
 		if (!strncasecmp(pdevbuf, "ASIC CHANNELS:", 14))
 		if (!strncasecmp(pdevbuf, "ASIC CHANNELS:", 14))
 		{
 		{
-			procs = parallel = atoi(&pdevbuf[14]);
+			parallel = atoi(&pdevbuf[14]);
 			initdata->style = BFS_28NM;
 			initdata->style = BFS_28NM;
 		}
 		}
 		else
 		else
+		if (!strncasecmp(pdevbuf, "Queue Depth:", 12))
+			initdata->queue_depth = atoi(&pdevbuf[12]);
+		else
+		if (!strncasecmp(pdevbuf, "Scan Interval:", 14))
+			initdata->scan_interval_ms = atoi(&pdevbuf[14]);
+		else
+		if (!strncasecmp(pdevbuf, "Max Queue ID:", 13))
+			initdata->max_queueid = strtol(&pdevbuf[13], NULL, 0x10);
+		else
 		if (!strncasecmp(pdevbuf, "MANUFACTURER:", 13))
 		if (!strncasecmp(pdevbuf, "MANUFACTURER:", 13))
 		{
 		{
 			manuf = &pdevbuf[13];
 			manuf = &pdevbuf[13];
@@ -566,10 +726,8 @@ bool bitforce_detect_oneof(const char * const devpath, struct bitforce_lowl_inte
 	if (initdata->style != BFS_FPGA)
 	if (initdata->style != BFS_FPGA)
 		bitforce->cutofftemp = 85;
 		bitforce->cutofftemp = 85;
 
 
-	if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
-		s[0] = '\0';
-		bitforce->name = strdup(pdevbuf + 7);
-	}
+	if (s)
+		bitforce->name = s;
 	bitforce->device_data = initdata;
 	bitforce->device_data = initdata;
 	
 	
 	// Skip fanspeed until we probe support for it
 	// Skip fanspeed until we probe support for it
@@ -592,6 +750,10 @@ bool bitforce_lowl_probe(const struct lowlevel_device_info * const info)
 #ifdef NEED_BFG_LOWL_PCI
 #ifdef NEED_BFG_LOWL_PCI
 	if (info->lowl == &lowl_pci)
 	if (info->lowl == &lowl_pci)
 		return bitforce_detect_oneof(info->path, &bfllif_pci);
 		return bitforce_detect_oneof(info->path, &bfllif_pci);
+#endif
+#ifdef NEED_BFG_LOWL_MSWIN
+	if (lowl_mswin_match_guid(info, &WIN_GUID_DEVINTERFACE_MonarchKMDF))
+		return bitforce_detect_oneof(info->path, &bfllif_vcom);
 #endif
 #endif
 	return vcom_lowl_probe_wrapper(info, bitforce_detect_one);
 	return vcom_lowl_probe_wrapper(info, bitforce_detect_one);
 }
 }
@@ -662,7 +824,6 @@ void bitforce_reinit(struct cgpu_info *bitforce)
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
 	int retries = 0;
 	int retries = 0;
 	char pdevbuf[0x100];
 	char pdevbuf[0x100];
-	char *s;
 	
 	
 	if (!procdata->handles_board)
 	if (!procdata->handles_board)
 		return;
 		return;
@@ -687,7 +848,7 @@ void bitforce_reinit(struct cgpu_info *bitforce)
 	__bitforce_clear_buffer(bitforce);
 	__bitforce_clear_buffer(bitforce);
 	
 	
 	do {
 	do {
-		bitforce_cmd1b(bitforce, pdevbuf, sizeof(pdevbuf), "ZGX", 3);
+		bitforce_zgx(bitforce, pdevbuf, sizeof(pdevbuf));
 		if (unlikely(!pdevbuf[0])) {
 		if (unlikely(!pdevbuf[0])) {
 			mutex_unlock(mutexp);
 			mutex_unlock(mutexp);
 			bitforce_close(bitforce);
 			bitforce_close(bitforce);
@@ -706,11 +867,8 @@ void bitforce_reinit(struct cgpu_info *bitforce)
 		return;
 		return;
 	}
 	}
 	
 	
-	if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
-		s[0] = '\0';
-		free((void*)bitforce->name);
-		bitforce->name = strdup(pdevbuf + 7);
-	}
+	free((void*)bitforce->name);
+	bitforce->name = bitforce_copy_name(pdevbuf);
 
 
 	bitforce->sleep_ms = data->sleep_ms_default;
 	bitforce->sleep_ms = data->sleep_ms_default;
 	
 	
@@ -1477,6 +1635,20 @@ static bool bitforce_identify(struct cgpu_info *bitforce)
 	return true;
 	return true;
 }
 }
 
 
+static
+void bitforce_zero_stats(struct cgpu_info * const proc)
+{
+	struct bitforce_data *data = proc->device_data;
+	
+	// These don't get cleared when not-read, so we clear them here
+	data->volts_count = 0;
+	data->temp[0] = data->temp[1] = 0;
+	free(data->volts);
+	data->volts = NULL;
+	
+	proc->avg_wait_f = 0;
+}
+
 static bool bitforce_thread_init(struct thr_info *thr)
 static bool bitforce_thread_init(struct thr_info *thr)
 {
 {
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct cgpu_info *bitforce = thr->cgpu;
@@ -1504,7 +1676,7 @@ static bool bitforce_thread_init(struct thr_info *thr)
 		bitforce->sleep_ms = BITFORCE_SLEEP_MS;
 		bitforce->sleep_ms = BITFORCE_SLEEP_MS;
 		bitforce->device_data = data = malloc(sizeof(*data));
 		bitforce->device_data = data = malloc(sizeof(*data));
 		*data = (struct bitforce_data){
 		*data = (struct bitforce_data){
-			.lowlif = &bfllif_vcom,
+			.lowlif = initdata->lowlif,
 			.xlink_id = xlink_id,
 			.xlink_id = xlink_id,
 			.next_work_ob = ">>>>>>>>|---------- MidState ----------||-DataTail-||Nonces|>>>>>>>>",
 			.next_work_ob = ">>>>>>>>|---------- MidState ----------||-DataTail-||Nonces|>>>>>>>>",
 			.proto = BFP_RANGE,
 			.proto = BFP_RANGE,
@@ -1512,6 +1684,7 @@ static bool bitforce_thread_init(struct thr_info *thr)
 			.sleep_ms_default = BITFORCE_SLEEP_MS,
 			.sleep_ms_default = BITFORCE_SLEEP_MS,
 			.parallel = abs(initdata->parallels[boardno]),
 			.parallel = abs(initdata->parallels[boardno]),
 			.parallel_protocol = (initdata->parallels[boardno] != -1),
 			.parallel_protocol = (initdata->parallels[boardno] != -1),
+			.max_queueid = initdata->max_queueid,
 		};
 		};
 		thr->cgpu_data = procdata = malloc(sizeof(*procdata));
 		thr->cgpu_data = procdata = malloc(sizeof(*procdata));
 		*procdata = (struct bitforce_proc_data){
 		*procdata = (struct bitforce_proc_data){
@@ -1542,8 +1715,8 @@ static bool bitforce_thread_init(struct thr_info *thr)
 				data->queued_max = data->parallel * 2;
 				data->queued_max = data->parallel * 2;
 				if (data->queued_max < BITFORCE_MIN_QUEUED_MAX)
 				if (data->queued_max < BITFORCE_MIN_QUEUED_MAX)
 					data->queued_max = BITFORCE_MIN_QUEUED_MAX;
 					data->queued_max = BITFORCE_MIN_QUEUED_MAX;
-				if (data->queued_max > BITFORCE_MAX_QUEUED_MAX)
-					data->queued_max = BITFORCE_MAX_QUEUED_MAX;
+				if (data->queued_max > initdata->queue_depth)
+					data->queued_max = initdata->queue_depth;
 			}
 			}
 			else
 			else
 				bitforce_change_mode(bitforce, BFP_WORK);
 				bitforce_change_mode(bitforce, BFP_WORK);
@@ -1562,6 +1735,10 @@ static bool bitforce_thread_init(struct thr_info *thr)
 			if (opt_bfl_noncerange)
 			if (opt_bfl_noncerange)
 				bitforce_change_mode(bitforce, BFP_RANGE);
 				bitforce_change_mode(bitforce, BFP_RANGE);
 		}
 		}
+		
+		if (initdata->scan_interval_ms)
+			bitforce->sleep_ms = initdata->scan_interval_ms;
+		
 		bitforce->status = LIFE_INIT2;
 		bitforce->status = LIFE_INIT2;
 		
 		
 		first_on_this_board = procdata;
 		first_on_this_board = procdata;
@@ -1609,8 +1786,16 @@ static bool bitforce_thread_init(struct thr_info *thr)
 	if (style != BFS_FPGA)
 	if (style != BFS_FPGA)
 	{
 	{
 		// Clear results queue last, to start fresh; ignore response
 		// Clear results queue last, to start fresh; ignore response
+		int last_xlink_id = -1;
 		for (bitforce = bitforce->device; bitforce; bitforce = bitforce->next_proc)
 		for (bitforce = bitforce->device; bitforce; bitforce = bitforce->next_proc)
+		{
+			struct bitforce_data * const data = bitforce->device_data;
+			if (data->xlink_id == last_xlink_id)
+				continue;
+			last_xlink_id = data->xlink_id;
+			thr = bitforce->thr[0];
 			bitforce_zox(thr, "ZOX");
 			bitforce_zox(thr, "ZOX");
+		}
 	}
 	}
 	
 	
 	return true;
 	return true;
@@ -1913,7 +2098,27 @@ retry:
 	if (data->missing_zwx)
 	if (data->missing_zwx)
 		queued_ok = 1;
 		queued_ok = 1;
 	else
 	else
-		queued_ok = atoi(&buf[9]);
+	{
+		char *p;
+		queued_ok = strtol(&buf[9], &p, 0);
+		if (data->max_queueid)
+		{
+			if (unlikely(p[0] != ':'))
+				applog(LOG_ERR, "%"PRIpreprv": Successfully queued %d/%d jobs, but no queue ids returned (queued<=%d)", bitforce->proc_repr, queued_ok, data->ready_to_queue, data->queued + queued_ok);
+			else
+			{
+				// NOTE: work is set to just-before the first item from the build-command loop earlier
+				// NOTE: This ugly statement ends up with the first work item queued
+				work = work ? (work->next ?: work) : thr->work_list;
+				for (int i = data->ready_to_queue; i > 0; --i, (work = work->next))
+				{
+					work->device_id = strtol(&p[1], &p, 0x10);
+					if (unlikely(!p[0]))
+						--p;
+				}
+			}
+		}
+	}
 	data->queued += queued_ok;
 	data->queued += queued_ok;
 	applog(LOG_DEBUG, "%"PRIpreprv": Successfully queued %d/%d jobs on device (queued<=%d)",
 	applog(LOG_DEBUG, "%"PRIpreprv": Successfully queued %d/%d jobs on device (queued<=%d)",
 	       bitforce->proc_repr,
 	       bitforce->proc_repr,
@@ -1978,27 +2183,39 @@ again:
 		if ( (noncebuf = next_line(buf)) )
 		if ( (noncebuf = next_line(buf)) )
 			noncebuf[-1] = '\0';
 			noncebuf[-1] = '\0';
 		
 		
-		if (strlen(buf) <= 90)
+		if (data->max_queueid)
 		{
 		{
-			applog(LOG_ERR, "%"PRIpreprv": Gibberish within queue results: %s", bitforce->proc_repr, buf);
-			continue;
+			const work_device_id_t queueid = strtol(buf, &end, 0x10);
+			if (unlikely(!end[0]))
+				goto gibberish;
+			DL_SEARCH_SCALAR(thr->work_list, thiswork, device_id, queueid);
 		}
 		}
-		
-		hex2bin(midstate, buf, 32);
-		hex2bin(datatail, &buf[65], 12);
-		
-		thiswork = NULL;
-		DL_FOREACH(thr->work_list, work)
+		else
 		{
 		{
-			if (unlikely(memcmp(work->midstate, midstate, 32)))
-				continue;
-			if (unlikely(memcmp(&work->data[64], datatail, 12)))
+			if (strlen(buf) <= 90)
+			{
+gibberish:
+				applog(LOG_ERR, "%"PRIpreprv": Gibberish within queue results: %s", bitforce->proc_repr, buf);
 				continue;
 				continue;
-			thiswork = work;
-			break;
+			}
+			
+			hex2bin(midstate, buf, 32);
+			hex2bin(datatail, &buf[65], 12);
+			
+			thiswork = NULL;
+			DL_FOREACH(thr->work_list, work)
+			{
+				if (unlikely(memcmp(work->midstate, midstate, 32)))
+					continue;
+				if (unlikely(memcmp(&work->data[64], datatail, 12)))
+					continue;
+				thiswork = work;
+				break;
+			}
+			
+			end = &buf[89];
 		}
 		}
 		
 		
-		end = &buf[89];
 		chip_cgpu = bitforce;
 		chip_cgpu = bitforce;
 		if (data->parallel_protocol)
 		if (data->parallel_protocol)
 		{
 		{
@@ -2034,7 +2251,7 @@ again:
 				applog(LOG_ERR, "%"PRIpreprv": Missing nonces in queue results: %s", chip_cgpu->proc_repr, buf);
 				applog(LOG_ERR, "%"PRIpreprv": Missing nonces in queue results: %s", chip_cgpu->proc_repr, buf);
 				goto finishresult;
 				goto finishresult;
 			}
 			}
-			bitforce_process_result_nonces(chip_thr, work, &end[1]);
+			bitforce_process_result_nonces(chip_thr, thiswork, &end[1]);
 		}
 		}
 		++fcount;
 		++fcount;
 		++counts[chipno];
 		++counts[chipno];
@@ -2144,9 +2361,157 @@ bool bitforce_queue_append(struct thr_info *thr, struct work *work)
 struct _jobinfo {
 struct _jobinfo {
 	uint8_t key[32+12];
 	uint8_t key[32+12];
 	int instances;
 	int instances;
+	int flushed_instances;
 	UT_hash_handle hh;
 	UT_hash_handle hh;
 };
 };
 
 
+static
+void _bitforce_queue_flush_add_to_processing(struct _jobinfo ** const processing_p, struct _jobinfo * const this, const size_t keysz, const bool was_flushed)
+{
+	struct _jobinfo *item;
+	HASH_FIND(hh, *processing_p, &this->key[0], keysz, item);
+	if (likely(!item))
+	{
+		item = this;
+		this->flushed_instances = this->instances = 0;
+		HASH_ADD(hh, *processing_p, key, keysz, this);
+	}
+	else
+	{
+		// This should really only happen in testing/benchmarking...
+		free(this);
+	}
+	if (was_flushed)
+		++item->flushed_instances;
+	else
+		++item->instances;
+}
+
+static
+void bitforce_delete_last_n_work(struct thr_info * const thr, int n)
+{
+	while (n--)
+		work_list_del(&thr->work_list, thr->work_list->prev);
+}
+
+static
+void bitforce_queue_flush_sanity_check(struct thr_info * const thr, struct _jobinfo ** const processing_p, const size_t keysz, const bool ignore_race)
+{
+	struct cgpu_info * const bitforce = thr->cgpu;
+	struct bitforce_data * const data = bitforce->device_data;
+	struct work *work, *tmp;
+	struct _jobinfo *item, *this;
+	uint8_t key[keysz];
+	char hex[(keysz * 2) + 1];
+	
+	// Iterate over the work_list and delete anything not in the hash
+	DL_FOREACH_SAFE(thr->work_list, work, tmp)
+	{
+		if (data->max_queueid)
+		{
+			memcpy(&key[0], &work->device_id, sizeof(work->device_id));
+			snprintf(hex, sizeof(hex), "%04x", work->device_id);
+		}
+		else
+		{
+			memcpy(&key[ 0],  work->midstate, 32);
+			memcpy(&key[32], &work->data[64], 12);
+			bin2hex(hex, key, keysz);
+		}
+		HASH_FIND(hh, *processing_p, &key[0], keysz, item);
+		if (unlikely(!item))
+		{
+			applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device is missing queued job! %s", bitforce->proc_repr, hex);
+			work_list_del(&thr->work_list, work);
+			--data->queued;
+			continue;
+		}
+		if (item->instances)
+		{
+			applog(LOG_DEBUG, "%"PRIpreprv": Queue flush: %s inprogress", bitforce->proc_repr, hex);
+			--item->instances;
+		}
+		else
+		{
+			--item->flushed_instances;
+			work_list_del(&thr->work_list, work);
+			// NOTE: data->queued is decremented later via bitforce_finish_flush
+			applog(LOG_DEBUG, "%"PRIpreprv": Queue flush: %s flushed", bitforce->proc_repr, hex);
+		}
+		if (likely(!(item->instances + item->flushed_instances)))
+		{
+			HASH_DEL(*processing_p, item);
+			free(item);
+		}
+	}
+	if (unlikely(*processing_p))
+	{
+		HASH_ITER(hh, *processing_p, item, this)
+		{
+			bin2hex(hex, &item->key[0], keysz);
+			if (item->instances && !ignore_race)
+				applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device %s unknown work %s (%d)", bitforce->proc_repr, "is processing", hex, item->instances);
+			if (item->flushed_instances)
+				applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device %s unknown work %s (%d)", bitforce->proc_repr, "flushed", hex, item->flushed_instances);
+			
+			HASH_DEL(*processing_p, item);
+			free(item);
+		}
+	}
+}
+
+static
+void bitforce_finish_flush(struct thr_info * const thr, const int flushed)
+{
+	struct cgpu_info *bitforce = thr->cgpu;
+	struct bitforce_data * const data = bitforce->device_data;
+	
+	data->queued -= flushed;
+	
+	applog(LOG_DEBUG, "%"PRIpreprv": Flushed %u jobs from device and %d from driver (queued<=%d)",
+	       bitforce->proc_repr, flushed, data->ready_to_queue, data->queued);
+	
+	bitforce_set_queue_full(thr);
+	data->just_flushed = true;
+	data->want_to_send_queue = false;
+	data->ready_to_queue = 0;
+}
+
+static
+void bitforce_process_flb_result(struct thr_info * const thr, int inproc, int flushed)
+{
+	struct cgpu_info *bitforce = thr->cgpu;
+	
+	size_t total = inproc + flushed, readsz;
+	uint16_t buf[total];
+	readsz = bitforce_read(bitforce, buf, total * 2) / 2;
+	if (unlikely(readsz != total))
+	{
+		applog(LOG_ERR, "%"PRIpreprv": Short read for FLB result", bitforce->proc_repr);
+		if (readsz < inproc)
+		{
+			inproc = readsz;
+			flushed = 0;
+		}
+		else
+			flushed = readsz - inproc;
+	}
+	
+	const int keysz = sizeof(work_device_id_t);
+	struct _jobinfo *processing = NULL, *this;
+	for (int i = inproc + flushed; i--; )
+	{
+		this = malloc(sizeof(*this));
+		const work_device_id_t queueid = be16toh(buf[i]);
+		memcpy(&this->key[0], &queueid, sizeof(queueid));
+		_bitforce_queue_flush_add_to_processing(&processing, this, keysz, !(i < inproc));
+	}
+	
+	bitforce_queue_flush_sanity_check(thr, &processing, keysz, false);
+	
+	bitforce_finish_flush(thr, flushed);
+}
+
 static
 static
 void bitforce_queue_flush(struct thr_info *thr)
 void bitforce_queue_flush(struct thr_info *thr)
 {
 {
@@ -2158,23 +2523,40 @@ void bitforce_queue_flush(struct thr_info *thr)
 	struct bitforce_data *data = bitforce->device_data;
 	struct bitforce_data *data = bitforce->device_data;
 	char *buf = &data->noncebuf[0], *buf2 = NULL;
 	char *buf = &data->noncebuf[0], *buf2 = NULL;
 	const char *cmd = "ZqX";
 	const char *cmd = "ZqX";
+	int inproc = -1;
 	unsigned flushed;
 	unsigned flushed;
-	struct _jobinfo *processing = NULL, *item, *this;
+	struct _jobinfo *processing = NULL, *this;
+	
+	// First, eliminate all unsent works
+	bitforce_delete_last_n_work(thr, data->ready_to_queue);
 	
 	
 	if (data->parallel == 1)
 	if (data->parallel == 1)
 		// Pre-parallelization neither needs nor supports "ZqX"
 		// Pre-parallelization neither needs nor supports "ZqX"
 		cmd = "ZQX";
 		cmd = "ZQX";
-	// TODO: Call "ZQX" most of the time: don't need to do sanity checks so often
+	else
+	if (data->max_queueid)
+		cmd = "FLB";
 	bitforce_zox(thr, cmd);
 	bitforce_zox(thr, cmd);
 	if (!strncasecmp(buf, "OK:FLUSHED", 10))
 	if (!strncasecmp(buf, "OK:FLUSHED", 10))
 		flushed = atoi(&buf[10]);
 		flushed = atoi(&buf[10]);
 	else
 	else
 	if ((!strncasecmp(buf, "COUNT:", 6)) && (buf2 = strstr(buf, "FLUSHED:")) )
 	if ((!strncasecmp(buf, "COUNT:", 6)) && (buf2 = strstr(buf, "FLUSHED:")) )
 	{
 	{
+		inproc = atoi(&buf[6]);
 		flushed = atoi(&buf2[8]);
 		flushed = atoi(&buf2[8]);
 		buf2 = next_line(buf2);
 		buf2 = next_line(buf2);
 	}
 	}
 	else
 	else
+	if ((!strncasecmp(buf, "BIN-InP:", 8)) && (buf2 = strstr(buf, "FLUSHED:")) )
+	{
+		inproc = atoi(&buf[8]);
+		flushed = atoi(&buf2[8]);
+		if (unlikely(data->queued != inproc + flushed))
+			applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device work count mismatch (dev inproc=%d, dev flushed=%u, queued=%d)", bitforce->proc_repr, inproc, flushed, data->queued);
+		bitforce_process_flb_result(thr, inproc, flushed);
+		goto final;
+	}
+	else
 	if (!strncasecmp(buf, "OK", 2))
 	if (!strncasecmp(buf, "OK", 2))
 	{
 	{
 		applog(LOG_DEBUG, "%"PRIpreprv": Didn't report flush count", bitforce->proc_repr);
 		applog(LOG_DEBUG, "%"PRIpreprv": Didn't report flush count", bitforce->proc_repr);
@@ -2196,84 +2578,49 @@ void bitforce_queue_flush(struct thr_info *thr)
 		flushed = data->queued;
 		flushed = data->queued;
 	}
 	}
 	
 	
-	data->queued -= flushed;
-	
-	applog(LOG_DEBUG, "%"PRIpreprv": Flushed %u jobs from device and %d from driver (queued<=%d)",
-	       bitforce->proc_repr, flushed, data->ready_to_queue, data->queued);
-	
-	flushed += data->ready_to_queue;
-	data->ready_to_queue = 0;
-	while (flushed--)
-		work_list_del(&thr->work_list, thr->work_list->prev);
-	bitforce_set_queue_full(thr);
-	data->just_flushed = true;
-	data->want_to_send_queue = false;
+	bitforce_delete_last_n_work(thr, flushed);
+	bitforce_finish_flush(thr, flushed);
 	
 	
 	// "ZqX" returns jobs in progress, allowing us to sanity check
 	// "ZqX" returns jobs in progress, allowing us to sanity check
 	// NOTE: Must process buffer into hash table BEFORE calling bitforce_queue_do_results, which clobbers it
 	// NOTE: Must process buffer into hash table BEFORE calling bitforce_queue_do_results, which clobbers it
 	// NOTE: Must do actual sanity check AFTER calling bitforce_queue_do_results, to ensure we don't delete completed jobs
 	// NOTE: Must do actual sanity check AFTER calling bitforce_queue_do_results, to ensure we don't delete completed jobs
+	
+	const size_t keysz = data->max_queueid ? sizeof(work_device_id_t) : sizeof(this->key);
+	
 	if (buf2)
 	if (buf2)
 	{
 	{
 		// First, turn buf2 into a hash
 		// First, turn buf2 into a hash
 		for ( ; buf2[0]; buf2 = next_line(buf2))
 		for ( ; buf2[0]; buf2 = next_line(buf2))
 		{
 		{
 			this = malloc(sizeof(*this));
 			this = malloc(sizeof(*this));
-			hex2bin(&this->key[ 0], &buf2[ 0], 32);
-			hex2bin(&this->key[32], &buf2[65], 12);
-			HASH_FIND(hh, processing, &this->key[0], sizeof(this->key), item);
-			if (likely(!item))
+			if (data->max_queueid)
 			{
 			{
-				this->instances = 1;
-				HASH_ADD(hh, processing, key, sizeof(this->key), this);
+				const work_device_id_t queueid = strtol(buf2, NULL, 0x10);
+				memcpy(&this->key[0], &queueid, sizeof(queueid));
 			}
 			}
 			else
 			else
 			{
 			{
-				// This should really only happen in testing/benchmarking...
-				++item->instances;
-				free(this);
+				hex2bin(&this->key[ 0], &buf2[ 0], 32);
+				hex2bin(&this->key[32], &buf2[65], 12);
 			}
 			}
+			_bitforce_queue_flush_add_to_processing(&processing, this, keysz, false);
 		}
 		}
 	}
 	}
 	
 	
 	bitforce_queue_do_results(thr);
 	bitforce_queue_do_results(thr);
 	
 	
 	if (buf2)
 	if (buf2)
+		// There is a race condition where the flush may have reported a job as in progress even though we completed and processed its results just now - so we just silence the sanity check
+		bitforce_queue_flush_sanity_check(thr, &processing, keysz, true);
+	
+final: ;
+#if 0
+	if (unlikely(inproc != -1 && inproc != data->queued))
 	{
 	{
-		struct work *work, *tmp;
-		uint8_t key[32+12];
-		
-		// Now iterate over the work_list and delete anything not in the hash
-		DL_FOREACH_SAFE(thr->work_list, work, tmp)
-		{
-			memcpy(&key[ 0],  work->midstate, 32);
-			memcpy(&key[32], &work->data[64], 12);
-			HASH_FIND(hh, processing, &key[0], sizeof(key), item);
-			if (unlikely(!item))
-			{
-				char hex[89];
-				bin2hex(hex, key, 32+12);
-				applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device is missing queued job! %s", bitforce->proc_repr, hex);
-				work_list_del(&thr->work_list, work);
-				continue;
-			}
-			if (likely(!--item->instances))
-			{
-				HASH_DEL(processing, item);
-				free(item);
-			}
-		}
-		if (unlikely( (flushed = HASH_COUNT(processing)) ))
-		{
-			//applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device is working on %d unknown jobs!", bitforce->proc_repr, flushed);
-			// FIXME: Probably these were jobs finished after ZqX, included in the result check we just did
-			// NOTE: We need to do that result check first to avoid deleting work_list items for things just solved
-			HASH_ITER(hh, processing, item, this)
-			{
-				HASH_DEL(processing, item);
-				free(item);
-			}
-		}
+		applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device work inprogress count mismatch (dev inproc=%d, queued=%d)", bitforce->proc_repr, inproc, data->queued);
+		data->queued = inproc;
 	}
 	}
+#endif
 }
 }
 
 
 static
 static
@@ -2338,6 +2685,7 @@ struct device_drv bitforce_queue_api = {
 	.lowl_probe = bitforce_lowl_probe,
 	.lowl_probe = bitforce_lowl_probe,
 	.minerloop = minerloop_queue,
 	.minerloop = minerloop_queue,
 	.reinit_device = bitforce_reinit,
 	.reinit_device = bitforce_reinit,
+	.zero_stats = bitforce_zero_stats,
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 	.proc_wlogprint_status = bitforce_wlogprint_status,
 	.proc_wlogprint_status = bitforce_wlogprint_status,
 	.proc_tui_wlogprint_choices = bitforce_tui_wlogprint_choices,
 	.proc_tui_wlogprint_choices = bitforce_tui_wlogprint_choices,

+ 45 - 27
driver-bitfury.c

@@ -1,7 +1,7 @@
 /*
 /*
  * Copyright 2013 bitfury
  * Copyright 2013 bitfury
  * Copyright 2013 Anatoly Legkodymov
  * Copyright 2013 Anatoly Legkodymov
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * of this software and associated documentation files (the "Software"), to deal
@@ -37,6 +37,8 @@
 #include "lowl-spi.h"
 #include "lowl-spi.h"
 #include "util.h"
 #include "util.h"
 
 
+static const int chipgen_timeout_secs = 30;
+
 BFG_REGISTER_DRIVER(bitfury_drv)
 BFG_REGISTER_DRIVER(bitfury_drv)
 const struct bfg_set_device_definition bitfury_set_device_funcs[];
 const struct bfg_set_device_definition bitfury_set_device_funcs[];
 
 
@@ -48,15 +50,15 @@ int bitfury_autodetect()
 	int chip_n;
 	int chip_n;
 	struct cgpu_info *bitfury_info;
 	struct cgpu_info *bitfury_info;
 
 
-	bitfury_info = calloc(1, sizeof(struct cgpu_info));
-	bitfury_info->drv = &bitfury_drv;
-	bitfury_info->threads = 1;
-
 	applog(LOG_INFO, "INFO: bitfury_detect");
 	applog(LOG_INFO, "INFO: bitfury_detect");
 	spi_init();
 	spi_init();
 	if (!sys_spi)
 	if (!sys_spi)
 		return 0;
 		return 0;
 	
 	
+	bitfury_info = calloc(1, sizeof(struct cgpu_info));
+	bitfury_info->drv = &bitfury_drv;
+	bitfury_info->threads = 1;
+	
 	{
 	{
 		struct bitfury_device dummy_bitfury = {
 		struct bitfury_device dummy_bitfury = {
 			.spi = sys_spi,
 			.spi = sys_spi,
@@ -67,6 +69,7 @@ int bitfury_autodetect()
 	chip_n = libbitfury_detectChips1(sys_spi);
 	chip_n = libbitfury_detectChips1(sys_spi);
 	if (!chip_n) {
 	if (!chip_n) {
 		applog(LOG_WARNING, "No Bitfury chips detected!");
 		applog(LOG_WARNING, "No Bitfury chips detected!");
+		free(bitfury_info);
 		return 0;
 		return 0;
 	} else {
 	} else {
 		applog(LOG_WARNING, "BITFURY: %d chips detected!", chip_n);
 		applog(LOG_WARNING, "BITFURY: %d chips detected!", chip_n);
@@ -121,6 +124,7 @@ bool bitfury_init_oldbuf(struct cgpu_info * const proc, const uint32_t *inp)
 	struct bitfury_device * const bitfury = proc->device_data;
 	struct bitfury_device * const bitfury = proc->device_data;
 	uint32_t * const oldbuf = &bitfury->oldbuf[0];
 	uint32_t * const oldbuf = &bitfury->oldbuf[0];
 	uint32_t * const buf = &bitfury->newbuf[0];
 	uint32_t * const buf = &bitfury->newbuf[0];
+	uint32_t *inp_new;
 	int i, differ, tried = 0;
 	int i, differ, tried = 0;
 	
 	
 	if (!inp)
 	if (!inp)
@@ -134,8 +138,10 @@ tryagain:
 		return false;
 		return false;
 	}
 	}
 	++tried;
 	++tried;
-	memcpy(buf, inp, 0x10 * 4);
-	inp = bitfury_just_io(bitfury);
+	swap32tole(buf, inp, 0x10);
+	inp_new = bitfury_just_io(bitfury);
+	swap32tole(inp_new, inp_new, 0x10);
+	inp = inp_new;
 	differ = -1;
 	differ = -1;
 	for (i = 0; i < 0x10; ++i)
 	for (i = 0; i < 0x10; ++i)
 	{
 	{
@@ -179,9 +185,9 @@ bool bitfury_init_chip(struct cgpu_info * const proc)
 	struct bitfury_payload payload = {
 	struct bitfury_payload payload = {
 		.midstate = "\x33\xfb\x46\xdc\x61\x2a\x7a\x23\xf0\xa2\x2d\x63\x31\x54\x21\xdc"
 		.midstate = "\x33\xfb\x46\xdc\x61\x2a\x7a\x23\xf0\xa2\x2d\x63\x31\x54\x21\xdc"
 		            "\xae\x86\xfe\xc3\x88\xc1\x9c\x8c\x20\x18\x10\x68\xfc\x95\x3f\xf7",
 		            "\xae\x86\xfe\xc3\x88\xc1\x9c\x8c\x20\x18\x10\x68\xfc\x95\x3f\xf7",
-		.m7    = 0xc3baafef,
-		.ntime = 0x326fa351,
-		.nbits = 0x6461011a,
+		.m7    = htole32(0xc3baafef),
+		.ntime = htole32(0x326fa351),
+		.nbits = htole32(0x6461011a),
 	};
 	};
 	bitfury_payload_to_atrvec(bitfury->atrvec, &payload);
 	bitfury_payload_to_atrvec(bitfury->atrvec, &payload);
 	return bitfury_init_oldbuf(proc, NULL);
 	return bitfury_init_oldbuf(proc, NULL);
@@ -425,7 +431,7 @@ void bitfury_do_io(struct thr_info * const master_thr)
 	
 	
 	for (j = 0; j < n_chips; ++j)
 	for (j = 0; j < n_chips; ++j)
 	{
 	{
-		memcpy(rxbuf_copy[j], rxbuf[j], 0x11 * 4);
+		swap32tole(rxbuf_copy[j], rxbuf[j], 0x11);
 		rxbuf[j] = rxbuf_copy[j];
 		rxbuf[j] = rxbuf_copy[j];
 	}
 	}
 	
 	
@@ -439,6 +445,12 @@ void bitfury_do_io(struct thr_info * const master_thr)
 		uint32_t * const newbuf = &bitfury->newbuf[0];
 		uint32_t * const newbuf = &bitfury->newbuf[0];
 		uint32_t * const oldbuf = &bitfury->oldbuf[0];
 		uint32_t * const oldbuf = &bitfury->oldbuf[0];
 		
 		
+		if (tvp_stat->tv_sec == 0 && tvp_stat->tv_usec == 0) {
+			copy_time(tvp_stat, &tv_now);
+		}
+		
+		int stat_elapsed_secs = timer_elapsed(tvp_stat, &tv_now);
+		
 		inp = rxbuf[j];
 		inp = rxbuf[j];
 		
 		
 		if (unlikely(bitfury->desync_counter == 99))
 		if (unlikely(bitfury->desync_counter == 99))
@@ -537,13 +549,9 @@ void bitfury_do_io(struct thr_info * const master_thr)
 			}
 			}
 		}
 		}
 		
 		
-		if (tvp_stat->tv_sec == 0 && tvp_stat->tv_usec == 0) {
-			copy_time(tvp_stat, &tv_now);
-		}
-		
 		if (c->osc6_max)
 		if (c->osc6_max)
 		{
 		{
-			if (timer_elapsed(tvp_stat, &tv_now) >= 60)
+			if (stat_elapsed_secs >= 60)
 			{
 			{
 				double mh_diff, s_diff;
 				double mh_diff, s_diff;
 				const int osc = bitfury->osc6_bits;
 				const int osc = bitfury->osc6_bits;
@@ -588,22 +596,22 @@ void bitfury_do_io(struct thr_info * const master_thr)
 				nonce = bitfury_decnonce(newbuf[i]);
 				nonce = bitfury_decnonce(newbuf[i]);
 				if (unlikely(!bitfury->chipgen))
 				if (unlikely(!bitfury->chipgen))
 				{
 				{
-					switch (nonce)
+					switch (nonce & 0xe03fffff)
 					{
 					{
-						case 0x6cc054e0:
-							if (++bitfury->chipgen_probe > 4)
+						case 0x40060f87:
+						case 0x600054e0:
+						case 0x80156423:
+						case 0x991abced:
+						case 0xa004b2a0:
+							if (++bitfury->chipgen_probe > 0x10)
 								bitfury->chipgen = 1;
 								bitfury->chipgen = 1;
 							break;
 							break;
-						case 0xed7081a3:
-						case 0xf883df88:
+						case 0xe03081a3:
+						case 0xe003df88:
 							bitfury->chipgen = 2;
 							bitfury->chipgen = 2;
 					}
 					}
 					if (bitfury->chipgen)
 					if (bitfury->chipgen)
-					{
-						applog(LOG_DEBUG, "%"PRIpreprv": Detected bitfury gen%d chip",
-						       proc->proc_repr, bitfury->chipgen);
-						bitfury_payload_to_atrvec(bitfury->atrvec, &bitfury->payload);
-					}
+						goto chipgen_detected;
 				}
 				}
 				else
 				else
 				if (fudge_nonce(thr->work, &nonce))
 				if (fudge_nonce(thr->work, &nonce))
@@ -643,6 +651,16 @@ void bitfury_do_io(struct thr_info * const master_thr)
 					bitfury->sample_tot = bitfury->sample_hwe = 0;
 					bitfury->sample_tot = bitfury->sample_hwe = 0;
 				}
 				}
 			}
 			}
+			if ((!bitfury->chipgen) && stat_elapsed_secs >= chipgen_timeout_secs)
+			{
+				bitfury->chipgen = 1;
+				applog(LOG_WARNING, "%"PRIpreprv": Failed to detect chip generation in %d seconds, falling back to gen%d assumption",
+				       proc->proc_repr, chipgen_timeout_secs, bitfury->chipgen);
+chipgen_detected:
+				applog(LOG_DEBUG, "%"PRIpreprv": Detected bitfury gen%d chip",
+				       proc->proc_repr, bitfury->chipgen);
+				bitfury_payload_to_atrvec(bitfury->atrvec, &bitfury->payload);
+			}
 			bitfury->active = (bitfury->active + n) % 0x10;
 			bitfury->active = (bitfury->active + n) % 0x10;
 		}
 		}
 		
 		
@@ -661,7 +679,7 @@ out:
 			bitfury->mhz_best = 0;
 			bitfury->mhz_best = 0;
 			bitfury->force_reinit = false;
 			bitfury->force_reinit = false;
 		}
 		}
-		if (timer_elapsed(tvp_stat, &tv_now) >= 60)
+		if (stat_elapsed_secs >= 60)
 			copy_time(tvp_stat, &tv_now);
 			copy_time(tvp_stat, &tv_now);
 	}
 	}
 	
 	

+ 1 - 1
driver-cairnsmore.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free

+ 3 - 3
driver-cpu.c

@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright 2011-2012 Con Kolivas
- * Copyright 2011-2013 Luke Dashjr
+ * Copyright 2011-2013 Con Kolivas
+ * Copyright 2011-2014 Luke Dashjr
  * Copyright 2010 Jeff Garzik
  * Copyright 2010 Jeff Garzik
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
@@ -228,7 +228,7 @@ double bench_algo_stage3(
 	struct work work __attribute__((aligned(128)));
 	struct work work __attribute__((aligned(128)));
 	unsigned char hash1[64];
 	unsigned char hash1[64];
 
 
-	get_benchmark_work(&work);
+	get_benchmark_work(&work, false);
 
 
 	static struct thr_info dummy;
 	static struct thr_info dummy;
 
 

+ 7 - 7
driver-drillbit.c

@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
- * Copyright 2013 Angus Gratton
+ * Copyright 2013-2014 Luke Dashjr
+ * Copyright 2013-2014 Angus Gratton
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -8,6 +8,8 @@
  * any later version.  See COPYING for more details.
  * any later version.  See COPYING for more details.
  */
  */
 
 
+#include "config.h"
+
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdio.h>
@@ -45,8 +47,6 @@ struct drillbit_board {
 static
 static
 bool drillbit_lowl_match(const struct lowlevel_device_info * const info)
 bool drillbit_lowl_match(const struct lowlevel_device_info * const info)
 {
 {
-	if (!lowlevel_match_id(info, &lowl_vcom, 0, 0))
-		return false;
 	return (info->manufacturer && strstr(info->manufacturer, "Drillbit"));
 	return (info->manufacturer && strstr(info->manufacturer, "Drillbit"));
 }
 }
 
 
@@ -114,9 +114,6 @@ err:
 		// Production firmware Thumbs don't set any capability bits, so fill in the EXT_CLOCK one
 		// Production firmware Thumbs don't set any capability bits, so fill in the EXT_CLOCK one
 		caps |= DBC_EXT_CLOCK;
 		caps |= DBC_EXT_CLOCK;
 	
 	
-	char *serno = malloc(9);
-	snprintf(serno, 9, "%08lx", serialno);
-	
 	if (chips > 0x100)
 	if (chips > 0x100)
 	{
 	{
 		applog(LOG_WARNING, "%s: %s: %u chips reported, but driver only supports up to 256",
 		applog(LOG_WARNING, "%s: %s: %u chips reported, but driver only supports up to 256",
@@ -129,6 +126,9 @@ err:
 	
 	
 	intptr_t device_data = caps | ((intptr_t)protover << 16); // Store capabilities & protocol version in device_data, temporarily
 	intptr_t device_data = caps | ((intptr_t)protover << 16); // Store capabilities & protocol version in device_data, temporarily
 
 
+	char *serno = malloc(9);
+	snprintf(serno, 9, "%08lx", serialno);
+	
 	struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
 	struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
 	*cgpu = (struct cgpu_info){
 	*cgpu = (struct cgpu_info){
 		.drv = &drillbit_drv,
 		.drv = &drillbit_drv,

+ 15 - 7
driver-dualminer.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  * Copyright 2014 Nate Woolls
  * Copyright 2014 Nate Woolls
  * Copyright 2014 Dualminer Team
  * Copyright 2014 Dualminer Team
  *
  *
@@ -124,7 +124,7 @@ void dualminer_init_firstrun(struct cgpu_info *icarus)
 {
 {
 	int fd = icarus->device_fd;
 	int fd = icarus->device_fd;
 
 
-	gc3355_init_usbstick(fd, opt_pll_freq, !opt_dual_mode, false);
+	gc3355_init_dualminer(fd, opt_pll_freq, !opt_dual_mode, false);
 	
 	
 	dualminer_init_hashrate(icarus);
 	dualminer_init_hashrate(icarus);
 
 
@@ -168,7 +168,7 @@ bool dualminer_detect_init(const char *devpath, int fd, struct ICARUS_INFO * __m
 {
 {
 	dualminer_set_defaults(fd);
 	dualminer_set_defaults(fd);
 	
 	
-	gc3355_init_usbstick(fd, opt_pll_freq, !opt_dual_mode, true);
+	gc3355_init_dualminer(fd, opt_pll_freq, !opt_dual_mode, true);
 
 
 	return true;
 	return true;
 }
 }
@@ -191,6 +191,13 @@ bool dualminer_job_start(struct thr_info * const thr)
 			gc3355_scrypt_reset(fd);
 			gc3355_scrypt_reset(fd);
 		else
 		else
 			gc3355_scrypt_only_reset(fd);
 			gc3355_scrypt_only_reset(fd);
+
+		// See https://github.com/gridseed/gc3355-doc/blob/master/GC3355_DataSheet.pdf
+		// WAIT: Before start a new transaction, WAIT Cycle must be inserted.
+		// WAIT Cycle value is programmable register in UART and default wait
+		// time is UART receive 32 bits time (One DATA Cycle).
+		// Note: prevents register corruption
+		cgsleep_ms(100);
 	}
 	}
 
 
 	return icarus_job_start(thr);
 	return icarus_job_start(thr);
@@ -212,8 +219,7 @@ bool dualminer_detect_one(const char *devpath)
 		.timing_mode = MODE_DEFAULT,
 		.timing_mode = MODE_DEFAULT,
 		.do_icarus_timing = false,
 		.do_icarus_timing = false,
 		.nonce_littleendian = true,
 		.nonce_littleendian = true,
-		.work_division = 2,
-		.fpga_count = 2,
+		.work_division = 1,
 		.detect_init_func = dualminer_detect_init,
 		.detect_init_func = dualminer_detect_init,
 		.job_start_func = dualminer_job_start
 		.job_start_func = dualminer_job_start
 	};
 	};
@@ -295,7 +301,7 @@ bool dualminer_job_prepare(struct thr_info *thr, struct work *work, __maybe_unus
 	if (opt_scrypt)
 	if (opt_scrypt)
 		gc3355_scrypt_prepare_work(state->ob_bin, work);
 		gc3355_scrypt_prepare_work(state->ob_bin, work);
 	else
 	else
-		gc3355_sha2_prepare_work(state->ob_bin, work, false);
+		gc3355_sha2_prepare_work(state->ob_bin, work);
 
 
 	return true;
 	return true;
 }
 }
@@ -329,7 +335,9 @@ void dualminer_drv_init()
 	dualminer_drv.thread_shutdown = dualminer_thread_shutdown;
 	dualminer_drv.thread_shutdown = dualminer_thread_shutdown;
 	dualminer_drv.job_prepare = dualminer_job_prepare;
 	dualminer_drv.job_prepare = dualminer_job_prepare;
 	dualminer_drv.set_device = dualminer_set_device;
 	dualminer_drv.set_device = dualminer_set_device;
-	++dualminer_drv.probe_priority;
+
+	// currently setup specifically to probe after ZeusMiner
+	dualminer_drv.probe_priority = -50;
 }
 }
 
 
 struct device_drv dualminer_drv =
 struct device_drv dualminer_drv =

+ 34 - 22
driver-getwork.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -32,28 +32,34 @@
 #include "miner.h"
 #include "miner.h"
 
 
 static
 static
-void getwork_prepare_resp(struct MHD_Response *resp)
+void getwork_prepare_resp(struct MHD_Response *resp, struct MHD_Connection * const conn)
 {
 {
 	httpsrv_prepare_resp(resp);
 	httpsrv_prepare_resp(resp);
 	MHD_add_response_header(resp, MHD_HTTP_HEADER_CONTENT_TYPE, "application/json");
 	MHD_add_response_header(resp, MHD_HTTP_HEADER_CONTENT_TYPE, "application/json");
 	MHD_add_response_header(resp, "X-Mining-Extensions", "hashesdone");
 	MHD_add_response_header(resp, "X-Mining-Extensions", "hashesdone");
+#if MHD_VERSION >= 0x00093701
+	const char * const agent = MHD_lookup_connection_value(conn, MHD_HEADER_KIND, "User-Agent");
+	// Block Erupter products can't handle the Connection: close header, so force HTTP/1.0 for them
+	if (!(strcmp(agent, "BE Cube BTC Miner") && strcmp(agent, "Jephis PIC Miner")))
+		MHD_set_response_options(resp, MHD_RF_HTTP_VERSION_1_0_ONLY, MHD_RO_END);
+#endif
 }
 }
 
 
 static
 static
-struct MHD_Response *getwork_gen_error(int16_t errcode, const char *errmsg, const char *idstr, size_t idstr_sz)
+struct MHD_Response *getwork_gen_error(int16_t errcode, const char *errmsg, const char *idstr, size_t idstr_sz, struct MHD_Connection * const conn)
 {
 {
 	size_t replysz = 0x40 + strlen(errmsg) + idstr_sz;
 	size_t replysz = 0x40 + strlen(errmsg) + idstr_sz;
 	char * const reply = malloc(replysz);
 	char * const reply = malloc(replysz);
 	replysz = snprintf(reply, replysz, "{\"result\":null,\"error\":{\"code\":%d,\"message\":\"%s\"},\"id\":%s}", errcode, errmsg, idstr ?: "0");
 	replysz = snprintf(reply, replysz, "{\"result\":null,\"error\":{\"code\":%d,\"message\":\"%s\"},\"id\":%s}", errcode, errmsg, idstr ?: "0");
 	struct MHD_Response * const resp = MHD_create_response_from_buffer(replysz, reply, MHD_RESPMEM_MUST_FREE);
 	struct MHD_Response * const resp = MHD_create_response_from_buffer(replysz, reply, MHD_RESPMEM_MUST_FREE);
-	getwork_prepare_resp(resp);
+	getwork_prepare_resp(resp, conn);
 	return resp;
 	return resp;
 }
 }
 
 
 static
 static
 int getwork_error(struct MHD_Connection *conn, int16_t errcode, const char *errmsg, const char *idstr, size_t idstr_sz)
 int getwork_error(struct MHD_Connection *conn, int16_t errcode, const char *errmsg, const char *idstr, size_t idstr_sz)
 {
 {
-	struct MHD_Response * const resp = getwork_gen_error(errcode, errmsg, idstr, idstr_sz);
+	struct MHD_Response * const resp = getwork_gen_error(errcode, errmsg, idstr, idstr_sz, conn);
 	const int ret = MHD_queue_response(conn, 500, resp);
 	const int ret = MHD_queue_response(conn, 500, resp);
 	MHD_destroy_response(resp);
 	MHD_destroy_response(resp);
 	return ret;
 	return ret;
@@ -72,7 +78,7 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 	json_error_t jerr;
 	json_error_t jerr;
 	struct work *work;
 	struct work *work;
 	char *reply;
 	char *reply;
-	const char *hashesdone = NULL;
+	long long hashes_done = -1;
 	int ret;
 	int ret;
 	
 	
 	if (bytes_len(upbuf))
 	if (bytes_len(upbuf))
@@ -102,7 +108,7 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 	user = MHD_basic_auth_get_username_password(conn, NULL);
 	user = MHD_basic_auth_get_username_password(conn, NULL);
 	if (!user)
 	if (!user)
 	{
 	{
-		resp = getwork_gen_error(-4096, "Please provide a username", idstr, idstr_sz);
+		resp = getwork_gen_error(-4096, "Please provide a username", idstr, idstr_sz, conn);
 		ret = MHD_queue_basic_auth_fail_response(conn, PACKAGE, resp);
 		ret = MHD_queue_basic_auth_fail_response(conn, PACKAGE, resp);
 		goto out;
 		goto out;
 	}
 	}
@@ -117,7 +123,11 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 	cgpu = client->cgpu;
 	cgpu = client->cgpu;
 	thr = cgpu->thr[0];
 	thr = cgpu->thr[0];
 	
 	
-	hashesdone = MHD_lookup_connection_value(conn, MHD_HEADER_KIND, "X-Hashes-Done");
+	{
+		const char * const hashesdone = MHD_lookup_connection_value(conn, MHD_HEADER_KIND, "X-Hashes-Done");
+		if (hashesdone)
+			hashes_done = strtoll(hashesdone, NULL, 0);
+	}
 	
 	
 	if (submit)
 	if (submit)
 	{
 	{
@@ -144,13 +154,8 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 			else
 			else
 				rejreason = NULL;
 				rejreason = NULL;
 			
 			
-			if (!hashesdone)
-			{
-				if (opt_scrypt)
-					hashesdone = "0x10000";
-				else
-					hashesdone = "0x100000000";
-			}
+			if (hashes_done == -1)
+				hashes_done = (double)0x100000000 * work->nonce_diff;
 		}
 		}
 		
 		
 		reply = malloc(36 + idstr_sz);
 		reply = malloc(36 + idstr_sz);
@@ -158,7 +163,7 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 		sprintf(reply, "{\"error\":null,\"result\":%s,\"id\":%s}",
 		sprintf(reply, "{\"error\":null,\"result\":%s,\"id\":%s}",
 		        rejreason ? "false" : "true", idstr);
 		        rejreason ? "false" : "true", idstr);
 		resp = MHD_create_response_from_buffer(replysz, reply, MHD_RESPMEM_MUST_FREE);
 		resp = MHD_create_response_from_buffer(replysz, reply, MHD_RESPMEM_MUST_FREE);
-		getwork_prepare_resp(resp);
+		getwork_prepare_resp(resp, conn);
 		MHD_add_response_header(resp, "X-Mining-Identifier", cgpu->proc_repr);
 		MHD_add_response_header(resp, "X-Mining-Identifier", cgpu->proc_repr);
 		if (rejreason)
 		if (rejreason)
 			MHD_add_response_header(resp, "X-Reject-Reason", rejreason);
 			MHD_add_response_header(resp, "X-Reject-Reason", rejreason);
@@ -169,7 +174,7 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 	
 	
 	if (cgpu->deven == DEV_DISABLED)
 	if (cgpu->deven == DEV_DISABLED)
 	{
 	{
-		resp = getwork_gen_error(-10, "Virtual device has been disabled", idstr, idstr_sz);
+		resp = getwork_gen_error(-10, "Virtual device has been disabled", idstr, idstr_sz, conn);
 		MHD_add_response_header(resp, "X-Mining-Identifier", cgpu->proc_repr);
 		MHD_add_response_header(resp, "X-Mining-Identifier", cgpu->proc_repr);
 		ret = MHD_queue_response(conn, 500, resp);
 		ret = MHD_queue_response(conn, 500, resp);
 		MHD_destroy_response(resp);
 		MHD_destroy_response(resp);
@@ -180,8 +185,16 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 		size_t replysz = 590 + idstr_sz;
 		size_t replysz = 590 + idstr_sz;
 		
 		
 		work = get_work(thr);
 		work = get_work(thr);
+		work->nonce_diff = client->desired_share_pdiff;
+		if (work->nonce_diff > work->work_difficulty)
+			work->nonce_diff = work->work_difficulty;
+		
 		reply = malloc(replysz);
 		reply = malloc(replysz);
-		memcpy(reply, "{\"error\":null,\"result\":{\"target\":\"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000\",\"data\":\"", 108);
+		uint8_t target[0x20];
+		set_target_to_pdiff(target, work->nonce_diff);
+		memcpy(reply, "{\"error\":null,\"result\":{\"target\":\"", 34);
+		bin2hex(&reply[34], target, sizeof(target));
+		memcpy(&reply[98], "\",\"data\":\"", 10);
 		bin2hex(&reply[108], work->data, 128);
 		bin2hex(&reply[108], work->data, 128);
 		memcpy(&reply[364], "\",\"midstate\":\"", 14);
 		memcpy(&reply[364], "\",\"midstate\":\"", 14);
 		bin2hex(&reply[378], work->midstate, 32);
 		bin2hex(&reply[378], work->midstate, 32);
@@ -190,7 +203,6 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 		memcpy(&reply[589 + idstr_sz], "}", 1);
 		memcpy(&reply[589 + idstr_sz], "}", 1);
 		if (opt_scrypt)
 		if (opt_scrypt)
 		{
 		{
-			memset(&reply[90], 'f', 4);
 			replysz += 21;
 			replysz += 21;
 			reply = realloc(reply, replysz);
 			reply = realloc(reply, replysz);
 			memmove(&reply[443 + 21], &reply[443], replysz - (443 + 21));
 			memmove(&reply[443 + 21], &reply[443], replysz - (443 + 21));
@@ -201,15 +213,15 @@ int handle_getwork(struct MHD_Connection *conn, bytes_t *upbuf)
 		HASH_ADD_KEYPTR(hh, client->work, work->data, 76, work);
 		HASH_ADD_KEYPTR(hh, client->work, work->data, 76, work);
 		
 		
 		resp = MHD_create_response_from_buffer(replysz, reply, MHD_RESPMEM_MUST_FREE);
 		resp = MHD_create_response_from_buffer(replysz, reply, MHD_RESPMEM_MUST_FREE);
-		getwork_prepare_resp(resp);
+		getwork_prepare_resp(resp, conn);
 		MHD_add_response_header(resp, "X-Mining-Identifier", cgpu->proc_repr);
 		MHD_add_response_header(resp, "X-Mining-Identifier", cgpu->proc_repr);
 		ret = MHD_queue_response(conn, 200, resp);
 		ret = MHD_queue_response(conn, 200, resp);
 		MHD_destroy_response(resp);
 		MHD_destroy_response(resp);
 	}
 	}
 	
 	
 out:
 out:
-	if (hashesdone)
-		hashes_done2(thr, strtoll(hashesdone, NULL, 0), NULL);
+	if (hashes_done != -1)
+		hashes_done2(thr, hashes_done, NULL);
 	
 	
 	free(idstr);
 	free(idstr);
 	if (json)
 	if (json)

+ 268 - 248
driver-gridseed.c

@@ -19,16 +19,22 @@
 #include "gc3355.h"
 #include "gc3355.h"
 
 
 #define GRIDSEED_DEFAULT_FREQUENCY  600
 #define GRIDSEED_DEFAULT_FREQUENCY  600
-#define GRIDSEED_MAX_QUEUED          10
+// 60Kh/s at 700MHz in ms
+#define GRIDSEED_HASH_SPEED         0.08571428571429
+// GridSeed driver currently scans a full nonce range
+#define GRIDSEED_MAX_NONCE          0xffffffff
 
 
 BFG_REGISTER_DRIVER(gridseed_drv)
 BFG_REGISTER_DRIVER(gridseed_drv)
 
 
+static const struct bfg_set_device_definition gridseed_set_device_funcs_probe[];
+static const struct bfg_set_device_definition gridseed_set_device_funcs_live[];
+
 /*
 /*
  * helper functions
  * helper functions
  */
  */
 
 
 static
 static
-struct cgpu_info *gridseed_alloc_device(const char *path, struct device_drv *driver, struct gc3355_orb_info *info)
+struct cgpu_info *gridseed_alloc_device(const char *path, struct device_drv *driver, struct gc3355_info *info)
 {
 {
 	struct cgpu_info *device = calloc(1, sizeof(struct cgpu_info));
 	struct cgpu_info *device = calloc(1, sizeof(struct cgpu_info));
 	if (unlikely(!device))
 	if (unlikely(!device))
@@ -38,18 +44,18 @@ struct cgpu_info *gridseed_alloc_device(const char *path, struct device_drv *dri
 	device->device_path = strdup(path);
 	device->device_path = strdup(path);
 	device->device_fd = -1;
 	device->device_fd = -1;
 	device->threads = 1;
 	device->threads = 1;
-	device->procs = GC3355_ORB_DEFAULT_CHIPS;
 	device->device_data = info;
 	device->device_data = info;
+	device->set_device_funcs = gridseed_set_device_funcs_live;
 	
 	
 	return device;
 	return device;
 }
 }
 
 
 static
 static
-struct gc3355_orb_info *gridseed_alloc_info()
+struct gc3355_info *gridseed_alloc_info()
 {
 {
-	struct gc3355_orb_info *info = calloc(1, sizeof(struct gc3355_orb_info));
+	struct gc3355_info *info = calloc(1, sizeof(struct gc3355_info));
 	if (unlikely(!info))
 	if (unlikely(!info))
-		quit(1, "Failed to malloc gc3355_orb_info");
+		quit(1, "Failed to malloc gc3355_info");
 	
 	
 	info->freq = GRIDSEED_DEFAULT_FREQUENCY;
 	info->freq = GRIDSEED_DEFAULT_FREQUENCY;
 	
 	
@@ -63,12 +69,88 @@ void gridseed_empty_work(int fd)
 	gc3355_read(fd, (char *)buf, GC3355_READ_SIZE);
 	gc3355_read(fd, (char *)buf, GC3355_READ_SIZE);
 }
 }
 
 
+static
+struct thr_info *gridseed_thread_by_chip(const struct cgpu_info * const device, uint32_t const chip)
+{
+	const struct cgpu_info *proc = device_proc_by_id(device, chip);
+	if (unlikely(!proc))
+		proc = device;
+	return proc->thr[0];
+}
+
+// return the number of hashes done in elapsed_ms
+static
+int64_t gridseed_calculate_chip_hashes_ms(const struct cgpu_info * const device, int const elapsed_ms)
+{
+	struct gc3355_info *info = device->device_data;
+	return GRIDSEED_HASH_SPEED * (double)elapsed_ms * (double)(info->freq);
+}
+
+// return the number of hashes done since start_tv
+static
+int64_t gridseed_calculate_chip_hashes(const struct cgpu_info * const device, struct timeval const start_tv)
+{
+	struct timeval now_tv;
+	timer_set_now(&now_tv);
+	int elapsed_ms = ms_tdiff(&now_tv, &start_tv);
+
+	return gridseed_calculate_chip_hashes_ms(device, elapsed_ms);
+}
+
+// adjust calculated hashes that overflow possible values
+static
+int64_t gridseed_fix_hashes_done(int64_t const hashes_done)
+{
+	int64_t result = hashes_done;
+
+	// not possible to complete more than 0xffffffff nonces
+	if (unlikely(result > 0xffffffff))
+		result = 0xffffffff;
+
+	return result;
+}
+
+// report on hashes done since start_tv
+// return the number of hashes done since start_tv
+static
+int64_t gridseed_hashes_done(struct cgpu_info * const device, struct timeval const start_tv, int64_t previous_hashes)
+{
+	int64_t total_chip_hashes = gridseed_calculate_chip_hashes(device, start_tv);
+	total_chip_hashes = gridseed_fix_hashes_done(total_chip_hashes);
+
+	int64_t previous_chip_hashes = previous_hashes / device->procs;
+	int64_t recent_chip_hashes = total_chip_hashes - previous_chip_hashes;
+	int64_t total_hashes = 0;
+
+	for_each_managed_proc(proc, device)
+	{
+		total_hashes += recent_chip_hashes;
+		hashes_done2(proc->thr[0], recent_chip_hashes, NULL);
+	}
+
+	return total_hashes;
+}
+
+// return duration in seconds for device to scan a nonce range
+static
+uint32_t gridseed_nonce_range_duration(const struct cgpu_info * const device)
+{
+	struct gc3355_info *info = device->device_data;
+
+	// total hashrate of this device:
+	uint32_t hashes_per_sec = gridseed_calculate_chip_hashes_ms(device, 1000) * info->chips;
+	// amount of time it takes this device to scan a nonce range:
+	uint32_t nonce_range_sec = 0xffffffff / hashes_per_sec;
+
+	return nonce_range_sec;
+}
+
 /*
 /*
  * device detection
  * device detection
  */
  */
 
 
 static
 static
-bool gridseed_detect_custom(const char *path, struct device_drv *driver, struct gc3355_orb_info *info)
+bool gridseed_detect_custom(const char *path, struct device_drv *driver, struct gc3355_info *info)
 {
 {
 	int fd = gc3355_open(path);
 	int fd = gc3355_open(path);
 	if(fd < 0)
 	if(fd < 0)
@@ -76,29 +158,36 @@ bool gridseed_detect_custom(const char *path, struct device_drv *driver, struct
 	
 	
 	gridseed_empty_work(fd);
 	gridseed_empty_work(fd);
 	
 	
-	uint32_t fw_version = gc3355_get_firmware_version(fd);
+	int64_t fw_version = gc3355_get_firmware_version(fd);
 	
 	
 	if (fw_version == -1)
 	if (fw_version == -1)
 	{
 	{
-		applog(LOG_ERR, "%s: Invalid detect response from %s", gridseed_drv.dname, path);
+		applog(LOG_DEBUG, "%s: Invalid detect response from %s", gridseed_drv.dname, path);
 		gc3355_close(fd);
 		gc3355_close(fd);
 		return false;
 		return false;
 	}
 	}
 	
 	
-	struct cgpu_info *device = gridseed_alloc_device(path, driver, info);
-	
 	if (serial_claim_v(path, driver))
 	if (serial_claim_v(path, driver))
 		return false;
 		return false;
 	
 	
-	if (!add_cgpu(device))
-		return false;
+	info->chips = GC3355_ORB_DEFAULT_CHIPS;
+	if((fw_version & 0xffff) == 0x1402)
+		info->chips = GC3355_BLADE_DEFAULT_CHIPS;
+	
+	//pick up any user-defined settings passed in via --set
+	drv_set_defaults(driver, gridseed_set_device_funcs_probe, info, path, detectone_meta_info.serial, 1);
 	
 	
+	struct cgpu_info *device = gridseed_alloc_device(path, driver, info);
 	device->device_fd = fd;
 	device->device_fd = fd;
+	device->procs = info->chips;
+	
+	if (!add_cgpu(device))
+		return false;
 	
 	
-	gc3355_init_usborb(device->device_fd, info->freq, false, false);
+	gc3355_init_miner(device->device_fd, info->freq);
 	
 	
 	applog(LOG_INFO, "Found %"PRIpreprv" at %s", device->proc_repr, path);
 	applog(LOG_INFO, "Found %"PRIpreprv" at %s", device->proc_repr, path);
-	applog(LOG_DEBUG, "%"PRIpreprv": Init: firmware=%d", device->proc_repr, fw_version);
+	applog(LOG_DEBUG, "%"PRIpreprv": Init: firmware=%"PRId64", chips=%d", device->proc_repr, fw_version, info->chips);
 	
 	
 	return true;
 	return true;
 }
 }
@@ -106,7 +195,7 @@ bool gridseed_detect_custom(const char *path, struct device_drv *driver, struct
 static
 static
 bool gridseed_detect_one(const char *path)
 bool gridseed_detect_one(const char *path)
 {
 {
-	struct gc3355_orb_info *info = gridseed_alloc_info();
+	struct gc3355_info *info = gridseed_alloc_info();
 	
 	
 	if (!gridseed_detect_custom(path, &gridseed_drv, info))
 	if (!gridseed_detect_custom(path, &gridseed_drv, info))
 	{
 	{
@@ -131,28 +220,9 @@ bool gridseed_thread_prepare(struct thr_info *thr)
 {
 {
 	thr->cgpu_data = calloc(1, sizeof(*thr->cgpu_data));
 	thr->cgpu_data = calloc(1, sizeof(*thr->cgpu_data));
 	
 	
-	if (opt_scrypt)
-	{
-		struct cgpu_info *device = thr->cgpu;
-		device->min_nonce_diff = 1./0x10000;
-	}
-	
-	return true;
-}
-
-static
-bool gridseed_set_queue_full(const struct cgpu_info * const device, int needwork);
+	struct cgpu_info *device = thr->cgpu;
+	device->min_nonce_diff = 1./0x10000;
 
 
-static
-bool gridseed_thread_init(struct thr_info *master_thr)
-{
-	struct cgpu_info * const device = master_thr->cgpu;
-	gridseed_set_queue_full(device, 0);
-	timer_set_now(&master_thr->tv_poll);
-	
-	// kick off queue minerloop
-	gridseed_set_queue_full(device, device->procs * 2);
-	
 	return true;
 	return true;
 }
 }
 
 
@@ -160,266 +230,216 @@ static
 void gridseed_thread_shutdown(struct thr_info *thr)
 void gridseed_thread_shutdown(struct thr_info *thr)
 {
 {
 	struct cgpu_info *device = thr->cgpu;
 	struct cgpu_info *device = thr->cgpu;
+
 	gc3355_close(device->device_fd);
 	gc3355_close(device->device_fd);
-	
 	free(thr->cgpu_data);
 	free(thr->cgpu_data);
 }
 }
 
 
-static
-void gridseed_reinit_device(struct cgpu_info * const proc)
-{
-	timer_set_now(&proc->thr[0]->tv_poll);
-}
-
 /*
 /*
- * queued mining loop
+ * scanhash mining loop
  */
  */
 
 
+// send work to the device
 static
 static
-bool gridseed_set_queue_full(const struct cgpu_info * const device, int needwork)
+bool gridseed_job_start(const struct thr_info * const thr, struct work * const work)
 {
 {
-	struct gc3355_orb_info * const info = device->device_data;
-	struct thr_info * const master_thr = device->thr[0];
-	
-	if (needwork != -1)
-		info->needwork = needwork;
-	
-	const bool full = (device->device_fd == -1 || !info->needwork);
-	
-	if (full == master_thr->queue_full)
-		return full;
-	
-	for (const struct cgpu_info *proc = device; proc; proc = proc->next_proc)
-	{
-		struct thr_info * const thr = proc->thr[0];
-		thr->queue_full = full;
-	}
-	
-	return full;
-}
+	struct cgpu_info *device = thr->cgpu;
+	unsigned char cmd[156];
 
 
-static
-bool gridseed_send_work(const struct cgpu_info * const device, struct work *work)
-{
-	int work_size = opt_scrypt ? 156 : 52;
-	unsigned char cmd[work_size];
-	
-	if (opt_scrypt)
-	{
-		gc3355_scrypt_reset(device->device_fd);
-		gc3355_scrypt_prepare_work(cmd, work);
-	}
-	else
-		gc3355_sha2_prepare_work(cmd, work, true);
+	gc3355_scrypt_reset(device->device_fd);
+	gc3355_scrypt_prepare_work(cmd, work);
+
+	// See https://github.com/gridseed/gc3355-doc/blob/master/GC3355_DataSheet.pdf
+	// WAIT: Before start a new transaction, WAIT Cycle must be inserted.
+	// WAIT Cycle value is programmable register in UART and default wait
+	// time is UART receive 32 bits time (One DATA Cycle).
+	// Note: prevents register corruption
+	cgsleep_ms(100);
 	
 	
 	// send work
 	// send work
 	if (sizeof(cmd) != gc3355_write(device->device_fd, cmd, sizeof(cmd)))
 	if (sizeof(cmd) != gc3355_write(device->device_fd, cmd, sizeof(cmd)))
 	{
 	{
 		applog(LOG_ERR, "%s: Failed to send work", device->dev_repr);
 		applog(LOG_ERR, "%s: Failed to send work", device->dev_repr);
+		dev_error(device, REASON_DEV_COMMS_ERROR);
 		return false;
 		return false;
 	}
 	}
-	
+
+	// after sending work to the device, minerloop_scanhash-based
+	// drivers must set work->blk.nonce to the last nonce to hash
+	work->blk.nonce = GRIDSEED_MAX_NONCE;
+
 	return true;
 	return true;
 }
 }
 
 
 static
 static
-void gridseed_prune_queue(const struct cgpu_info * const device, struct work *work)
+void gridseed_submit_nonce(struct thr_info * const thr, const unsigned char buf[GC3355_READ_SIZE], struct work * const work)
 {
 {
-	struct thr_info * const master_thr = device->thr[0];
+	struct cgpu_info *device = thr->cgpu;
+	
+	uint32_t nonce = *(uint32_t *)(buf + 4);
+	nonce = le32toh(nonce);
+	uint32_t chip = nonce / (GRIDSEED_MAX_NONCE / device->procs);
 	
 	
-	// prune queue
-	int prunequeue = HASH_COUNT(master_thr->work_list) - GRIDSEED_MAX_QUEUED;
-	if (prunequeue > 0)
+	struct thr_info *proc_thr = gridseed_thread_by_chip(device, chip);
+	
+	submit_nonce(proc_thr, work, nonce);
+}
+
+// read from device for nonce or command
+// unless the device can target specific nonce ranges, the scanhash routine should loop
+// until the device has processed the work item, scanning the full nonce range
+// return the total number of hashes done
+static
+int64_t gridseed_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
+{
+	struct cgpu_info *device = thr->cgpu;
+	struct timeval start_tv, nonce_range_tv, report_hashes_tv;
+
+	// amount of time it takes this device to scan a nonce range:
+	uint32_t nonce_full_range_sec = gridseed_nonce_range_duration(device);
+	// 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 99% of the range
+	uint64_t nonce_near_range_usec = (nonce_full_range_sec * 1000000. * 0.99);
+	timer_set_delay_from_now(&nonce_range_tv, nonce_near_range_usec);
+
+	// timer to calculate hashes every 10s
+	const uint32_t report_delay = 10 * 1000000;
+	timer_set_delay_from_now(&report_hashes_tv, report_delay);
+
+	// start the job
+	timer_set_now(&start_tv);
+	gridseed_job_start(thr, work);
+
+	// scan for results
+	unsigned char buf[GC3355_READ_SIZE];
+	int read = 0;
+	int fd = device->device_fd;
+	int64_t total_hashes = 0;
+	bool range_nearly_scanned = false;
+
+	while (!thr->work_restart                                                   // true when new work is available (miner.c)
+	    && ((read = gc3355_read(fd, (char *)buf, GC3355_READ_SIZE)) >= 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
 	{
 	{
-		struct work *tmp;
-		applog(LOG_DEBUG, "%s: Pruning %d old work item%s",
-		       device->dev_repr, prunequeue, prunequeue == 1 ? "" : "s");
-		HASH_ITER(hh, master_thr->work_list, work, tmp)
+		if (timer_passed(&report_hashes_tv, NULL))
 		{
 		{
-			HASH_DEL(master_thr->work_list, work);
-			free_work(work);
-			if (--prunequeue < 1)
-				break;
+			total_hashes += gridseed_hashes_done(device, start_tv, total_hashes);
+			timer_set_delay_from_now(&report_hashes_tv, report_delay);
 		}
 		}
+
+		if (read == 0)
+			continue;
+
+		if ((buf[0] == 0x55) && (buf[1] == 0x20))
+			gridseed_submit_nonce(thr, buf, work);
+		else
+			applog(LOG_ERR, "%"PRIpreprv": Unrecognized response", device->proc_repr);
 	}
 	}
-}
 
 
-// send work to the device & queue work
-static
-bool gridseed_queue_append(struct thr_info * const thr, struct work *work)
-{
-	const struct cgpu_info * const device = thr->cgpu->device;
-	struct gc3355_orb_info * const info = device->device_data;
-	struct thr_info * const master_thr = device->thr[0];
-	
-	// if queue is full (-1 is a check flag) do not append new work
-	if (gridseed_set_queue_full(device, -1))
-		return false;
-	
-	// send work
-	if (!gridseed_send_work(device, work))
-		return false;
-	
-	// store work in queue
-	HASH_ADD(hh, master_thr->work_list, id, sizeof(work->id), work);
-	
-	// prune queue
-	gridseed_prune_queue(device, work);
-	
-	// sets info->needwork equal to 2nd arg and updates "full" flags
-	gridseed_set_queue_full(device, info->needwork - 1);
-	
-	return true;
+	if (read == -1)
+	{
+		applog(LOG_ERR, "%s: Failed to read result", device->dev_repr);
+		dev_error(device, REASON_DEV_COMMS_ERROR);
+	}
+
+	// calculate remaining hashes for elapsed time
+	// e.g. work_restart ~report_delay after report_hashes_tv
+	gridseed_hashes_done(device, start_tv, total_hashes);
+
+	return 0;
 }
 }
 
 
+/*
+ * specify settings / options via RPC or command line
+ */
+
+// support for --set-device
+// must be set before probing the device
+
 static
 static
-void gridseed_queue_flush(struct thr_info * const thr)
+void gridseed_set_clock_freq(struct cgpu_info * const device, int const val)
 {
 {
-	const struct cgpu_info *device = thr->cgpu;
-	if (device != device->device)
-		return;
-	
-	gridseed_set_queue_full(device, device->procs);
+	struct gc3355_info * const info = device->device_data;
+
+	if ((info->freq != val) &&                          // method called for each processor, we only want to set pll once
+	    (device->device_fd > 0))                        // we may not be mining yet, in which case just store freq
+	    gc3355_set_pll_freq(device->device_fd, val);    // clock was set via RPC or TUI
+
+	info->freq = val;
 }
 }
 
 
 static
 static
-const struct cgpu_info *gridseed_proc_by_id(const struct cgpu_info * const dev, int procid)
+const char *gridseed_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)
 {
 {
-	const struct cgpu_info *proc = dev;
-	for (int i = 0; i < procid; ++i)
-	{
-		proc = proc->next_proc;
-		if (unlikely(!proc))
-			return NULL;
-	}
-	return proc;
+	gridseed_set_clock_freq(device, atoi(setting));
+
+	return NULL;
 }
 }
 
 
 static
 static
-void gridseed_submit_nonce(struct thr_info * const master_thr, const unsigned char buf[GC3355_READ_SIZE])
+const char *gridseed_set_chips(struct cgpu_info * const device, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
 {
 {
-	struct work *work;
-	uint32_t nonce;
-	int workid;
-	struct cgpu_info * const device = master_thr->cgpu;
-	struct gc3355_orb_info * const info = device->device_data;
-	
-	// extract workid from buffer
-	memcpy(&workid, buf + 8, 4);
-	// extract nonce from buffer
-	memcpy(&nonce, buf + 4, 4);
-	// extract chip # from nonce
-	const int chip = nonce / ((uint32_t)0xffffffff / GC3355_ORB_DEFAULT_CHIPS);
-	// find processor by device & chip
-	const struct cgpu_info *proc = gridseed_proc_by_id(device, chip);
-	// default process to device
-	if (unlikely(!proc))
-		proc = device;
-	// the thread specific to the ASIC chip:
-	struct thr_info * thr = proc->thr[0];
+	struct gc3355_info * const info = device->device_data;
+	int val = atoi(setting);
 	
 	
-	nonce = htole32(nonce);
+	info->chips = val;
 	
 	
-	// find the queued work for this nonce, by workid
-	HASH_FIND(hh, master_thr->work_list, &workid, sizeof(workid), work);
-	if (work)
-	{
-		submit_nonce(thr, work, nonce);
-		
-		HASH_DEL(master_thr->work_list, work);
-		
-		gridseed_set_queue_full(device, info->needwork + 2);
-	}
+	return NULL;
 }
 }
 
 
+// for setting clock and chips during probe / detect
 static
 static
-void gridseed_estimate_hashes(const struct cgpu_info * const device)
+const struct bfg_set_device_definition gridseed_set_device_funcs_probe[] = {
+	{ "clock", gridseed_set_clock, NULL },
+	{ "chips", gridseed_set_chips, NULL },
+	{ NULL },
+};
+
+// for setting clock while mining
+static
+const struct bfg_set_device_definition gridseed_set_device_funcs_live[] = {
+	{ "clock", gridseed_set_clock, NULL },
+	{ NULL },
+};
+
+/*
+ * specify settings / options via TUI
+ */
+
+#ifdef HAVE_CURSES
+static
+void gridseed_tui_wlogprint_choices(struct cgpu_info * const proc)
 {
 {
-	const struct cgpu_info *proc = device;
-	const struct gc3355_orb_info *info = device->device_data;
-	
-	while (true)
-	{
-		hashes_done2(proc->thr[0], info->freq * 0xA4, NULL);
-		proc = proc->next_proc;
-		if (unlikely(!proc))
-			return;
-	}
+	wlogprint("[C]lock speed ");
 }
 }
 
 
-#define GRIDSEED_SHORT_WORK_DELAY_MS  20
-#define GRIDSEED_LONG_WORK_DELAY_MS   30
-
-// read from device for nonce or command
 static
 static
-void gridseed_poll(struct thr_info * const master_thr)
+const char *gridseed_tui_handle_choice(struct cgpu_info * const proc, const int input)
 {
 {
-	struct cgpu_info * const device = master_thr->cgpu;
-	unsigned char buf[GC3355_READ_SIZE];
-	int read = 0;
-	struct timeval tv_timeout;
-	timer_set_delay_from_now(&tv_timeout, GRIDSEED_LONG_WORK_DELAY_MS * 1000);  // X MS
-	
-	while (!master_thr->work_restart && (read = gc3355_read(device->device_fd, (char *)buf, GC3355_READ_SIZE)) > 0)
+	static char buf[0x100];  // Static for replies
+
+	switch (input)
 	{
 	{
-		if (buf[0] == 0x55)
-		{
-			switch(buf[1]) {
-				case 0xaa:
-					// Queue length result
-					// could watch for watchdog reset here
-					break;
-				case 0x10: // BTC result
-				case 0x20: // LTC result
-				{
-					gridseed_submit_nonce(master_thr, buf);
-					break;
-				}
-			}
-		} else
+		case 'c': case 'C':
 		{
 		{
-			applog(LOG_ERR, "%"PRIpreprv": Unrecognized response", device->proc_repr);
-			break;
-		}
-		
-		if (timer_passed(&tv_timeout, NULL))
-		{
-			// allow work to be sent to the device
-			applog(LOG_DEBUG, "%s poll: timeout met", device->dev_repr);
-			break;
+			sprintf(buf, "Set clock speed");
+			char * const setting = curses_input(buf);
+
+			gridseed_set_clock_freq(proc->device, atoi(setting));
+
+			return "Clock speed changed\n";
 		}
 		}
 	}
 	}
-	
-	gridseed_estimate_hashes(device);
-	
-	// allow work to be sent to the device
-	timer_set_delay_from_now(&master_thr->tv_poll, GRIDSEED_SHORT_WORK_DELAY_MS * 1000); // X MS
+	return NULL;
 }
 }
 
 
-/*
- * specify settings / options
- */
-
-// support for --set-device dualminer:clock=freq
 static
 static
-char *gridseed_set_device(struct cgpu_info *device, char *option, char *setting, char *replybuf)
+void gridseed_wlogprint_status(struct cgpu_info * const proc)
 {
 {
-	if (strcasecmp(option, "clock") == 0)
-	{
-		int val = atoi(setting);
-		
-		struct gc3355_orb_info *info = (struct gc3355_orb_info *)(device->device_data);
-		info->freq = val;
-		int fd = device->device_fd;
-		
-		gc3355_set_pll_freq(fd, val);
-		
-		return NULL;
-	}
-	
-	sprintf(replybuf, "Unknown option: %s", option);
-	return replybuf;
+	struct gc3355_info * const info = proc->device->device_data;
+	wlogprint("Clock speed: %d\n", info->freq);
 }
 }
+#endif
 
 
 struct device_drv gridseed_drv =
 struct device_drv gridseed_drv =
 {
 {
@@ -433,20 +453,20 @@ struct device_drv gridseed_drv =
 	
 	
 	// initialize device
 	// initialize device
 	.thread_prepare = gridseed_thread_prepare,
 	.thread_prepare = gridseed_thread_prepare,
-	.thread_init = gridseed_thread_init,
-	.reinit_device = gridseed_reinit_device,
 	
 	
 	// specify mining type - scanhash
 	// specify mining type - scanhash
-	.minerloop = minerloop_queue,
+	.minerloop = minerloop_scanhash,
 	
 	
-	// queued mining hooks
-	.queue_append = gridseed_queue_append,
-	.queue_flush = gridseed_queue_flush,
-	.poll = gridseed_poll,
+	// scanhash mining hooks
+	.scanhash = gridseed_scanhash,
 	
 	
 	// teardown device
 	// teardown device
 	.thread_shutdown = gridseed_thread_shutdown,
 	.thread_shutdown = gridseed_thread_shutdown,
-	
-	// specify settings / options
-	.set_device = gridseed_set_device,
+
+	// TUI support - e.g. setting clock via UI
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = gridseed_wlogprint_status,
+	.proc_tui_wlogprint_choices = gridseed_tui_wlogprint_choices,
+	.proc_tui_handle_choice = gridseed_tui_handle_choice,
+#endif
 };
 };

+ 8 - 2
driver-hashbuster.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  * Copyright 2013 Vladimir Strinski
  * Copyright 2013 Vladimir Strinski
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
@@ -91,7 +91,7 @@ bool hashbuster_spi_reset(hid_device * const h, uint8_t chips)
 	uint8_t buf[0x40] = {'\x02', chips};
 	uint8_t buf[0x40] = {'\x02', chips};
 	if (!hashbuster_io(h, buf, buf))
 	if (!hashbuster_io(h, buf, buf))
 		return false;
 		return false;
-	return (buf[1] == '\xff');
+	return (buf[1] == 0xff);
 }
 }
 
 
 static
 static
@@ -175,11 +175,17 @@ bool hashbuster_lowl_probe(const struct lowlevel_device_info * const info)
 	uint8_t buf[0x40] = {'\xfe'};
 	uint8_t buf[0x40] = {'\xfe'};
 	
 	
 	if (info->lowl != &lowl_hid)
 	if (info->lowl != &lowl_hid)
+	{
+		bfg_probe_result_flags = BPR_WRONG_DEVTYPE;
 		applogr(false, LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not hid!",
 		applogr(false, LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not hid!",
 		       __func__, product, serial);
 		       __func__, product, serial);
+	}
 	
 	
 	if (info->vid != 0xFA04 || info->pid != 0x0011)
 	if (info->vid != 0xFA04 || info->pid != 0x0011)
+	{
+		bfg_probe_result_flags = BPR_WRONG_DEVTYPE;
 		applogr(false, LOG_DEBUG, "%s: Wrong VID/PID", __func__);
 		applogr(false, LOG_DEBUG, "%s: Wrong VID/PID", __func__);
+	}
 	
 	
 	h = hid_open_path(path);
 	h = hid_open_path(path);
 	if (!h)
 	if (!h)

+ 2 - 0
driver-hashbusteravalon.c

@@ -7,6 +7,8 @@
  * any later version.  See COPYING for more details.
  * any later version.  See COPYING for more details.
  */
  */
 
 
+#include "config.h"
+
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdlib.h>
 #include <stdlib.h>
 
 

+ 7 - 1
driver-hashbusterusb.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  * Copyright 2013 Vladimir Strinski
  * Copyright 2013 Vladimir Strinski
  * Copyright 2013 HashBuster team
  * Copyright 2013 HashBuster team
  *
  *
@@ -156,11 +156,17 @@ bool hashbusterusb_lowl_probe(const struct lowlevel_device_info * const info)
 	libusb_device_handle *h;
 	libusb_device_handle *h;
 	
 	
 	if (info->lowl != &lowl_usb)
 	if (info->lowl != &lowl_usb)
+	{
+		bfg_probe_result_flags = BPR_WRONG_DEVTYPE;
 		applogr(false, LOG_DEBUG, "%s: Matched \"%s\" %s, but lowlevel driver is not usb_generic!",
 		applogr(false, LOG_DEBUG, "%s: Matched \"%s\" %s, but lowlevel driver is not usb_generic!",
 		       __func__, product, info->devid);
 		       __func__, product, info->devid);
+	}
 	
 	
 	if (info->vid != 0xFA04 || info->pid != 0x000D)
 	if (info->vid != 0xFA04 || info->pid != 0x000D)
+	{
+		bfg_probe_result_flags = BPR_WRONG_DEVTYPE;
 		applogr(false, LOG_DEBUG, "%s: Wrong VID/PID", __func__);
 		applogr(false, LOG_DEBUG, "%s: Wrong VID/PID", __func__);
+	}
 	
 	
 	libusb_device *dev = info->lowl_data;
 	libusb_device *dev = info->lowl_data;
 	if ( (j = libusb_open(dev, &h)) )
 	if ( (j = libusb_open(dev, &h)) )

+ 182 - 6
driver-hashfast.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -34,6 +34,7 @@ BFG_REGISTER_DRIVER(hashfast_ums_drv)
 #define HASHFAST_MAX_DATA 0x3fc
 #define HASHFAST_MAX_DATA 0x3fc
 #define HASHFAST_HASH_SIZE (0x20 + 0xc + 4 + 4 + 2 + 1 + 1)
 #define HASHFAST_HASH_SIZE (0x20 + 0xc + 4 + 4 + 2 + 1 + 1)
 #define HASHFAST_MAX_VOLTAGES 4
 #define HASHFAST_MAX_VOLTAGES 4
+#define HASHFAST_CONFIG_DATA_SIZE  0x10
 
 
 enum hashfast_opcode {
 enum hashfast_opcode {
 	HFOP_NULL          =    0,
 	HFOP_NULL          =    0,
@@ -63,6 +64,7 @@ enum hashfast_opcode {
 	HFOP_USB_SHUTDOWN  = 0x85,
 	HFOP_USB_SHUTDOWN  = 0x85,
 	HFOP_DIE_STATUS    = 0x86,
 	HFOP_DIE_STATUS    = 0x86,
 	HFOP_GWQ_STATUS    = 0x87,
 	HFOP_GWQ_STATUS    = 0x87,
+	HFOP_UMS_CLOCK_CHANGE = 0x88,
 	HFOP_WORK_RESTART  = 0x88,
 	HFOP_WORK_RESTART  = 0x88,
 	HFOP_USB_STATS1    = 0x89,
 	HFOP_USB_STATS1    = 0x89,
 	HFOP_USB_GWQSTATS  = 0x8a,
 	HFOP_USB_GWQSTATS  = 0x8a,
@@ -70,6 +72,23 @@ enum hashfast_opcode {
 	HFOP_USB_DEBUG     = 0xff,
 	HFOP_USB_DEBUG     = 0xff,
 };
 };
 
 
+enum hashfast_config_hdata {
+	HFCH_WRITE         = 1 << 0xf,
+	HFCH_THERMAL_LIMIT = 1 << 0xe,
+	HFCH_TACHO         = 1 << 0xd,
+};
+
+enum hashfast_config_flags {
+	HFCF_STATUS_PERIOD = 1 << 0xb,
+	HFCF_STATUS_IDLE   = 1 << 0xc,
+	HFCF_STATUS_EMPTY  = 1 << 0xd,
+	HFCF_PWM_ACTIVE_LV = 1 << 0xe,
+};
+
+enum hashfast_clock_change_cmd {
+	HFWR_SET_CLOCK     = 1 << 0xc,
+};
+
 typedef unsigned long hashfast_isn_t;
 typedef unsigned long hashfast_isn_t;
 
 
 static inline
 static inline
@@ -203,8 +222,8 @@ ignoresome:
 static
 static
 bool hashfast_lowl_match(const struct lowlevel_device_info * const info)
 bool hashfast_lowl_match(const struct lowlevel_device_info * const info)
 {
 {
-	if (!lowlevel_match_id(info, &lowl_vcom, 0, 0))
-		return false;
+	if (lowlevel_match_product(info, "GoldenNonce"))
+		return true;
 	return (info->manufacturer && strstr(info->manufacturer, "HashFast"));
 	return (info->manufacturer && strstr(info->manufacturer, "HashFast"));
 }
 }
 
 
@@ -218,10 +237,12 @@ const char *hashfast_set_clock(struct cgpu_info * const proc, const char * const
 }
 }
 
 
 static const struct bfg_set_device_definition hashfast_set_device_funcs_probe[] = {
 static const struct bfg_set_device_definition hashfast_set_device_funcs_probe[] = {
-	{"clock", hashfast_set_clock, "clock frequency (can only be set at startup, with --set-device)"},
+	{"clock", hashfast_set_clock, "clock frequency"},
 	{NULL},
 	{NULL},
 };
 };
 
 
+static const struct bfg_set_device_definition hashfast_set_device_funcs[];
+
 static
 static
 bool hashfast_detect_one(const char * const devpath)
 bool hashfast_detect_one(const char * const devpath)
 {
 {
@@ -259,10 +280,20 @@ bool hashfast_detect_one(const char * const devpath)
 		        __func__, devpath, pmsg->data[8]);
 		        __func__, devpath, pmsg->data[8]);
 		goto err;
 		goto err;
 	}
 	}
+	uint16_t fwrev = upk_u16le(pmsg->data, 0);
+	if (!fwrev)
+	{
+		// fwrev == 0 means latest experimental; make it >= every possible comparison
+		fwrev = 0xffff;
+		pk_u16le(pmsg->data, 0, fwrev);
+	}
 	
 	
 	if (serial_claim_v(devpath, &hashfast_ums_drv))
 	if (serial_claim_v(devpath, &hashfast_ums_drv))
 		return false;
 		return false;
 	
 	
+	// Hijack hdata for a quick way to transfer clock to init
+	pmsg->hdata = clock;
+	
 	struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
 	struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
 	*cgpu = (struct cgpu_info){
 	*cgpu = (struct cgpu_info){
 		.drv = &hashfast_ums_drv,
 		.drv = &hashfast_ums_drv,
@@ -273,6 +304,10 @@ bool hashfast_detect_one(const char * const devpath)
 		.device_data = pmsg,
 		.device_data = pmsg,
 		.cutofftemp = 100,
 		.cutofftemp = 100,
 	};
 	};
+	
+	if (fwrev >= 0x0005)
+		cgpu->set_device_funcs = hashfast_set_device_funcs;
+	
 	return add_cgpu(cgpu);
 	return add_cgpu(cgpu);
 
 
 err:
 err:
@@ -290,12 +325,16 @@ struct hashfast_dev_state {
 	uint8_t cores_per_chip;
 	uint8_t cores_per_chip;
 	int fd;
 	int fd;
 	struct hashfast_chip_state *chipstates;
 	struct hashfast_chip_state *chipstates;
+	uint16_t fwrev;
 };
 };
 
 
 struct hashfast_chip_state {
 struct hashfast_chip_state {
 	struct cgpu_info **coreprocs;
 	struct cgpu_info **coreprocs;
 	hashfast_isn_t last_isn;
 	hashfast_isn_t last_isn;
 	float voltages[HASHFAST_MAX_VOLTAGES];
 	float voltages[HASHFAST_MAX_VOLTAGES];
+	uint16_t clock;
+	uint16_t clock_desired;
+	uint8_t cfgdata[HASHFAST_CONFIG_DATA_SIZE];
 };
 };
 
 
 struct hashfast_core_state {
 struct hashfast_core_state {
@@ -309,6 +348,80 @@ struct hashfast_core_state {
 	unsigned queued;
 	unsigned queued;
 };
 };
 
 
+static
+const char *hashfast_set_clock_runtime(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 thr_info * const thr = proc->thr[0];
+	struct hashfast_dev_state * const devstate = proc->device_data;
+	struct hashfast_core_state * const cs = thr->cgpu_data;
+	struct hashfast_chip_state * const chipstate = &devstate->chipstates[cs->chipaddr];
+	
+	const int nv = atoi(newvalue);
+	if (nv >= 0xfff)
+		return "Clock frequency too high";
+	
+	chipstate->clock_desired = nv;
+	
+	return NULL;
+}
+
+static const struct bfg_set_device_definition hashfast_set_device_funcs[] = {
+	{"clock", hashfast_set_clock_runtime, "clock frequency"},
+	{NULL},
+};
+
+static
+void hashfast_init_cfgdata(struct hashfast_chip_state * const chipstate)
+{
+	uint8_t * const cfgdata = chipstate->cfgdata;
+	
+	const uint16_t status_ms = 500;
+	const bool send_status_on_core_idle = false;
+	const bool send_status_on_pending_empty = false;
+	const bool pwm_active_level = false;
+	const uint8_t status_batching_delay_ms = 0;
+	const uint8_t watchdog_sec = 0;
+	const uint8_t rx_header_timeout = 20, rx_data_timeout = 20;
+	const uint8_t stats_sec = 10;
+	const uint8_t temp_measure_ms = 100;
+	const uint16_t lf_clocks_per_usec = 125 /* FIXME: or 126? */;
+	const uint8_t max_nonces_per_frame = 1;
+	const uint8_t voltage_sample_points = 0x1f;
+	const uint8_t pwm_phases = 1, pwm_period = 0, pwm_pulse_period = 0;
+	const uint8_t temp_trim = 0;
+	
+	pk_u16le(cfgdata, 0,
+	         (status_ms & 0x7ff) | (status_ms ? HFCF_STATUS_PERIOD : 0) |
+	         (send_status_on_core_idle     ? HFCF_STATUS_IDLE   : 0) |
+	         (send_status_on_pending_empty ? HFCF_STATUS_EMPTY  : 0) |
+	         (pwm_active_level             ? HFCF_PWM_ACTIVE_LV : 0));
+	pk_u8(cfgdata, 2, status_batching_delay_ms);
+	pk_u8(cfgdata, 3, watchdog_sec & 0x7f);
+	
+	pk_u8(cfgdata, 4, rx_header_timeout & 0x7f);
+	pk_u8(cfgdata, 5, rx_data_timeout   & 0x7f);
+	pk_u8(cfgdata, 6, stats_sec         & 0x7f);
+	pk_u8(cfgdata, 7, temp_measure_ms);
+	
+	pk_u16le(cfgdata, 8,
+	         ((lf_clocks_per_usec - 1) & 0xfff) |
+	         ((max_nonces_per_frame & 0xf) << 0xc));
+	pk_u8(cfgdata, 0xa, voltage_sample_points);
+	pk_u8(cfgdata, 0xb,
+	      ((pwm_phases - 1) & 3) |
+	      ((temp_trim & 0xf) << 2));
+	
+	pk_u16le(cfgdata, 0xc, pwm_period);
+	pk_u16le(cfgdata, 0xe, pwm_pulse_period);
+}
+
+static
+uint16_t hashfast_chip_thermal_cutoff_hdata(const float temp)
+{
+	const uint16_t v = (temp + 61.5) * 0x1000 / 240;
+	return HFCH_THERMAL_LIMIT | (v & 0x3ff);
+}
+
 static
 static
 bool hashfast_init(struct thr_info * const master_thr)
 bool hashfast_init(struct thr_info * const master_thr)
 {
 {
@@ -323,14 +436,20 @@ bool hashfast_init(struct thr_info * const master_thr)
 		.chipstates = chipstates,
 		.chipstates = chipstates,
 		.cores_per_chip = pmsg->coreaddr,
 		.cores_per_chip = pmsg->coreaddr,
 		.fd = serial_open(dev->device_path, 0, 1, true),
 		.fd = serial_open(dev->device_path, 0, 1, true),
+		.fwrev = upk_u16le(pmsg->data, 0),
 	};
 	};
 	
 	
+	const uint16_t clock = pmsg->hdata;
+	
 	for (i = 0; i < pmsg->chipaddr; ++i)
 	for (i = 0; i < pmsg->chipaddr; ++i)
 	{
 	{
 		chipstate = &chipstates[i];
 		chipstate = &chipstates[i];
 		*chipstate = (struct hashfast_chip_state){
 		*chipstate = (struct hashfast_chip_state){
 			.coreprocs = malloc(sizeof(struct cgpu_info *) * pmsg->coreaddr),
 			.coreprocs = malloc(sizeof(struct cgpu_info *) * pmsg->coreaddr),
+			.clock = clock,
+			.clock_desired = clock,
 		};
 		};
+		hashfast_init_cfgdata(chipstate);
 	}
 	}
 	
 	
 	for ((i = 0), (proc = dev); proc; ++i, (proc = proc->next_proc))
 	for ((i = 0), (proc = dev); proc; ++i, (proc = proc->next_proc))
@@ -352,6 +471,11 @@ bool hashfast_init(struct thr_info * const master_thr)
 	
 	
 	// TODO: actual clock = [12,13]
 	// TODO: actual clock = [12,13]
 	
 	
+	for_each_managed_proc(proc, dev)
+	{
+		proc->status = LIFE_INIT2;
+	}
+	
 	timer_set_now(&master_thr->tv_poll);
 	timer_set_now(&master_thr->tv_poll);
 	return true;
 	return true;
 }
 }
@@ -370,7 +494,7 @@ bool hashfast_queue_append(struct thr_info * const thr, struct work * const work
 	hashfast_isn_t isn;
 	hashfast_isn_t isn;
 	uint8_t seq;
 	uint8_t seq;
 	
 	
-	if (cs->has_pending)
+	if (cs->has_pending || chipstate->clock_desired != chipstate->clock)
 	{
 	{
 		thr->queue_full = true;
 		thr->queue_full = true;
 		return false;
 		return false;
@@ -544,6 +668,7 @@ bool hashfast_poll_msg(struct thr_info * const master_thr)
 		{
 		{
 			const uint8_t *data = &msg.data[8];
 			const uint8_t *data = &msg.data[8];
 			struct cgpu_info *proc = hashfast_find_proc(master_thr, msg.chipaddr, 0);
 			struct cgpu_info *proc = hashfast_find_proc(master_thr, msg.chipaddr, 0);
+			struct cgpu_info *first_proc = proc;
 			if (unlikely(!proc))
 			if (unlikely(!proc))
 			{
 			{
 				applog(LOG_ERR, "%s: Unknown chip address %u",
 				applog(LOG_ERR, "%s: Unknown chip address %u",
@@ -584,13 +709,50 @@ bool hashfast_poll_msg(struct thr_info * const master_thr)
 				{
 				{
 					++cores_transitioned;
 					++cores_transitioned;
 					cs->has_pending = false;
 					cs->has_pending = false;
-					thr->queue_full = false;
+					// Avoid refilling pending slot if we are preparing to change the clock frequency
+					if (chipstate->clock_desired == chipstate->clock)
+						thr->queue_full = false;
 				}
 				}
 			}
 			}
 			applog(LOG_DEBUG, "%s: STATUS from chipaddr=0x%02x with hdata=0x%04x (isn=0x%lx): total=%d uptodate=%d active=%d pending=%d transitioned=%d",
 			applog(LOG_DEBUG, "%s: STATUS from chipaddr=0x%02x with hdata=0x%04x (isn=0x%lx): total=%d uptodate=%d active=%d pending=%d transitioned=%d",
 			       dev->dev_repr, (unsigned)msg.chipaddr, (unsigned)msg.hdata, isn,
 			       dev->dev_repr, (unsigned)msg.chipaddr, (unsigned)msg.hdata, isn,
 			       devstate->cores_per_chip, cores_uptodate,
 			       devstate->cores_per_chip, cores_uptodate,
 			       cores_active, cores_pending, cores_transitioned);
 			       cores_active, cores_pending, cores_transitioned);
+			if ((!cores_active) && chipstate->clock_desired != chipstate->clock)
+			{
+				// All cores finished their work, change clock frequency and then refill
+				uint8_t buf[HASHFAST_HEADER_SIZE + HASHFAST_CONFIG_DATA_SIZE];
+				uint16_t clock = chipstate->clock_desired, hdata;
+				if (!hashfast_send_msg(fd, buf, HFOP_UMS_CLOCK_CHANGE, msg.chipaddr, 0, HFWR_SET_CLOCK | clock, 0))
+				{
+					applog(LOG_ERR, "%"PRIpreprv": Clock change failure (%s)", proc->proc_repr, "OP_UMS_CLOCK_CHANGE");
+					goto clockchangefailed;
+				}
+				// Until we send HFOP_CONFIG, the state is undefined
+				chipstate->clock = 0;
+				
+				hdata = HFCH_WRITE;
+				hdata |= hashfast_chip_thermal_cutoff_hdata(110);
+				pk_uNle(chipstate->cfgdata, 8, 0, 0xc, clock);
+				memcpy(&buf[HASHFAST_HEADER_SIZE], chipstate->cfgdata, HASHFAST_CONFIG_DATA_SIZE);
+				if (!hashfast_send_msg(fd, buf, HFOP_CONFIG, msg.chipaddr, 0, hdata, HASHFAST_CONFIG_DATA_SIZE))
+				{
+					applog(LOG_ERR, "%"PRIpreprv": Clock change failure (%s)", proc->proc_repr, "OP_CONFIG");
+					goto clockchangefailed;
+				}
+				
+				chipstate->clock = clock;
+				
+				// Time to refill queues
+				proc = first_proc;
+				for (int i = 0; i < devstate->cores_per_chip; ++i, (proc = proc->next_proc))
+				{
+					struct thr_info * const thr = proc->thr[0];
+					thr->queue_full = false;
+				}
+				
+clockchangefailed: ;
+			}
 			break;
 			break;
 		}
 		}
 	}
 	}
@@ -640,6 +802,19 @@ struct api_data *hashfast_api_stats(struct cgpu_info * const proc)
 	return root;
 	return root;
 }
 }
 
 
+static
+struct api_data *hashfast_api_devdetail(struct cgpu_info * const proc)
+{
+	struct thr_info * const thr = proc->thr[0];
+	struct hashfast_core_state * const cs = thr->cgpu_data;
+	struct api_data *root = NULL;
+	
+	root = api_add_uint8(root, "Chip Address", &cs->chipaddr, false);
+	root = api_add_uint8(root, "Core Address", &cs->coreaddr, false);
+	
+	return root;
+}
+
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 static
 static
 void hashfast_wlogprint_status(struct cgpu_info * const proc)
 void hashfast_wlogprint_status(struct cgpu_info * const proc)
@@ -686,6 +861,7 @@ struct device_drv hashfast_ums_drv = {
 	.poll = hashfast_poll,
 	.poll = hashfast_poll,
 	
 	
 	.get_api_stats = hashfast_api_stats,
 	.get_api_stats = hashfast_api_stats,
+	.get_api_extra_device_detail = hashfast_api_devdetail,
 	
 	
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 	.proc_wlogprint_status = hashfast_wlogprint_status,
 	.proc_wlogprint_status = hashfast_wlogprint_status,

+ 196 - 157
driver-icarus.c

@@ -1,6 +1,7 @@
 /*
 /*
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2014 Luke Dashjr
  * Copyright 2012 Xiangfu
  * Copyright 2012 Xiangfu
+ * Copyright 2014 Nate Woolls
  * Copyright 2012 Andrew Smith
  * Copyright 2012 Andrew Smith
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
@@ -148,21 +149,10 @@ static const char *MODE_UNKNOWN_STR = "unknown";
 
 
 BFG_REGISTER_DRIVER(icarus_drv)
 BFG_REGISTER_DRIVER(icarus_drv)
 extern const struct bfg_set_device_definition icarus_set_device_funcs[];
 extern const struct bfg_set_device_definition icarus_set_device_funcs[];
+extern const struct bfg_set_device_definition icarus_set_device_funcs_live[];
 
 
 extern void convert_icarus_to_cairnsmore(struct cgpu_info *);
 extern void convert_icarus_to_cairnsmore(struct cgpu_info *);
 
 
-static void rev(unsigned char *s, size_t l)
-{
-	size_t i, j;
-	unsigned char t;
-
-	for (i = 0, j = l - 1; i < j; i++, j--) {
-		t = s[i];
-		s[i] = s[j];
-		s[j] = t;
-	}
-}
-
 static inline
 static inline
 uint32_t icarus_nonce32toh(const struct ICARUS_INFO * const info, const uint32_t nonce)
 uint32_t icarus_nonce32toh(const struct ICARUS_INFO * const info, const uint32_t nonce)
 {
 {
@@ -324,9 +314,8 @@ static const char *timing_mode_str(enum timing_mode timing_mode)
 }
 }
 
 
 static
 static
-const char *icarus_set_timing(struct cgpu_info * const proc, const char * const optname, const char * const buf, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+const char *_icarus_set_timing(struct ICARUS_INFO * const info, const char * const repr, const struct device_drv * const drv, const char * const buf)
 {
 {
-	struct ICARUS_INFO * const info = proc->device_data;
 	double Hs;
 	double Hs;
 	char *eq;
 	char *eq;
 
 
@@ -399,7 +388,7 @@ const char *icarus_set_timing(struct cgpu_info * const proc, const char * const
 		int def_read_count = ICARUS_READ_COUNT_TIMING;
 		int def_read_count = ICARUS_READ_COUNT_TIMING;
 
 
 		if (info->timing_mode == MODE_DEFAULT) {
 		if (info->timing_mode == MODE_DEFAULT) {
-			if (proc->drv == &icarus_drv) {
+			if (drv == &icarus_drv) {
 				info->do_default_detection = 0x10;
 				info->do_default_detection = 0x10;
 			} else {
 			} else {
 				def_read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
 				def_read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
@@ -416,36 +405,23 @@ const char *icarus_set_timing(struct cgpu_info * const proc, const char * const
 	info->min_data_count = MIN_DATA_COUNT;
 	info->min_data_count = MIN_DATA_COUNT;
 
 
 	applog(LOG_DEBUG, "%"PRIpreprv": Init: mode=%s read_count=%d limit=%dms Hs=%e",
 	applog(LOG_DEBUG, "%"PRIpreprv": Init: mode=%s read_count=%d limit=%dms Hs=%e",
-		proc->proc_repr,
+		repr,
 		timing_mode_str(info->timing_mode),
 		timing_mode_str(info->timing_mode),
 		info->read_count, info->read_count_limit, info->Hs);
 		info->read_count, info->read_count_limit, info->Hs);
 	
 	
 	return NULL;
 	return NULL;
 }
 }
 
 
-static uint32_t mask(int work_division)
+static
+const char *icarus_set_timing(struct cgpu_info * const proc, const char * const optname, const char * const buf, char * const replybuf, enum bfg_set_device_replytype * const out_success)
 {
 {
-	uint32_t nonce_mask = 0x7fffffff;
-
-	// yes we can calculate these, but this way it's easy to see what they are
-	switch (work_division) {
-	case 1:
-		nonce_mask = 0xffffffff;
-		break;
-	case 2:
-		nonce_mask = 0x7fffffff;
-		break;
-	case 4:
-		nonce_mask = 0x3fffffff;
-		break;
-	case 8:
-		nonce_mask = 0x1fffffff;
-		break;
-	default:
-		quit(1, "Invalid2 work_division (%d) must be 1, 2, 4 or 8", work_division);
-	}
+	struct ICARUS_INFO * const info = proc->device_data;
+	return _icarus_set_timing(info, proc->proc_repr, proc->drv, buf);
+}
 
 
-	return nonce_mask;
+static uint32_t mask(int work_division)
+{
+	return 0xffffffff / work_division;
 }
 }
 
 
 // Number of bytes remaining after reading a nonce from Icarus
 // Number of bytes remaining after reading a nonce from Icarus
@@ -469,6 +445,56 @@ int icarus_excess_nonce_size(int fd, struct ICARUS_INFO *info)
 	return bytes_read;
 	return bytes_read;
 }
 }
 
 
+int icarus_probe_work_division(const int fd, const char * const repr, struct ICARUS_INFO * const info)
+{
+	struct timeval tv_finish;
+	
+	// For reading the nonce from Icarus
+	unsigned char res_bin[info->read_size];
+	// For storing the the 32-bit nonce
+	uint32_t res;
+	int work_division = 0;
+	
+	applog(LOG_DEBUG, "%s: Work division not specified - autodetecting", repr);
+	
+	// Special packet to probe work_division
+	unsigned char pkt[64] =
+		"\x2e\x4c\x8f\x91\xfd\x59\x5d\x2d\x7e\xa2\x0a\xaa\xcb\x64\xa2\xa0"
+		"\x43\x82\x86\x02\x77\xcf\x26\xb6\xa1\xee\x04\xc5\x6a\x5b\x50\x4a"
+		"BFGMiner Probe\0\0"
+		"BFG\0\x64\x61\x01\x1a\xc9\x06\xa9\x51\xfb\x9b\x3c\x73";
+	
+	icarus_write(fd, pkt, sizeof(pkt));
+	memset(res_bin, 0, sizeof(res_bin));
+	if (ICA_GETS_OK == icarus_gets(res_bin, fd, &tv_finish, NULL, info->read_count, info->read_size))
+	{
+		memcpy(&res, res_bin, sizeof(res));
+		res = icarus_nonce32toh(info, res);
+	}
+	else
+		res = 0;
+	
+	switch (res) {
+		case 0x04C0FDB4:
+			work_division = 1;
+			break;
+		case 0x82540E46:
+			work_division = 2;
+			break;
+		case 0x417C0F36:
+			work_division = 4;
+			break;
+		case 0x60C994D5:
+			work_division = 8;
+			break;
+		default:
+			applog(LOG_ERR, "%s: Work division autodetection failed (assuming 2): got %08x", repr, res);
+			work_division = 2;
+	}
+	applog(LOG_DEBUG, "%s: Work division autodetection got %08x (=%d)", repr, res, work_division);
+	return work_division;
+}
+
 bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct ICARUS_INFO *info)
 bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct ICARUS_INFO *info)
 {
 {
 	struct timeval tv_start, tv_finish;
 	struct timeval tv_start, tv_finish;
@@ -524,42 +550,47 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 	int ob_size = strlen(info->golden_ob) / 2;
 	int ob_size = strlen(info->golden_ob) / 2;
 	unsigned char ob_bin[ob_size];
 	unsigned char ob_bin[ob_size];
 	BFGINIT(info->ob_size, ob_size);
 	BFGINIT(info->ob_size, ob_size);
-	
-	hex2bin(ob_bin, info->golden_ob, sizeof(ob_bin));
-	icarus_write(fd, ob_bin, sizeof(ob_bin));
-	cgtime(&tv_start);
-
-	memset(nonce_bin, 0, sizeof(nonce_bin));
-	// Do not use info->read_size here, instead read exactly ICARUS_NONCE_SIZE
-	// We will then compare the bytes left in fd with info->read_size to determine
-	// if this is a valid device
-	icarus_gets(nonce_bin, fd, &tv_finish, NULL, info->probe_read_count, ICARUS_NONCE_SIZE);
-	
-	// How many bytes were left after reading the above nonce
-	int bytes_left = icarus_excess_nonce_size(fd, info);
-	
-	icarus_close(fd);
 
 
-	bin2hex(nonce_hex, nonce_bin, sizeof(nonce_bin));
-	if (strncmp(nonce_hex, info->golden_nonce, 8))
+	if (!info->ignore_golden_nonce)
 	{
 	{
-		applog(LOG_DEBUG,
-			"%s: "
-			"Test failed at %s: get %s, should: %s",
-			api->dname,
-			devpath, nonce_hex, info->golden_nonce);
-		return false;
-	}
+		hex2bin(ob_bin, info->golden_ob, sizeof(ob_bin));
+		icarus_write(fd, ob_bin, sizeof(ob_bin));
+		cgtime(&tv_start);
 		
 		
-	if (info->read_size - ICARUS_NONCE_SIZE != bytes_left) 
-	{
-		applog(LOG_DEBUG,
-			   "%s: "
-			   "Test failed at %s: expected %d bytes, got %d",
-			   api->dname,
-			   devpath, info->read_size, ICARUS_NONCE_SIZE + bytes_left);
-		return false;
+		memset(nonce_bin, 0, sizeof(nonce_bin));
+		// Do not use info->read_size here, instead read exactly ICARUS_NONCE_SIZE
+		// We will then compare the bytes left in fd with info->read_size to determine
+		// if this is a valid device
+		icarus_gets(nonce_bin, fd, &tv_finish, NULL, info->probe_read_count, ICARUS_NONCE_SIZE);
+		
+		// How many bytes were left after reading the above nonce
+		int bytes_left = icarus_excess_nonce_size(fd, info);
+		
+		icarus_close(fd);
+		
+		bin2hex(nonce_hex, nonce_bin, sizeof(nonce_bin));
+		if (strncmp(nonce_hex, info->golden_nonce, 8))
+		{
+			applog(LOG_DEBUG,
+				   "%s: "
+				   "Test failed at %s: get %s, should: %s",
+				   api->dname,
+				   devpath, nonce_hex, info->golden_nonce);
+			return false;
+		}
+		
+		if (info->read_size - ICARUS_NONCE_SIZE != bytes_left)
+		{
+			applog(LOG_DEBUG,
+				   "%s: "
+				   "Test failed at %s: expected %d bytes, got %d",
+				   api->dname,
+				   devpath, info->read_size, ICARUS_NONCE_SIZE + bytes_left);
+			return false;
+		}
 	}
 	}
+	else
+		icarus_close(fd);
 	
 	
 	applog(LOG_DEBUG,
 	applog(LOG_DEBUG,
 		"%s: "
 		"%s: "
@@ -570,6 +601,20 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 	if (serial_claim_v(devpath, api))
 	if (serial_claim_v(devpath, api))
 		return false;
 		return false;
 
 
+	_icarus_set_timing(info, api->dname, api, "");
+	if (!info->fpga_count)
+	{
+		if (!info->work_division)
+		{
+			fd = icarus_open2(devpath, baud, true);
+			info->work_division = icarus_probe_work_division(fd, api->dname, info);
+			icarus_close(fd);
+		}
+		info->fpga_count = info->work_division;
+	}
+	// Lock fpga_count from set_work_division
+	info->user_set |= IUS_FPGA_COUNT;
+	
 	/* We have a real Icarus! */
 	/* We have a real Icarus! */
 	struct cgpu_info *icarus;
 	struct cgpu_info *icarus;
 	icarus = calloc(1, sizeof(struct cgpu_info));
 	icarus = calloc(1, sizeof(struct cgpu_info));
@@ -577,7 +622,8 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 	icarus->device_path = strdup(devpath);
 	icarus->device_path = strdup(devpath);
 	icarus->device_fd = -1;
 	icarus->device_fd = -1;
 	icarus->threads = 1;
 	icarus->threads = 1;
-	icarus->set_device_funcs = icarus_set_device_funcs;
+	icarus->procs = info->fpga_count;
+	icarus->set_device_funcs = icarus_set_device_funcs_live;
 	add_cgpu(icarus);
 	add_cgpu(icarus);
 
 
 	applog(LOG_INFO, "Found %"PRIpreprv" at %s",
 	applog(LOG_INFO, "Found %"PRIpreprv" at %s",
@@ -591,7 +637,6 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 	icarus->device_data = info;
 	icarus->device_data = info;
 
 
 	timersub(&tv_finish, &tv_start, &(info->golden_tv));
 	timersub(&tv_finish, &tv_start, &(info->golden_tv));
-	icarus_set_timing(icarus, NULL, "", NULL, NULL);
 
 
 	return true;
 	return true;
 }
 }
@@ -663,64 +708,30 @@ bool icarus_init(struct thr_info *thr)
 	applog(LOG_INFO, "%s: Opened %s", icarus->dev_repr, icarus->device_path);
 	applog(LOG_INFO, "%s: Opened %s", icarus->dev_repr, icarus->device_path);
 	
 	
 	BFGINIT(info->job_start_func, icarus_job_start);
 	BFGINIT(info->job_start_func, icarus_job_start);
-	BFGINIT(state->ob_bin, malloc(info->ob_size));
+	BFGINIT(state->ob_bin, calloc(1, info->ob_size));
 	
 	
 	if (!info->work_division)
 	if (!info->work_division)
-	{
-		struct timeval tv_finish;
-		
-		// For reading the nonce from Icarus
-		unsigned char res_bin[info->read_size];
-		// For storing the the 32-bit nonce
-		uint32_t res;
-		
-		applog(LOG_DEBUG, "%"PRIpreprv": Work division not specified - autodetecting", icarus->proc_repr);
-		
-		// Special packet to probe work_division
-		unsigned char pkt[64] =
-			"\x2e\x4c\x8f\x91\xfd\x59\x5d\x2d\x7e\xa2\x0a\xaa\xcb\x64\xa2\xa0"
-			"\x43\x82\x86\x02\x77\xcf\x26\xb6\xa1\xee\x04\xc5\x6a\x5b\x50\x4a"
-			"BFGMiner Probe\0\0"
-			"BFG\0\x64\x61\x01\x1a\xc9\x06\xa9\x51\xfb\x9b\x3c\x73";
-		
-		icarus_write(fd, pkt, sizeof(pkt));
-		memset(res_bin, 0, sizeof(res_bin));
-		if (ICA_GETS_OK == icarus_gets(res_bin, fd, &tv_finish, NULL, info->read_count, info->read_size))
-		{
-			memcpy(&res, res_bin, sizeof(res));
-			res = icarus_nonce32toh(info, res);
-		}
-		else
-			res = 0;
-		
-		switch (res) {
-			case 0x04C0FDB4:
-				info->work_division = 1;
-				break;
-			case 0x82540E46:
-				info->work_division = 2;
-				break;
-			case 0x417C0F36:
-				info->work_division = 4;
-				break;
-			case 0x60C994D5:
-				info->work_division = 8;
-				break;
-			default:
-				applog(LOG_ERR, "%"PRIpreprv": Work division autodetection failed (assuming 2): got %08x", icarus->proc_repr, res);
-				info->work_division = 2;
-		}
-		applog(LOG_DEBUG, "%"PRIpreprv": Work division autodetection got %08x (=%d)", icarus->proc_repr, res, info->work_division);
-	}
-	
-	if (!info->fpga_count)
-		info->fpga_count = info->work_division;
+		info->work_division = icarus_probe_work_division(fd, icarus->proc_repr, info);
 	
 	
+	if (!is_power_of_two(info->work_division))
+		info->work_division = upper_power_of_two_u32(info->work_division);
 	info->nonce_mask = mask(info->work_division);
 	info->nonce_mask = mask(info->work_division);
 	
 	
 	return true;
 	return true;
 }
 }
 
 
+static
+struct thr_info *icarus_thread_for_nonce(const struct cgpu_info * const icarus, const uint32_t nonce)
+{
+	struct ICARUS_INFO * const info = icarus->device_data;
+	unsigned proc_id = 0;
+	for (int i = info->work_division, j = 0; i /= 2; ++j)
+		if (nonce & (1 << (31 - j)))
+			proc_id |= (1 << j);
+	const struct cgpu_info * const proc = device_proc_by_id(icarus, proc_id) ?: icarus;
+	return proc->thr[0];
+}
+
 static bool icarus_reopen(struct cgpu_info *icarus, struct icarus_state *state, int *fdp)
 static bool icarus_reopen(struct cgpu_info *icarus, struct icarus_state *state, int *fdp)
 {
 {
 	struct ICARUS_INFO *info = icarus->device_data;
 	struct ICARUS_INFO *info = icarus->device_data;
@@ -744,8 +755,8 @@ bool icarus_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused
 	struct icarus_state * const state = thr->cgpu_data;
 	struct icarus_state * const state = thr->cgpu_data;
 	uint8_t * const ob_bin = state->ob_bin;
 	uint8_t * const ob_bin = state->ob_bin;
 	
 	
-	memcpy(ob_bin, work->midstate, 32);
-	memcpy(ob_bin + 52, work->data + 64, 12);
+	swab256(ob_bin, work->midstate);
+	bswap_96p(&ob_bin[0x34], &work->data[0x40]);
 	if (!(memcmp(&ob_bin[56], "\xff\xff\xff\xff", 4)
 	if (!(memcmp(&ob_bin[56], "\xff\xff\xff\xff", 4)
 	   || memcmp(&ob_bin, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 32))) {
 	   || memcmp(&ob_bin, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 32))) {
 		// This sequence is used on cairnsmore bitstreams for commands, NEVER send it otherwise
 		// This sequence is used on cairnsmore bitstreams for commands, NEVER send it otherwise
@@ -753,8 +764,6 @@ bool icarus_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused
 		       icarus->proc_repr);
 		       icarus->proc_repr);
 		ob_bin[56] = 0;
 		ob_bin[56] = 0;
 	}
 	}
-	rev(ob_bin, 32);
-	rev(ob_bin + 52, 12);
 	
 	
 	return true;
 	return true;
 }
 }
@@ -846,7 +855,7 @@ void handle_identify(struct thr_info * const thr, int ret, const bool was_first_
 			{
 			{
 				memcpy(&nonce, nonce_bin, sizeof(nonce));
 				memcpy(&nonce, nonce_bin, sizeof(nonce));
 				nonce = icarus_nonce32toh(info, nonce);
 				nonce = icarus_nonce32toh(info, nonce);
-				submit_nonce(thr, state->last_work, nonce);
+				submit_nonce(icarus_thread_for_nonce(icarus, nonce), state->last_work, nonce);
 			}
 			}
 		}
 		}
 	}
 	}
@@ -908,7 +917,6 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	double Hs, W, fullnonce;
 	double Hs, W, fullnonce;
 	int read_count;
 	int read_count;
 	bool limited;
 	bool limited;
-	int64_t estimate_hashes;
 	uint32_t values;
 	uint32_t values;
 	int64_t hash_count_range;
 	int64_t hash_count_range;
 
 
@@ -992,7 +1000,7 @@ keepwaiting:
 			if (nonce_work == state->last2_work)
 			if (nonce_work == state->last2_work)
 			{
 			{
 				// nonce was for the last job; submit and keep processing the current one
 				// nonce was for the last job; submit and keep processing the current one
-				submit_nonce(thr, nonce_work, nonce);
+				submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
 				goto keepwaiting;
 				goto keepwaiting;
 			}
 			}
 			if (info->continue_search)
 			if (info->continue_search)
@@ -1000,7 +1008,7 @@ keepwaiting:
 				read_count = info->read_count - ((timer_elapsed_us(&state->tv_workstart, NULL) / (1000000 / TIME_FACTOR)) + 1);
 				read_count = info->read_count - ((timer_elapsed_us(&state->tv_workstart, NULL) / (1000000 / TIME_FACTOR)) + 1);
 				if (read_count)
 				if (read_count)
 				{
 				{
-					submit_nonce(thr, nonce_work, nonce);
+					submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
 					goto keepwaiting;
 					goto keepwaiting;
 				}
 				}
 			}
 			}
@@ -1052,46 +1060,57 @@ keepwaiting:
 
 
 	// OK, done starting Icarus's next job... now process the last run's result!
 	// OK, done starting Icarus's next job... now process the last run's result!
 
 
-	// aborted before becoming idle, get new work
-	if (ret == ICA_GETS_TIMEOUT || ret == ICA_GETS_RESTART) {
+	if (ret == ICA_GETS_OK && !was_hw_error)
+	{
+		submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
+		
 		icarus_transition_work(state, work);
 		icarus_transition_work(state, work);
-		// ONLY up to just when it aborted
-		// We didn't read a reply so we don't subtract ICARUS_READ_TIME
-		estimate_hashes = ((double)(elapsed.tv_sec)
-					+ ((double)(elapsed.tv_usec))/((double)1000000)) / info->Hs;
+		
+		hash_count = (nonce & info->nonce_mask);
+		hash_count++;
+		hash_count *= info->fpga_count;
+
+		applog(LOG_DEBUG, "%"PRIpreprv" nonce = 0x%08x = 0x%08" PRIx64 " hashes (%"PRId64".%06lus)",
+		       icarus->proc_repr,
+		       nonce,
+		       (uint64_t)hash_count,
+		       (int64_t)elapsed.tv_sec, (unsigned long)elapsed.tv_usec);
+	}
+	else
+	{
+		double estimate_hashes = elapsed.tv_sec;
+		estimate_hashes += ((double)elapsed.tv_usec) / 1000000.;
+		
+		if (ret == ICA_GETS_OK)
+		{
+			// We can't be sure which processor got the error, but at least this is a decent guess
+			inc_hw_errors(icarus_thread_for_nonce(icarus, nonce), state->last_work, nonce);
+			estimate_hashes -= ICARUS_READ_TIME(info->baud, info->read_size);
+		}
+		
+		icarus_transition_work(state, work);
+		
+		estimate_hashes /= info->Hs;
 
 
 		// If some Serial-USB delay allowed the full nonce range to
 		// If some Serial-USB delay allowed the full nonce range to
 		// complete it can't have done more than a full nonce
 		// complete it can't have done more than a full nonce
 		if (unlikely(estimate_hashes > 0xffffffff))
 		if (unlikely(estimate_hashes > 0xffffffff))
 			estimate_hashes = 0xffffffff;
 			estimate_hashes = 0xffffffff;
 
 
-		applog(LOG_DEBUG, "%"PRIpreprv" no nonce = 0x%08"PRIx64" hashes (%"PRId64".%06lus)",
+		applog(LOG_DEBUG, "%"PRIpreprv" %s nonce = 0x%08"PRIx64" hashes (%"PRId64".%06lus)",
 		       icarus->proc_repr,
 		       icarus->proc_repr,
+		       (ret == ICA_GETS_OK) ? "bad" : "no",
 		       (uint64_t)estimate_hashes,
 		       (uint64_t)estimate_hashes,
 		       (int64_t)elapsed.tv_sec, (unsigned long)elapsed.tv_usec);
 		       (int64_t)elapsed.tv_sec, (unsigned long)elapsed.tv_usec);
 
 
 		hash_count = estimate_hashes;
 		hash_count = estimate_hashes;
-		goto out;
+		
+		if (ret != ICA_GETS_OK)
+			goto out;
 	}
 	}
 
 
 	// Only ICA_GETS_OK gets here
 	// Only ICA_GETS_OK gets here
 	
 	
-	if (likely(!was_hw_error))
-		submit_nonce(thr, nonce_work, nonce);
-	else
-		inc_hw_errors(thr, state->last_work, nonce);
-	icarus_transition_work(state, work);
-
-	hash_count = (nonce & info->nonce_mask);
-	hash_count++;
-	hash_count *= info->fpga_count;
-
-	applog(LOG_DEBUG, "%"PRIpreprv" nonce = 0x%08x = 0x%08" PRIx64 " hashes (%"PRId64".%06lus)",
-	       icarus->proc_repr,
-	       nonce,
-	       (uint64_t)hash_count,
-	       (int64_t)elapsed.tv_sec, (unsigned long)elapsed.tv_usec);
-
 	if (info->do_default_detection && elapsed.tv_sec >= DEFAULT_DETECT_THRESHOLD) {
 	if (info->do_default_detection && elapsed.tv_sec >= DEFAULT_DETECT_THRESHOLD) {
 		int MHs = (double)hash_count / ((double)elapsed.tv_sec * 1e6 + (double)elapsed.tv_usec);
 		int MHs = (double)hash_count / ((double)elapsed.tv_sec * 1e6 + (double)elapsed.tv_usec);
 		--info->do_default_detection;
 		--info->do_default_detection;
@@ -1235,6 +1254,18 @@ out:
 	if (unlikely(state->identify))
 	if (unlikely(state->identify))
 		handle_identify(thr, ret, was_first_run);
 		handle_identify(thr, ret, was_first_run);
 	
 	
+	int hash_count_per_proc = hash_count / icarus->procs;
+	if (hash_count_per_proc > 0)
+	{
+		for_each_managed_proc(proc, icarus)
+		{
+			struct thr_info * const proc_thr = proc->thr[0];
+			
+			hashes_done2(proc_thr, hash_count_per_proc, NULL);
+			hash_count -= hash_count_per_proc;
+		}
+	}
+	
 	return hash_count;
 	return hash_count;
 }
 }
 
 
@@ -1296,8 +1327,8 @@ const char *icarus_set_work_division(struct cgpu_info * const proc, const char *
 {
 {
 	struct ICARUS_INFO * const info = proc->device_data;
 	struct ICARUS_INFO * const info = proc->device_data;
 	const int work_division = atoi(newvalue);
 	const int work_division = atoi(newvalue);
-	if (!(work_division == 1 || work_division == 2 || work_division == 4 || work_division == 8))
-		return "Invalid work_division: must be 1, 2, 4 or 8";
+	if (!is_power_of_two(work_division))
+		return "Invalid work_division: must be a power of two";
 	if (info->user_set & IUS_FPGA_COUNT)
 	if (info->user_set & IUS_FPGA_COUNT)
 	{
 	{
 		if (info->fpga_count > work_division)
 		if (info->fpga_count > work_division)
@@ -1316,7 +1347,7 @@ const char *icarus_set_fpga_count(struct cgpu_info * const proc, const char * co
 {
 {
 	struct ICARUS_INFO * const info = proc->device_data;
 	struct ICARUS_INFO * const info = proc->device_data;
 	const int fpga_count = atoi(newvalue);
 	const int fpga_count = atoi(newvalue);
-	if (fpga_count < 1 || fpga_count > info->work_division)
+	if (fpga_count < 1 || (fpga_count > info->work_division && info->work_division))
 		return "Invalid fpga_count: must be >0 and <=work_division";
 		return "Invalid fpga_count: must be >0 and <=work_division";
 	info->fpga_count = fpga_count;
 	info->fpga_count = fpga_count;
 	return NULL;
 	return NULL;
@@ -1360,6 +1391,14 @@ const struct bfg_set_device_definition icarus_set_device_funcs[] = {
 	{NULL},
 	{NULL},
 };
 };
 
 
+const struct bfg_set_device_definition icarus_set_device_funcs_live[] = {
+	{"baud"         , icarus_set_baud         , "serial baud rate"},
+	{"work_division", icarus_set_work_division, "number of pieces work is split into"},
+	{"reopen"       , icarus_set_reopen       , "how often to reopen device: never, timeout, cycle, (or now for a one-shot reopen)"},
+	{"timing"       , icarus_set_timing       , "timing of device; see README.FPGA"},
+	{NULL},
+};
+
 struct device_drv icarus_drv = {
 struct device_drv icarus_drv = {
 	.dname = "icarus",
 	.dname = "icarus",
 	.name = "ICA",
 	.name = "ICA",

+ 23 - 3
driver-icarus.h

@@ -1,5 +1,6 @@
 /*
 /*
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2014 Luke Dashjr
+ * Copyright 2014 Nate Woolls
  * Copyright 2012 Xiangfu
  * Copyright 2012 Xiangfu
  * Copyright 2012 Andrew Smith
  * Copyright 2012 Andrew Smith
  *
  *
@@ -70,13 +71,16 @@ struct ICARUS_INFO {
 	// time to calculate the golden_ob
 	// time to calculate the golden_ob
 	struct timeval golden_tv;
 	struct timeval golden_tv;
 
 
+	// History structures for calculating read_count
+	// when info->do_icarus_timing is true
 	struct ICARUS_HISTORY history[INFO_HISTORY+1];
 	struct ICARUS_HISTORY history[INFO_HISTORY+1];
 	uint32_t min_data_count;
 	uint32_t min_data_count;
 
 
-	// seconds per Hash
-	double Hs;
+	// Timeout scanning for a nonce (deciseconds)
 	int read_count;
 	int read_count;
+	// Timeout scanning for a golden nonce (deciseconds)
 	int probe_read_count;
 	int probe_read_count;
+	
 	// ds limit for (short=/long=) read_count
 	// ds limit for (short=/long=) read_count
 	int read_count_limit;
 	int read_count_limit;
 
 
@@ -97,9 +101,16 @@ struct ICARUS_INFO {
 
 
 	// icarus-options
 	// icarus-options
 	int baud;
 	int baud;
+	
+	// Used to calculate / display hash count when nonce is NOT found
+	// seconds per Hash
+	double Hs;
+	
+	// Used to calculate / display hash count when a nonce is found
 	int work_division;
 	int work_division;
 	int fpga_count;
 	int fpga_count;
 	uint32_t nonce_mask;
 	uint32_t nonce_mask;
+	
 	enum icarus_reopen_mode reopen_mode;
 	enum icarus_reopen_mode reopen_mode;
 	bool reopen_now;
 	bool reopen_now;
 	uint8_t user_set;
 	uint8_t user_set;
@@ -111,14 +122,23 @@ struct ICARUS_INFO {
 	// Bytes to read from Icarus for nonce
 	// Bytes to read from Icarus for nonce
 	int read_size;
 	int read_size;
 	
 	
+	// Settings used when probing / detecting
 	size_t ob_size;
 	size_t ob_size;
 	const char *golden_ob;
 	const char *golden_ob;
 	const char *golden_nonce;
 	const char *golden_nonce;
 	bool nonce_littleendian;
 	bool nonce_littleendian;
+	// Don't check the golden nonce returned when probing
+	bool ignore_golden_nonce;
 	
 	
 	// 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 *);
+	
+#ifdef USE_ZEUSMINER
+	// Hardware information, doesn't affect anything directly
+	uint16_t freq;
+	uint16_t chips;
+#endif
 };
 };
 
 
 struct icarus_state {
 struct icarus_state {

+ 248 - 0
driver-jingtian.c

@@ -0,0 +1,248 @@
+/*
+ * Copyright 2014 Luke Dashjr
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+
+#include "deviceapi.h"
+#include "driver-aan.h"
+#include "logging.h"
+#include "lowl-spi.h"
+#include "util.h"
+
+static const int jingtian_cs_gpio[] = {14, 15, 18};
+static const int jingtian_spi_disable_gpio = 25;
+static const int jingtian_reset_gpio = 3;
+static const int jingtian_max_cs = 1 << (sizeof(jingtian_cs_gpio) / sizeof(*jingtian_cs_gpio));
+static const uint8_t jingtian_pre_header[] = {0xb5, 0xb5};
+
+#define JINGTIAN_REGISTER_EXTRA_SIZE  2
+
+BFG_REGISTER_DRIVER(jingtian_drv)
+
+static
+bool jingtian_spi_txrx(struct spi_port * const port)
+{
+	if (*port->chipselect_current != port->chipselect)
+	{
+		unsigned cs_set_low = 0, cs_set_high = 0, cur_cs_bit;
+		bool bit_desired;
+		for (int i = 0; i < sizeof(jingtian_cs_gpio) / sizeof(*jingtian_cs_gpio); ++i)
+		{
+			cur_cs_bit = (1 << i);
+			bit_desired = (port->chipselect & cur_cs_bit);
+			if (bit_desired == (bool)(*port->chipselect_current & cur_cs_bit))
+				// No change needed
+				continue;
+			if (bit_desired)
+				cs_set_high |= (1 << jingtian_cs_gpio[i]);
+			else
+				cs_set_low  |= (1 << jingtian_cs_gpio[i]);
+		}
+		bfg_gpio_set_high(1 << jingtian_spi_disable_gpio);
+		if (cs_set_low)
+			bfg_gpio_set_low(cs_set_low);
+		if (cs_set_high)
+			bfg_gpio_set_high(cs_set_high);
+		bfg_gpio_set_low(1 << jingtian_spi_disable_gpio);
+		if (opt_dev_protocol)
+			applog(LOG_DEBUG, "%s(%p): CS %d", __func__, port, port->chipselect);
+		*port->chipselect_current = port->chipselect;
+	}
+	if (opt_dev_protocol)
+	{
+		char x[(spi_getbufsz(port) * 2) + 1];
+		bin2hex(x, spi_gettxbuf(port), spi_getbufsz(port));
+		applog(LOG_DEBUG, "%s(%p): %cX %s", __func__, port, 'T', x);
+	}
+	bool rv = linux_spi_txrx(port);
+	if (opt_dev_protocol)
+	{
+		char x[(spi_getbufsz(port) * 2) + 1];
+		bin2hex(x, spi_getrxbuf(port), spi_getbufsz(port));
+		applog(LOG_DEBUG, "%s(%p): %cX %s", __func__, port, 'R', x);
+	}
+	return rv;
+}
+
+static
+void jingtian_precmd(struct spi_port * const spi)
+{
+	spi_emit_buf(spi, jingtian_pre_header, sizeof(jingtian_pre_header));
+}
+
+static
+bool jingtian_read_reg(struct spi_port * const spi, const uint8_t chip, void * const out_buf, const struct timeval * const tvp_timeout)
+{
+	if (!aan_read_reg_direct(spi, chip, out_buf, tvp_timeout))
+		return false;
+	
+	spi_emit_nop(spi, JINGTIAN_REGISTER_EXTRA_SIZE);
+	if (!spi_txrx(spi))
+		applogr(false, LOG_DEBUG, "%s: %s failed", __func__, "spi_txrx");
+	
+	struct cgpu_info * const dev = spi->cgpu;
+	if (unlikely(!dev))
+		return true;
+	struct cgpu_info * const proc = aan_proc_for_chipid(dev, chip);
+	
+	uint8_t * const rx = spi_getrxbuf(spi);
+	proc->temp = upk_u16be(rx, 0);
+	
+	return true;
+}
+
+static
+struct aan_hooks jingtian_hooks = {
+	.precmd = jingtian_precmd,
+	.read_reg = jingtian_read_reg,
+};
+
+static
+void jingtian_common_init(void)
+{
+	RUNONCE();
+	spi_init();
+	for (int i = 0; i < sizeof(jingtian_cs_gpio) / sizeof(*jingtian_cs_gpio); ++i)
+		bfg_gpio_setpin_output(jingtian_cs_gpio[i]);
+	bfg_gpio_setpin_output(jingtian_spi_disable_gpio);
+	bfg_gpio_set_high(1 << jingtian_spi_disable_gpio);
+	
+	bfg_gpio_setpin_output(jingtian_reset_gpio);
+	bfg_gpio_set_high(1 << jingtian_reset_gpio);
+	cgsleep_ms(200);
+	bfg_gpio_set_low(1 << jingtian_reset_gpio);
+}
+
+static
+bool jingtian_detect_one(const char * const devpath)
+{
+	int found = 0, chips;
+	
+	jingtian_common_init();
+	
+	struct spi_port spi_cfg;
+	memset(&spi_cfg, 0, sizeof(spi_cfg));
+	spi_cfg.speed = 4000000;
+	spi_cfg.delay = 0;
+	spi_cfg.mode = SPI_MODE_1;
+	spi_cfg.bits = 8;
+	if (spi_open(&spi_cfg, devpath) < 0)
+		applogr(false, LOG_DEBUG, "%s: Failed to open %s", jingtian_drv.dname, devpath);
+	
+	struct cgpu_info *cgpu, *prev_cgpu = NULL;
+	struct spi_port *spi;
+	int * const chipselect_current = malloc(sizeof(*spi->chipselect_current));
+	*chipselect_current = -1;
+	
+	int devpath_len = strlen(devpath);
+	
+	int chipcount[jingtian_max_cs];
+	struct spi_port *spi_a[jingtian_max_cs];
+	for (int i = 0; i < jingtian_max_cs; ++i)
+	{
+		spi = spi_a[i] = calloc(sizeof(*spi), 1);
+		memcpy(spi, &spi_cfg, sizeof(*spi));
+		spi->repr = malloc(devpath_len + 0x10);
+		sprintf((void*)spi->repr, "%s(cs%d)", devpath, i);
+		spi->txrx = jingtian_spi_txrx;
+		spi->userp = &jingtian_hooks;
+		spi->chipselect = i;
+		spi->chipselect_current = chipselect_current;
+	}
+	
+	aan_detect_spi(chipcount, spi_a, jingtian_max_cs);
+	
+	for (int i = 0; i < jingtian_max_cs; ++i)
+	{
+		chips = chipcount[i];
+		free((void*)spi_a[i]->repr);
+		spi_a[i]->repr = NULL;
+		if (chips <= 0)
+		{
+			free(spi_a[i]);
+			continue;
+		}
+		cgpu = malloc(sizeof(*cgpu));
+		*cgpu = (struct cgpu_info){
+			.drv = &jingtian_drv,
+			.procs = chips,
+			.threads = prev_cgpu ? 0 : 1,
+			.device_data = spi_a[i],
+			.device_path = strdup(devpath),
+			.set_device_funcs = aan_set_device_funcs,
+		};
+		spi_a[i]->cgpu = cgpu;
+		add_cgpu_slave(cgpu, prev_cgpu);
+		prev_cgpu = cgpu;
+		found += chips;
+	}
+	
+	close(spi_cfg.fd);
+	if (!found)
+		free(chipselect_current);
+	return found;
+}
+
+static
+int jingtian_detect_auto(void)
+{
+	return jingtian_detect_one("/dev/spidev0.0") ? 1 : 0;
+}
+
+static
+void jingtian_detect(void)
+{
+	generic_detect(&jingtian_drv, jingtian_detect_one, jingtian_detect_auto, GDF_REQUIRE_DNAME | GDF_DEFAULT_NOAUTO);
+}
+
+static
+bool jingtian_init(struct thr_info * const master_thr)
+{
+	struct cgpu_info * const master_dev = master_thr->cgpu;
+	const char * const devpath = master_dev->device_path;
+	const int fd = open(devpath, O_RDWR);
+	if (fd < 0)
+		applogr(false, LOG_ERR, "%s: Failed to open %s", master_dev->dev_repr, devpath);
+	
+	for_each_managed_proc(proc, master_dev)
+	{
+		struct spi_port * const spi = proc->device_data;
+		spi->fd = fd;
+	}
+	
+	return aan_init(master_thr);
+}
+
+struct device_drv jingtian_drv = {
+	.dname = "jingtian",
+	.name = "JTN",
+	.drv_detect = jingtian_detect,
+	
+	.thread_init = jingtian_init,
+	
+	.minerloop = minerloop_queue,
+	.queue_append = aan_queue_append,
+	.queue_flush = aan_queue_flush,
+	.poll = aan_poll,
+	
+	.get_api_extra_device_status = aan_api_device_status,
+};

+ 17 - 1
driver-klondike.c

@@ -3,6 +3,7 @@
  * Copyright 2013 Andrew Smith
  * Copyright 2013 Andrew Smith
  * Copyright 2013 Con Kolivas
  * Copyright 2013 Con Kolivas
  * Copyright 2013 Chris Savery
  * Copyright 2013 Chris Savery
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -697,6 +698,19 @@ static void kln_disable(struct cgpu_info *klncgpu, int dev, bool all)
 	}
 	}
 }
 }
 
 
+static
+void klondike_zero_stats(struct cgpu_info * const proc)
+{
+	struct klondike_info * const klninfo = proc->device_data;
+	
+	for (int devn = klninfo->status[0].kline.ws.slavecount; devn >= 0; --devn)
+		for (int i = klninfo->status[devn].kline.ws.chipcount * 2; --i >= 0; )
+			klninfo->devinfo[devn].chipstats[i] = 0;
+	klninfo->hashcount = klninfo->errorcount = klninfo->noisecount = 0;
+	klninfo->delay_count = klninfo->delay_total = klninfo->delay_min = klninfo->delay_max = 0;
+	klninfo->nonce_count = klninfo->nonce_total = klninfo->nonce_min = klninfo->nonce_max = 0;
+}
+
 static bool klondike_init(struct cgpu_info *klncgpu)
 static bool klondike_init(struct cgpu_info *klncgpu)
 {
 {
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
@@ -851,6 +865,7 @@ bool klondike_lowl_probe_custom(const struct lowlevel_device_info * const info,
 {
 {
 	if (unlikely(info->lowl != &lowl_usb))
 	if (unlikely(info->lowl != &lowl_usb))
 	{
 	{
+		bfg_probe_result_flags = BPR_WRONG_DEVTYPE;
 		applog(LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not usb!",
 		applog(LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not usb!",
 		       __func__, info->product, info->serial);
 		       __func__, info->product, info->serial);
 		goto err;
 		goto err;
@@ -1686,7 +1701,7 @@ static struct api_data *klondike_api_stats(struct cgpu_info *klncgpu)
 }
 }
 
 
 struct device_drv klondike_drv = {
 struct device_drv klondike_drv = {
-	.dname = "Klondike",
+	.dname = "klondike",
 	.name = "KLN",
 	.name = "KLN",
 	.lowl_match = klondike_lowl_match,
 	.lowl_match = klondike_lowl_match,
 	.lowl_probe = klondike_lowl_probe,
 	.lowl_probe = klondike_lowl_probe,
@@ -1701,6 +1716,7 @@ struct device_drv klondike_drv = {
 	.thread_shutdown = klondike_shutdown,
 	.thread_shutdown = klondike_shutdown,
 	.thread_enable = klondike_thread_enable,
 	.thread_enable = klondike_thread_enable,
 	
 	
+	.zero_stats = klondike_zero_stats,
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 	.proc_wlogprint_status = klondike_wlogprint_status,
 	.proc_wlogprint_status = klondike_wlogprint_status,
 #endif
 #endif

+ 8 - 33
driver-knc.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -31,6 +31,7 @@
 #include "logging.h"
 #include "logging.h"
 #include "lowl-spi.h"
 #include "lowl-spi.h"
 #include "miner.h"
 #include "miner.h"
+#include "util.h"
 
 
 #define KNC_POLL_INTERVAL_US 10000
 #define KNC_POLL_INTERVAL_US 10000
 #define KNC_SPI_SPEED 3000000
 #define KNC_SPI_SPEED 3000000
@@ -213,23 +214,7 @@ fail:
 	return false;
 	return false;
 }
 }
 
 
-static
-bool knc_spi_txrx(struct spi_port * const spi)
-{
-	const void * const wrbuf = spi_gettxbuf(spi);
-	void * const rdbuf = spi_getrxbuf(spi);
-	const size_t bufsz = spi_getbufsz(spi);
-	const int fd = spi->fd;
-	struct spi_ioc_transfer xf = {
-		.tx_buf = (uintptr_t) wrbuf,
-		.rx_buf = (uintptr_t) rdbuf,
-		.len = bufsz,
-		.delay_usecs = spi->delay,
-		.speed_hz = spi->speed,
-		.bits_per_word = spi->bits,
-	};
-	return (ioctl(fd, SPI_IOC_MESSAGE(1), &xf) > 0);
-}
+#define knc_spi_txrx  linux_spi_txrx
 
 
 static
 static
 void knc_clean_flush(struct spi_port * const spi)
 void knc_clean_flush(struct spi_port * const spi)
@@ -597,7 +582,7 @@ void knc_poll(struct thr_info * const thr)
 			--knc->workqueue_size;
 			--knc->workqueue_size;
 			DL_DELETE(knc->workqueue, work);
 			DL_DELETE(knc->workqueue, work);
 			work->device_id = knc->next_id++ & 0x7fff;
 			work->device_id = knc->next_id++ & 0x7fff;
-			HASH_ADD_INT(knc->devicework, device_id, work);
+			HASH_ADD(hh, knc->devicework, device_id, sizeof(work->device_id), work);
 			if (!--workaccept)
 			if (!--workaccept)
 				break;
 				break;
 		}
 		}
@@ -825,21 +810,11 @@ const char *knc_set_use_dcdc(struct cgpu_info *proc, const char * const optname,
 {
 {
 	int core_index_on_die = proc->proc_id % KNC_CORES_PER_DIE;
 	int core_index_on_die = proc->proc_id % KNC_CORES_PER_DIE;
 	bool nv;
 	bool nv;
+	char *end;
 	
 	
-	if (!(strcasecmp(newvalue, "no") && strcasecmp(newvalue, "false") && strcasecmp(newvalue, "0") && strcasecmp(newvalue, "off") && strcasecmp(newvalue, "disable")))
-		nv = false;
-	else
-	if (!(strcasecmp(newvalue, "yes") && strcasecmp(newvalue, "true") && strcasecmp(newvalue, "on") && strcasecmp(newvalue, "enable")))
-		nv = true;
-	else
-	{
-		char *p;
-		strtol(newvalue, &p, 0);
-		if (newvalue[0] && !p[0])
-			nv = true;
-		else
-			return "Usage: use_dcdc=yes/no";
-	}
+	nv = bfg_strtobool(newvalue, &end, 0);
+	if (!(newvalue[0] && !end[0]))
+		return "Usage: use_dcdc=yes/no";
 	
 	
 	if (core_index_on_die)
 	if (core_index_on_die)
 	{
 	{

+ 8 - 59
driver-littlefury.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -38,57 +38,6 @@ enum littlefury_opcode {
 
 
 BFG_REGISTER_DRIVER(littlefury_drv)
 BFG_REGISTER_DRIVER(littlefury_drv)
 
 
-static uint16_t crc16tab[] = {
-	0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
-	0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
-	0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
-	0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
-	0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
-	0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
-	0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
-	0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
-	0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
-	0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
-	0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
-	0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
-	0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
-	0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
-	0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
-	0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
-	0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
-	0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
-	0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
-	0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
-	0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
-	0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
-	0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
-	0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
-	0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
-	0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
-	0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
-	0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
-	0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
-	0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
-	0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
-	0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0,
-};
-
-static
-uint16_t crc16_floating(uint16_t next_byte, uint16_t seed)
-{
-	return ((seed << 8) ^ crc16tab[(seed >> 8) ^ next_byte]) & 0xFFFF;
-}
-
-static
-uint16_t crc16(void *p, size_t sz)
-{
-	const uint8_t * const s = p;
-	uint16_t crc = 0xFFFF;
-	for (size_t i = 0; i < sz; ++i)
-		crc = crc16_floating(s[i], crc);
-	return crc;
-}
-
 static
 static
 ssize_t keep_reading(int prio, int fd, void *buf, size_t count)
 ssize_t keep_reading(int prio, int fd, void *buf, size_t count)
 {
 {
@@ -128,7 +77,7 @@ bool bitfury_do_packet(int prio, const char *repr, const int fd, void * const bu
 		pkt[4] = payloadsz & 0xff;
 		pkt[4] = payloadsz & 0xff;
 		if (payloadsz)
 		if (payloadsz)
 			memcpy(&pkt[5], payload, payloadsz);
 			memcpy(&pkt[5], payload, payloadsz);
-		crc = crc16(&pkt[2], 3 + (size_t)payloadsz);
+		crc = crc16ffff(&pkt[2], 3 + (size_t)payloadsz);
 		pkt[sz - 2] = crc >> 8;
 		pkt[sz - 2] = crc >> 8;
 		pkt[sz - 1] = crc & 0xff;
 		pkt[sz - 1] = crc & 0xff;
 		if (unlikely(opt_dev_protocol))
 		if (unlikely(opt_dev_protocol))
@@ -167,7 +116,7 @@ bool bitfury_do_packet(int prio, const char *repr, const int fd, void * const bu
 			return false;
 			return false;
 		}
 		}
 		crc = (pkt[sz + 3] << 8) | pkt[sz + 4];
 		crc = (pkt[sz + 3] << 8) | pkt[sz + 4];
-		b = (crc != crc16(&pkt[2], sz + 1));
+		b = (crc != crc16ffff(&pkt[2], sz + 1));
 		if (unlikely(opt_dev_protocol || b))
 		if (unlikely(opt_dev_protocol || b))
 		{
 		{
 			char hex[((sz + 5) * 2) + 1];
 			char hex[((sz + 5) * 2) + 1];
@@ -270,7 +219,7 @@ bool littlefury_detect_one(const char *devpath)
 	uint8_t buf[255];
 	uint8_t buf[255];
 	uint16_t bufsz;
 	uint16_t bufsz;
 	struct cgpu_info dummy;
 	struct cgpu_info dummy;
-	char *devname;
+	char *devname = NULL;
 	
 	
 	fd = serial_open(devpath, 0, 10, true);
 	fd = serial_open(devpath, 0, 10, true);
 	applog(LOG_DEBUG, "%s: %s %s",
 	applog(LOG_DEBUG, "%s: %s %s",
@@ -309,7 +258,6 @@ bool littlefury_detect_one(const char *devpath)
 	if (!chips) {
 	if (!chips) {
 		applog(LOG_WARNING, "%s: No Bitfury chips detected on %s",
 		applog(LOG_WARNING, "%s: No Bitfury chips detected on %s",
 		       littlefury_drv.dname, devpath);
 		       littlefury_drv.dname, devpath);
-		free(devname);
 		goto err;
 		goto err;
 	} else {
 	} else {
 		applog(LOG_DEBUG, "%s: %d chips detected",
 		applog(LOG_DEBUG, "%s: %d chips detected",
@@ -318,10 +266,10 @@ bool littlefury_detect_one(const char *devpath)
 	
 	
 	littlefury_set_power(LOG_DEBUG, littlefury_drv.dname, fd, false);
 	littlefury_set_power(LOG_DEBUG, littlefury_drv.dname, fd, false);
 	
 	
-	serial_close(fd);
-	
 	if (serial_claim_v(devpath, &littlefury_drv))
 	if (serial_claim_v(devpath, &littlefury_drv))
-		return false;
+		goto err;
+	
+	serial_close(fd);
 	
 	
 	struct cgpu_info *cgpu;
 	struct cgpu_info *cgpu;
 	cgpu = malloc(sizeof(*cgpu));
 	cgpu = malloc(sizeof(*cgpu));
@@ -343,6 +291,7 @@ bool littlefury_detect_one(const char *devpath)
 err:
 err:
 	if (fd != -1)
 	if (fd != -1)
 		serial_close(fd);
 		serial_close(fd);
+	free(devname);
 	return false;
 	return false;
 }
 }
 
 

+ 483 - 0
driver-minergate.c

@@ -0,0 +1,483 @@
+/*
+ * Copyright 2014 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.
+ *
+ * To avoid doubt: Programs using the minergate protocol to interface with
+ * BFGMiner are considered part of the Corresponding Source, and not an
+ * independent work. This means that such programs distrbuted with BFGMiner
+ * must be released under the terms of the GPLv3 license, or sufficiently
+ * compatible terms.
+ */
+
+#include "config.h"
+
+#include <ctype.h>
+#include <math.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/epoll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "deviceapi.h"
+#include "logging.h"
+#include "lowlevel.h"
+#include "miner.h"
+
+#define MINERGATE_MAX_NONCE_DIFF  0x20
+
+static const char * const minergate_stats_file = "/var/run/mg_rate_temp";
+
+#define MINERGATE_PROTOCOL_VER  6
+#define MINERGATE_MAGIC  0xcaf4
+static const int minergate_max_responses = 300;
+#define MINERGATE_PKT_HEADER_SZ       8
+#define MINERGATE_PKT_REQ_ITEM_SZ  0x34
+#define MINERGATE_PKT_REQ_MAX     100
+#define MINERGATE_PKT_RSP_ITEM_SZ  0x14
+#define MINERGATE_PKT_RSP_MAX     300
+#define MINERGATE_POLL_US      100000
+#define MINERGATE_RETRY_US    5000000
+
+#define MINERGATE_PKT_REQ_SZ  (MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_REQ_ITEM_SZ * MINERGATE_PKT_REQ_MAX))
+#define MINERGATE_PKT_RSP_SZ  (MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_RSP_ITEM_SZ * MINERGATE_PKT_RSP_MAX))
+
+BFG_REGISTER_DRIVER(minergate_drv)
+
+enum minergate_reqpkt_flags {
+	MRPF_FIRST = 1,
+	MRPF_FLUSH = 2,
+};
+
+struct minergate_state {
+	work_device_id_t next_jobid;
+	unsigned ready_to_queue;
+	uint8_t *req_buffer;
+	long *stats;
+	unsigned stats_count;
+	struct work *flushed_work;
+};
+
+static
+int minergate_open(const char * const devpath)
+{
+	size_t devpath_len = strlen(devpath);
+	struct sockaddr_un sa = {
+		.sun_family = AF_UNIX,
+	};
+#ifdef UNIX_PATH_MAX
+	if (devpath_len >= UNIX_PATH_MAX)
+#else
+	if (devpath_len >= sizeof(sa.sun_path))
+#endif
+		return -1;
+	const int fd = socket(PF_UNIX, SOCK_STREAM, 0);
+	strcpy(sa.sun_path, devpath);
+	if (connect(fd, &sa, sizeof(sa)))
+	{
+		close(fd);
+		return -1;
+	}
+	return fd;
+}
+
+static
+ssize_t minergate_read(const int fd, void * const buf_p, size_t bufLen)
+{
+	uint8_t *buf = buf_p;
+	ssize_t rv, ret = 0;
+	while (bufLen > 0)
+	{
+		rv = read(fd, buf, bufLen);
+		if (rv <= 0)
+		{
+			if (ret > 0)
+				return ret;
+			return rv;
+		}
+		buf += rv;
+		bufLen -= rv;
+		ret += rv;
+	}
+	return ret;
+}
+
+static
+bool minergate_detect_one(const char * const devpath)
+{
+	bool rv = false;
+	const int fd = minergate_open(devpath);
+	if (unlikely(fd < 0))
+		applogr(false, LOG_DEBUG, "%s: %s: Cannot connect", minergate_drv.dname, devpath);
+	
+	int epfd = -1;
+	uint8_t buf[MINERGATE_PKT_REQ_SZ] = {0xbf, 0x90, MINERGATE_PROTOCOL_VER, MRPF_FIRST, 0,0, 0 /* req count */,};
+	pk_u16le(buf, 4, MINERGATE_MAGIC);
+	if (MINERGATE_PKT_REQ_SZ != write(fd, buf, MINERGATE_PKT_REQ_SZ))
+		return_via_applog(out, , LOG_DEBUG, "%s: %s: write incomplete or failed", minergate_drv.dname, devpath);
+	
+	epfd = epoll_create(1);
+	if (epfd < 0)
+		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s failed", minergate_drv.dname, devpath, "epoll_create");
+	
+	struct epoll_event eev;
+	eev.events = EPOLLIN;
+	if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &eev))
+		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s failed", minergate_drv.dname, devpath, "epoll_ctl");
+	
+	size_t read_bytes = 0;
+	static const size_t read_expect = MINERGATE_PKT_HEADER_SZ;
+	ssize_t r;
+	while (read_bytes < read_expect)
+	{
+		if (epoll_wait(epfd, &eev, 1, 1000) != 1)
+			return_via_applog(out, , LOG_DEBUG, "%s: %s: Timeout waiting for response", minergate_drv.dname, devpath);
+		r = read(fd, &buf[read_bytes], read_expect - read_bytes);
+		if (r <= 0)
+			return_via_applog(out, , LOG_DEBUG, "%s: %s: %s failed", minergate_drv.dname, devpath, "read");
+		read_bytes += r;
+	}
+	
+	if (buf[1] != 0x90)
+		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "request_id");
+	if (buf[2] != MINERGATE_PROTOCOL_VER)
+		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "Protocol version");
+	if (upk_u16le(buf, 4) != MINERGATE_MAGIC)
+		return_via_applog(out, , LOG_DEBUG, "%s: %s: %s mismatch", minergate_drv.dname, devpath, "magic");
+	
+	uint16_t responses = upk_u16le(buf, 6);
+	if (responses > minergate_max_responses)
+		return_via_applog(out, , LOG_DEBUG, "%s: %s: More than maximum responses", minergate_drv.dname, devpath);
+	
+	if (bfg_claim_any2(&minergate_drv, devpath, "unix", devpath))
+		goto out;
+	
+	struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
+	*cgpu = (struct cgpu_info){
+		.drv = &minergate_drv,
+		.device_path = strdup(devpath),
+		.deven = DEV_ENABLED,
+		.threads = 1,
+	};
+	rv = add_cgpu(cgpu);
+	
+out:
+	close(fd);
+	if (epfd >= 0)
+		close(epfd);
+	return rv;
+}
+
+static
+int minergate_detect_auto(void)
+{
+	return minergate_detect_one("/tmp/connection_pipe") ? 1 : 0;
+}
+
+static
+void minergate_detect(void)
+{
+	generic_detect(&minergate_drv, minergate_detect_one, minergate_detect_auto, 0);
+}
+
+static
+bool minergate_init(struct thr_info * const thr)
+{
+	struct cgpu_info * const dev = thr->cgpu;
+	
+	const int fd = minergate_open(dev->device_path);
+	dev->device_fd = fd;
+	if (fd < 0)
+		applogr(false, LOG_ERR, "%s: Cannot connect", dev->dev_repr);
+	
+	struct minergate_state * const state = malloc(sizeof(*state) + MINERGATE_PKT_REQ_SZ);
+	if (!state)
+		applogr(false, LOG_ERR, "%s: %s failed", dev->dev_repr, "malloc");
+	*state = (struct minergate_state){
+		.req_buffer = (void*)&state[1]
+	};
+	thr->cgpu_data = state;
+	thr->work = thr->work_list = NULL;
+	
+	mutex_init(&dev->device_mutex);
+	memset(state->req_buffer, 0, MINERGATE_PKT_REQ_SZ);
+	pk_u8(state->req_buffer, 2, MINERGATE_PROTOCOL_VER);
+	state->req_buffer[3] = MRPF_FIRST | MRPF_FLUSH;
+	pk_u16le(state->req_buffer, 4, MINERGATE_MAGIC);
+	timer_set_delay_from_now(&thr->tv_poll, 0);
+	
+	return true;
+}
+
+static
+bool minergate_queue_full(struct thr_info * const thr)
+{
+	static const unsigned max_minergate_jobs = 300, max_requests = 100;
+	struct minergate_state * const state = thr->cgpu_data;
+	bool qf;
+	
+	if (HASH_COUNT(thr->work) + state->ready_to_queue >= max_minergate_jobs)
+		qf = true;
+	else
+	if (state->ready_to_queue >= max_requests)
+		qf = true;
+	else
+	if (state->req_buffer[3] & MRPF_FLUSH)
+		// Job flush occurs after new jobs get queued, so we have to wait until it completes
+		qf = true;
+	else
+		qf = false;
+	
+	thr->queue_full = qf;
+	return qf;
+}
+
+static
+bool minergate_queue_append(struct thr_info * const thr, struct work * const work)
+{
+	struct cgpu_info * const dev = thr->cgpu;
+	struct minergate_state * const state = thr->cgpu_data;
+	
+	if (minergate_queue_full(thr))
+		return false;
+	
+	work->device_id = (uint32_t)(state->next_jobid++);
+	work->tv_stamp.tv_sec = 0;
+	
+	uint8_t * const my_buf = &state->req_buffer[MINERGATE_PKT_HEADER_SZ + (MINERGATE_PKT_REQ_ITEM_SZ * state->ready_to_queue++)];
+	pk_u32be(my_buf,  0, work->device_id);
+	memcpy(&my_buf[   4], &work->data[0x48], 4);  // nbits
+	memcpy(&my_buf[   8], &work->data[0x44], 4);  // ntime
+	memcpy(&my_buf[0x0c], &work->data[0x40], 4);  // merkle-tail
+	memcpy(&my_buf[0x10], work->midstate, 0x20);
+	
+	if (work->work_difficulty >= MINERGATE_MAX_NONCE_DIFF)
+		work->nonce_diff = MINERGATE_MAX_NONCE_DIFF;
+	else
+		work->nonce_diff = work->work_difficulty;
+	const uint16_t zerobits = log2(floor(work->nonce_diff * 4294967296));
+	work->nonce_diff = pow(2, zerobits) / 4294967296;
+	pk_u8(my_buf, 0x30, zerobits);
+	
+	pk_u8(my_buf, 0x31,    0);  // ntime limit
+	pk_u8(my_buf, 0x32,    0);  // ntime offset
+	pk_u8(my_buf, 0x33,    0);  // reserved
+	
+	struct work *oldwork;
+	HASH_FIND(hh, thr->work, &work->device_id, sizeof(work->device_id), oldwork);
+	if (unlikely(oldwork))
+	{
+		applog(LOG_WARNING, "%s: Reusing allocated device id %"PRIwdi, dev->dev_repr, work->device_id);
+		HASH_DEL(thr->work, oldwork);
+		free_work(oldwork);
+	}
+	HASH_ADD(hh, thr->work, device_id, sizeof(work->device_id), work);
+	LL_PREPEND(thr->work_list, work);
+	timer_set_delay_from_now(&thr->tv_poll, 0);
+	minergate_queue_full(thr);
+	
+	return true;
+}
+
+static
+void minergate_queue_flush(struct thr_info * const thr)
+{
+	struct minergate_state * const state = thr->cgpu_data;
+	struct work *work, *worktmp;
+	
+	// Flush internal ready-to-queue list
+	LL_FOREACH_SAFE(thr->work_list, work, worktmp)
+	{
+		HASH_DEL(thr->work, work);
+		LL_DELETE(thr->work_list, work);
+		free_work(work);
+	}
+	state->ready_to_queue = 0;
+	
+	// Trigger minergate flush
+	state->req_buffer[3] |= MRPF_FLUSH;
+	
+	timer_set_delay_from_now(&thr->tv_poll, 0);
+}
+
+static
+void minergate_poll(struct thr_info * const thr)
+{
+	struct cgpu_info * const dev = thr->cgpu;
+	struct minergate_state * const state = thr->cgpu_data;
+	const int fd = dev->device_fd;
+	
+	if (opt_dev_protocol || state->ready_to_queue)
+		applog(LOG_DEBUG, "%s: Polling with %u new jobs", dev->dev_repr, state->ready_to_queue);
+	pk_u16le(state->req_buffer, 6, state->ready_to_queue);
+	if (MINERGATE_PKT_REQ_SZ != write(fd, state->req_buffer, MINERGATE_PKT_REQ_SZ))
+		return_via_applog(err, , LOG_ERR, "%s: write incomplete or failed", dev->dev_repr);
+	
+	uint8_t flags = state->req_buffer[3];
+	state->req_buffer[3] = 0;
+	state->ready_to_queue = 0;
+	thr->work_list = NULL;
+	
+	uint8_t buf[MINERGATE_PKT_RSP_SZ];
+	if (minergate_read(fd, buf, MINERGATE_PKT_RSP_SZ) != MINERGATE_PKT_RSP_SZ)
+		return_via_applog(err, , LOG_ERR, "%s: %s failed", dev->dev_repr, "read");
+	
+	if (upk_u8(buf, 2) != MINERGATE_PROTOCOL_VER || upk_u16le(buf, 4) != MINERGATE_MAGIC)
+		return_via_applog(err, , LOG_ERR, "%s: Protocol mismatch", dev->dev_repr);
+	
+	uint8_t *jobrsp = &buf[MINERGATE_PKT_HEADER_SZ];
+	struct work *work;
+	uint16_t rsp_count = upk_u16le(buf, 6);
+	if (rsp_count || opt_dev_protocol)
+		applog(LOG_DEBUG, "%s: Received %u job completions", dev->dev_repr, rsp_count);
+	uint32_t nonce;
+	int64_t hashes = 0;
+	for (unsigned i = 0; i < rsp_count; ++i, (jobrsp += MINERGATE_PKT_RSP_ITEM_SZ))
+	{
+		work_device_id_t jobid = upk_u32be(jobrsp, 0);
+		nonce = upk_u32le(jobrsp, 8);
+		HASH_FIND(hh, thr->work, &jobid, sizeof(jobid), work);
+		if (!work)
+		{
+			applog(LOG_ERR, "%s: Unknown job %"PRIwdi, dev->dev_repr, jobid);
+			if (nonce)
+			{
+				inc_hw_errors3(thr, NULL, &nonce, 1.);
+				nonce = upk_u32le(jobrsp, 0xc);
+				if (nonce)
+					inc_hw_errors3(thr, NULL, &nonce, 1.);
+			}
+			else
+				inc_hw_errors_only(thr);
+			continue;
+		}
+		if (nonce)
+		{
+			submit_nonce(thr, work, nonce);
+			
+			nonce = upk_u32be(jobrsp, 0xc);
+			if (nonce)
+				submit_nonce(thr, work, nonce);
+		}
+		
+		HASH_DEL(thr->work, work);
+		applog(LOG_DEBUG, "%s: %s job %"PRIwdi" completed", dev->dev_repr, work->tv_stamp.tv_sec ? "Flushed" : "Active", work->device_id);
+		if (!work->tv_stamp.tv_sec)
+			hashes += 100000000 * work->nonce_diff;
+		free_work(work);
+	}
+	hashes_done2(thr, hashes, NULL);
+	
+	if (flags & MRPF_FLUSH)
+	{
+		// Mark all remaining jobs as flushed so we don't count them in hashes_done
+		struct work *worktmp;
+		HASH_ITER(hh, thr->work, work, worktmp)
+		{
+			work->tv_stamp.tv_sec = 1;
+		}
+	}
+	
+	minergate_queue_full(thr);
+	timer_set_delay_from_now(&thr->tv_poll, MINERGATE_POLL_US);
+	return;
+
+err:
+	// TODO: reconnect
+	timer_set_delay_from_now(&thr->tv_poll, MINERGATE_RETRY_US);
+}
+
+static
+bool minergate_get_stats(struct cgpu_info * const dev)
+{
+	static const int skip_stats = 1;
+	struct thr_info * const thr = dev->thr[0];
+	struct minergate_state * const state = thr->cgpu_data;
+	
+	FILE *F = fopen(minergate_stats_file, "r");
+	char buf[0x100];
+	if (F)
+	{
+		char *p = fgets(buf, sizeof(buf), F);
+		fclose(F);
+		if (p)
+		{
+			long nums[0x80];
+			char *endptr;
+			unsigned i;
+			float max_temp = 0;
+			for (i = 0; 1; ++i)
+			{
+				if (!p[0])
+					break;
+				nums[i] = strtol(p, &endptr, 0);
+				if (p == endptr)
+					break;
+				if (i >= skip_stats && nums[i] > max_temp)
+					max_temp = nums[i];
+				while (endptr[0] && !isspace(endptr[0]))
+					++endptr;
+				while (endptr[0] && isspace(endptr[0]))
+					++endptr;
+				p = endptr;
+			}
+			i -= skip_stats;
+			long *new_stats = malloc(sizeof(*state->stats) * i);
+			memcpy(new_stats, &nums[skip_stats], sizeof(*nums) * i);
+			mutex_lock(&dev->device_mutex);
+			free(state->stats);
+			state->stats = new_stats;
+			state->stats_count = i;
+			mutex_unlock(&dev->device_mutex);
+			dev->temp = max_temp;
+		}
+	}
+	
+	return true;
+}
+
+static
+struct api_data *minergate_api_extra_device_status(struct cgpu_info * const dev)
+{
+	struct thr_info * const thr = dev->thr[0];
+	struct minergate_state * const state = thr->cgpu_data;
+	struct api_data *root = NULL;
+	
+	mutex_lock(&dev->device_mutex);
+	if (state->stats_count > 1)
+	{
+		char buf[0x10];
+		for (unsigned i = 0; i < state->stats_count; ++i)
+		{
+			float temp = state->stats[i];
+			if (!temp)
+				continue;
+			sprintf(buf, "Temperature%u", i);
+			root = api_add_temp(root, buf, &temp, true);
+		}
+	}
+	mutex_unlock(&dev->device_mutex);
+	
+	return root;
+}
+
+struct device_drv minergate_drv = {
+	.dname = "minergate",
+	.name = "MGT",
+	.drv_detect = minergate_detect,
+	
+	.thread_init = minergate_init,
+	.minerloop = minerloop_queue,
+	
+	.queue_append = minergate_queue_append,
+	.queue_flush = minergate_queue_flush,
+	.poll = minergate_poll,
+	
+	.get_stats = minergate_get_stats,
+	.get_api_extra_device_status = minergate_api_extra_device_status,
+};

+ 56 - 22
driver-nanofury.c

@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
- * Copyright 2013 Vladimir Strinski
+ * Copyright 2013-2014 Luke Dashjr
+ * Copyright 2013-2014 Vladimir Strinski
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -42,6 +42,7 @@ struct nanofury_state {
 	unsigned long current_baud;
 	unsigned long current_baud;
 	bool ledalternating;
 	bool ledalternating;
 	bool ledvalue;
 	bool ledvalue;
+	bool powered_off;
 };
 };
 
 
 // Bit-banging reset, to reset more chips in chain - toggle for longer period... Each 3 reset cycles reset first chip in chain
 // Bit-banging reset, to reset more chips in chain - toggle for longer period... Each 3 reset cycles reset first chip in chain
@@ -66,7 +67,7 @@ bool nanofury_spi_reset(struct mcp2210_device * const mcp)
 	return true;
 	return true;
 }
 }
 
 
-static void nanofury_device_off(struct mcp2210_device *);
+static void nanofury_device_off(struct mcp2210_device *, struct nanofury_state *);
 
 
 static
 static
 bool nanofury_spi_txrx(struct spi_port * const port)
 bool nanofury_spi_txrx(struct spi_port * const port)
@@ -113,7 +114,7 @@ bool nanofury_spi_txrx(struct spi_port * const port)
 
 
 err:
 err:
 	mcp2210_spi_cancel(mcp);
 	mcp2210_spi_cancel(mcp);
-	nanofury_device_off(mcp);
+	nanofury_device_off(mcp, state);
 	if (cgpu)
 	if (cgpu)
 	{
 	{
 		struct thr_info * const thr = cgpu->thr[0];
 		struct thr_info * const thr = cgpu->thr[0];
@@ -137,15 +138,17 @@ void nanofury_do_led_alternating(struct nanofury_state * const state)
 }
 }
 
 
 static
 static
-void nanofury_device_off(struct mcp2210_device * const mcp)
+void nanofury_device_off(struct mcp2210_device * const mcp, struct nanofury_state * const state)
 {
 {
 	// Try to reset everything back to input
 	// Try to reset everything back to input
 	for (int i = 0; i < 9; ++i)
 	for (int i = 0; i < 9; ++i)
 		mcp2210_get_gpio_input(mcp, i);
 		mcp2210_get_gpio_input(mcp, i);
+	if (state)
+		state->powered_off = true;
 }
 }
 
 
 static
 static
-bool nanofury_power_enable(struct mcp2210_device * const mcp, const bool poweron)
+bool nanofury_power_enable(struct mcp2210_device * const mcp, const bool poweron, struct nanofury_state * const state)
 {
 {
 	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_PWR_EN, poweron ? BGV_HIGH : BGV_LOW))
 	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_PWR_EN, poweron ? BGV_HIGH : BGV_LOW))
 		return false;
 		return false;
@@ -153,11 +156,14 @@ bool nanofury_power_enable(struct mcp2210_device * const mcp, const bool poweron
 	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_PWR_EN0, poweron ? BGV_LOW : BGV_HIGH))
 	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_PWR_EN0, poweron ? BGV_LOW : BGV_HIGH))
 		return false;
 		return false;
 	
 	
+	if (state)
+		state->powered_off = !poweron;
+	
 	return true;
 	return true;
 }
 }
 
 
 static
 static
-bool nanofury_checkport(struct mcp2210_device * const mcp, const unsigned long baud)
+bool nanofury_checkport(struct mcp2210_device * const mcp, const unsigned long baud, struct nanofury_state * const state)
 {
 {
 	int i;
 	int i;
 	const char tmp = 0;
 	const char tmp = 0;
@@ -174,7 +180,7 @@ bool nanofury_checkport(struct mcp2210_device * const mcp, const unsigned long b
 	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_LED, BGV_HIGH))
 	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_LED, BGV_HIGH))
 		goto fail;
 		goto fail;
 	
 	
-	nanofury_power_enable(mcp, true);
+	nanofury_power_enable(mcp, true, state);
 	
 	
 	// cancel any outstanding SPI transfers
 	// cancel any outstanding SPI transfers
 	mcp2210_spi_cancel(mcp);
 	mcp2210_spi_cancel(mcp);
@@ -217,7 +223,7 @@ bool nanofury_checkport(struct mcp2210_device * const mcp, const unsigned long b
 	return true;
 	return true;
 
 
 fail:
 fail:
-	nanofury_device_off(mcp);
+	nanofury_device_off(mcp, state);
 	return false;
 	return false;
 }
 }
 
 
@@ -239,6 +245,7 @@ bool nanofury_lowl_probe(const struct lowlevel_device_info * const info)
 	
 	
 	if (info->lowl != &lowl_mcp2210)
 	if (info->lowl != &lowl_mcp2210)
 	{
 	{
+		bfg_probe_result_flags = BPR_WRONG_DEVTYPE;
 		if (info->lowl != &lowl_hid && info->lowl != &lowl_usb)
 		if (info->lowl != &lowl_hid && info->lowl != &lowl_usb)
 			applog(LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not mcp2210!",
 			applog(LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not mcp2210!",
 			       __func__, product, serial);
 			       __func__, product, serial);
@@ -272,7 +279,7 @@ bool nanofury_lowl_probe(const struct lowlevel_device_info * const info)
 		drv_set_defaults(&nanofury_drv, bitfury_set_device_funcs_probe, &dummy_bitfury, NULL, NULL, 1);
 		drv_set_defaults(&nanofury_drv, bitfury_set_device_funcs_probe, &dummy_bitfury, NULL, NULL, 1);
 	}
 	}
 	
 	
-	if (!nanofury_checkport(mcp, port->speed))
+	if (!nanofury_checkport(mcp, port->speed, NULL))
 	{
 	{
 		applog(LOG_WARNING, "%s: Matched \"%s\" serial \"%s\", but failed to detect nanofury",
 		applog(LOG_WARNING, "%s: Matched \"%s\" serial \"%s\", but failed to detect nanofury",
 		       __func__, product, serial);
 		       __func__, product, serial);
@@ -284,7 +291,7 @@ bool nanofury_lowl_probe(const struct lowlevel_device_info * const info)
 	chips = libbitfury_detectChips1(port);
 	chips = libbitfury_detectChips1(port);
 	free(port);
 	free(port);
 	
 	
-	nanofury_device_off(mcp);
+	nanofury_device_off(mcp, NULL);
 	mcp2210_close(mcp);
 	mcp2210_close(mcp);
 	
 	
 	if (lowlevel_claim(&nanofury_drv, true, info))
 	if (lowlevel_claim(&nanofury_drv, true, info))
@@ -332,7 +339,7 @@ bool nanofury_init(struct thr_info * const thr)
 		applog(LOG_ERR, "%"PRIpreprv": Failed to open mcp2210 device", cgpu->proc_repr);
 		applog(LOG_ERR, "%"PRIpreprv": Failed to open mcp2210 device", cgpu->proc_repr);
 		return false;
 		return false;
 	}
 	}
-	if (!nanofury_checkport(mcp, state->current_baud))
+	if (!nanofury_checkport(mcp, state->current_baud, state))
 	{
 	{
 		applog(LOG_ERR, "%"PRIpreprv": checkport failed", cgpu->proc_repr);
 		applog(LOG_ERR, "%"PRIpreprv": checkport failed", cgpu->proc_repr);
 		mcp2210_close(mcp);
 		mcp2210_close(mcp);
@@ -360,6 +367,10 @@ bool nanofury_init(struct thr_info * const thr)
 	port->logprio = LOG_ERR;
 	port->logprio = LOG_ERR;
 	port->speed = state->current_baud;
 	port->speed = state->current_baud;
 		
 		
+	
+	const int init_osc6_bits = 50;
+	const int ramp_osc6_bits = (cgpu->procs > 1) ? 5 : init_osc6_bits;
+	
 	state->mcp = mcp;
 	state->mcp = mcp;
 	port->userp = state;
 	port->userp = state;
 	for (proc = cgpu; proc; (proc = proc->next_proc), ++bitfury)
 	for (proc = cgpu; proc; (proc = proc->next_proc), ++bitfury)
@@ -371,12 +382,13 @@ bool nanofury_init(struct thr_info * const thr)
 		};
 		};
 		proc->device_data = bitfury;
 		proc->device_data = bitfury;
 		mythr->cgpu_data = state;
 		mythr->cgpu_data = state;
-		bitfury->osc6_bits = 5;
+		bitfury->osc6_bits = ramp_osc6_bits;
 		bitfury_send_reinit(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
 		bitfury_send_reinit(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
 		bitfury_init_chip(proc);
 		bitfury_init_chip(proc);
 	}
 	}
 	
 	
-	while (bitfury->osc6_bits < 50)
+	--bitfury;
+	while (bitfury->osc6_bits < init_osc6_bits)
 	{
 	{
 		for (proc = cgpu; proc; proc = proc->next_proc)
 		for (proc = cgpu; proc; proc = proc->next_proc)
 		{
 		{
@@ -400,34 +412,56 @@ bool nanofury_init(struct thr_info * const thr)
 static
 static
 void nanofury_disable(struct thr_info * const thr)
 void nanofury_disable(struct thr_info * const thr)
 {
 {
+	struct cgpu_info * const proc = thr->cgpu;
+	struct cgpu_info * const dev = proc->device;
 	struct nanofury_state * const state = thr->cgpu_data;
 	struct nanofury_state * const state = thr->cgpu_data;
 	struct mcp2210_device * const mcp = state->mcp;
 	struct mcp2210_device * const mcp = state->mcp;
 	
 	
 	bitfury_disable(thr);
 	bitfury_disable(thr);
-	nanofury_device_off(mcp);
+	
+	// Before powering off, ensure no other chip needs power
+	for_each_managed_proc(oproc, dev)
+		if (oproc->deven == DEV_ENABLED)
+			return;
+	
+	applog(LOG_NOTICE, "%s: Last chip disabled, shutting off power",
+	       dev->dev_repr);
+	nanofury_device_off(mcp, state);
 }
 }
 
 
 static
 static
 void nanofury_enable(struct thr_info * const thr)
 void nanofury_enable(struct thr_info * const thr)
 {
 {
+	struct cgpu_info * const proc = thr->cgpu;
+	struct cgpu_info * const dev = proc->device;
 	struct nanofury_state * const state = thr->cgpu_data;
 	struct nanofury_state * const state = thr->cgpu_data;
 	struct mcp2210_device * const mcp = state->mcp;
 	struct mcp2210_device * const mcp = state->mcp;
 	
 	
-	nanofury_checkport(mcp, state->current_baud);
-	nanofury_send_led_gpio(state);
+	if (state->powered_off)
+	{
+		// All chips were disabled, so we need to power back on
+		applog(LOG_DEBUG, "%s: Enabling power",
+		       dev->dev_repr);
+		nanofury_checkport(mcp, state->current_baud, state);
+		nanofury_send_led_gpio(state);
+	}
+	
 	bitfury_enable(thr);
 	bitfury_enable(thr);
 }
 }
 
 
 static
 static
-void nanofury_reinit(struct cgpu_info * const cgpu)
+void nanofury_reinit(struct cgpu_info * const proc)
 {
 {
-	struct thr_info * const thr = cgpu->thr[0];
+	struct thr_info * const thr = proc->thr[0];
+	struct cgpu_info * const dev = proc->device;
 	struct nanofury_state * const state = thr->cgpu_data;
 	struct nanofury_state * const state = thr->cgpu_data;
 	struct mcp2210_device * const mcp = state->mcp;
 	struct mcp2210_device * const mcp = state->mcp;
 	
 	
-	nanofury_device_off(mcp);
+	nanofury_device_off(mcp, state);
 	cgsleep_ms(1);
 	cgsleep_ms(1);
-	nanofury_enable(thr);
+	for_each_managed_proc(oproc, dev)
+		if (oproc->deven == DEV_ENABLED)
+			nanofury_enable(oproc->thr[0]);
 }
 }
 
 
 static
 static
@@ -486,7 +520,7 @@ void nanofury_shutdown(struct thr_info * const thr)
 	struct mcp2210_device * const mcp = state->mcp;
 	struct mcp2210_device * const mcp = state->mcp;
 	
 	
 	if (mcp)
 	if (mcp)
-		nanofury_device_off(mcp);
+		nanofury_device_off(mcp, state);
 }
 }
 
 
 const char *nanofury_set_ledmode(struct cgpu_info * const proc, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
 const char *nanofury_set_ledmode(struct cgpu_info * const proc, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)

+ 9 - 7
driver-opencl.c

@@ -1,6 +1,7 @@
 /*
 /*
- * Copyright 2011-2012 Con Kolivas
- * Copyright 2011-2013 Luke Dashjr
+ * Copyright 2011-2013 Con Kolivas
+ * Copyright 2011-2014 Luke Dashjr
+ * Copyright 2014 Nate Woolls
  * Copyright 2010 Jeff Garzik
  * Copyright 2010 Jeff Garzik
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
@@ -432,9 +433,12 @@ static
 const char *opencl_init_binary(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
 const char *opencl_init_binary(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 opencl_device_data * const data = proc->device_data;
 	struct opencl_device_data * const data = proc->device_data;
+	char *end;
+	bool nv;
 	
 	
-	if (!(strcasecmp(newvalue, "no") && strcasecmp(newvalue, "never") && strcasecmp(newvalue, "none")))
-		data->opt_opencl_binaries = OBU_NONE;
+	nv = bfg_strtobool(newvalue, &end, 0);
+	if (newvalue[0] && !end[0])
+		data->opt_opencl_binaries = nv ? OBU_LOADSAVE : OBU_NONE;
 	else
 	else
 	if (!(strcasecmp(newvalue, "load") && strcasecmp(newvalue, "read")))
 	if (!(strcasecmp(newvalue, "load") && strcasecmp(newvalue, "read")))
 		data->opt_opencl_binaries = OBU_LOAD;
 		data->opt_opencl_binaries = OBU_LOAD;
@@ -442,7 +446,7 @@ const char *opencl_init_binary(struct cgpu_info * const proc, const char * const
 	if (!(strcasecmp(newvalue, "save") && strcasecmp(newvalue, "write")))
 	if (!(strcasecmp(newvalue, "save") && strcasecmp(newvalue, "write")))
 		data->opt_opencl_binaries = OBU_SAVE;
 		data->opt_opencl_binaries = OBU_SAVE;
 	else
 	else
-	if (!(strcasecmp(newvalue, "yes") && strcasecmp(newvalue, "always") && strcasecmp(newvalue, "both")))
+	if (!(strcasecmp(newvalue, "both")))
 		data->opt_opencl_binaries = OBU_LOADSAVE;
 		data->opt_opencl_binaries = OBU_LOADSAVE;
 	else
 	else
 	if (!(strcasecmp(newvalue, "default")))
 	if (!(strcasecmp(newvalue, "default")))
@@ -1608,8 +1612,6 @@ static bool opencl_thread_prepare(struct thr_info *thr)
 	}
 	}
 	if (!cgpu->name)
 	if (!cgpu->name)
 		cgpu->name = trimmed_strdup(name);
 		cgpu->name = trimmed_strdup(name);
-	if (!cgpu->kname)
-		cgpu->kname = opencl_get_kernel_interface_name(clStates[i]->chosen_kernel);
 	applog(LOG_INFO, "initCl() finished. Found %s", name);
 	applog(LOG_INFO, "initCl() finished. Found %s", name);
 	get_now_datestamp(cgpu->init, sizeof(cgpu->init));
 	get_now_datestamp(cgpu->init, sizeof(cgpu->init));
 
 

+ 28 - 1
driver-proxy.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -21,6 +21,7 @@
 #include "util.h"
 #include "util.h"
 
 
 BFG_REGISTER_DRIVER(proxy_drv)
 BFG_REGISTER_DRIVER(proxy_drv)
+static const struct bfg_set_device_definition proxy_set_device_funcs[];
 
 
 static
 static
 struct proxy_client *proxy_clients;
 struct proxy_client *proxy_clients;
@@ -94,6 +95,7 @@ struct proxy_client *proxy_find_or_create_client(const char *username)
 		client = malloc(sizeof(*client));
 		client = malloc(sizeof(*client));
 		*cgpu = (struct cgpu_info){
 		*cgpu = (struct cgpu_info){
 			.drv = &proxy_drv,
 			.drv = &proxy_drv,
+			.set_device_funcs = proxy_set_device_funcs,
 			.threads = 0,
 			.threads = 0,
 			.device_data = client,
 			.device_data = client,
 			.device_path = user,
 			.device_path = user,
@@ -110,6 +112,7 @@ struct proxy_client *proxy_find_or_create_client(const char *username)
 		*client = (struct proxy_client){
 		*client = (struct proxy_client){
 			.username = user,
 			.username = user,
 			.cgpu = cgpu,
 			.cgpu = cgpu,
+			.desired_share_pdiff = opt_scrypt ? (1./0x10000) : 1.,
 		};
 		};
 		
 		
 		b = HASH_COUNT(proxy_clients);
 		b = HASH_COUNT(proxy_clients);
@@ -118,6 +121,8 @@ struct proxy_client *proxy_find_or_create_client(const char *username)
 		
 		
 		if (!b)
 		if (!b)
 			proxy_first_client(cgpu);
 			proxy_first_client(cgpu);
+		
+		cgpu_set_defaults(cgpu);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -128,6 +133,23 @@ struct proxy_client *proxy_find_or_create_client(const char *username)
 	return client;
 	return client;
 }
 }
 
 
+static
+const char *proxy_set_diff(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	struct proxy_client * const client = proc->device_data;
+	const double nv = atof(newvalue);
+	if (nv <= 0)
+		return "Invalid difficulty";
+	
+	client->desired_share_pdiff = nv;
+	
+#ifdef USE_LIBEVENT
+	stratumsrv_client_changed_diff(client);
+#endif
+	
+	return NULL;
+}
+
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 static
 static
 void proxy_wlogprint_status(struct cgpu_info *cgpu)
 void proxy_wlogprint_status(struct cgpu_info *cgpu)
@@ -137,6 +159,11 @@ void proxy_wlogprint_status(struct cgpu_info *cgpu)
 }
 }
 #endif
 #endif
 
 
+static const struct bfg_set_device_definition proxy_set_device_funcs[] = {
+	{"diff", proxy_set_diff, "desired share difficulty for clients"},
+	{NULL},
+};
+
 struct device_drv proxy_drv = {
 struct device_drv proxy_drv = {
 	.dname = "proxy",
 	.dname = "proxy",
 	.name = "PXY",
 	.name = "PXY",

+ 15 - 0
driver-proxy.h

@@ -5,15 +5,30 @@
 
 
 #include "miner.h"
 #include "miner.h"
 
 
+#ifdef USE_LIBEVENT
+struct stratumsrv_conn_userlist;
+#endif
+
+extern struct device_drv proxy_drv;
+
 struct proxy_client {
 struct proxy_client {
 	char *username;
 	char *username;
 	struct cgpu_info *cgpu;
 	struct cgpu_info *cgpu;
 	struct work *work;
 	struct work *work;
 	struct timeval tv_hashes_done;
 	struct timeval tv_hashes_done;
+	float desired_share_pdiff;
+	
+#ifdef USE_LIBEVENT
+	struct stratumsrv_conn_userlist *stratumsrv_connlist;
+#endif
 	
 	
 	UT_hash_handle hh;
 	UT_hash_handle hh;
 };
 };
 
 
 extern struct proxy_client *proxy_find_or_create_client(const char *user);
 extern struct proxy_client *proxy_find_or_create_client(const char *user);
 
 
+#ifdef USE_LIBEVENT
+extern void stratumsrv_client_changed_diff(struct proxy_client *);
+#endif
+
 #endif
 #endif

+ 589 - 0
driver-rockminer.c

@@ -0,0 +1,589 @@
+/*
+ * Copyright 2014 Luke Dashjr
+ * Copyright 2014 Nate Woolls
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "deviceapi.h"
+#include "lowlevel.h"
+#include "lowl-vcom.h"
+#include "miner.h"
+
+#define ROCKMINER_MIN_FREQ_MHZ  200
+#define ROCKMINER_DEF_FREQ_MHZ  270
+#define ROCKMINER_MAX_SAFE_FREQ_MHZ  290
+#define ROCKMINER_MAX_FREQ_MHZ  2560
+#define ROCKMINER_POLL_US         0
+#define ROCKMINER_RETRY_US  5000000
+#define ROCKMINER_MIDTASK_TIMEOUT_US  500000
+#define ROCKMINER_MIDTASK_RETRY_US   1000000
+#define ROCKMINER_TASK_TIMEOUT_US    5273438
+#define ROCKMINER_IO_SPEED 115200
+#define ROCKMINER_READ_TIMEOUT 1 //deciseconds
+
+#define ROCKMINER_MAX_CHIPS  64
+#define ROCKMINER_WORK_REQ_SIZE  0x40
+#define ROCKMINER_REPLY_SIZE        8
+
+enum rockminer_replies {
+	ROCKMINER_REPLY_NONCE_FOUND = 0,
+	ROCKMINER_REPLY_TASK_COMPLETE = 1,
+	ROCKMINER_REPLY_GET_TASK = 2,
+};
+
+BFG_REGISTER_DRIVER(rockminer_drv)
+static const struct bfg_set_device_definition rockminer_set_device_funcs[];
+
+struct rockminer_chip_data {
+	uint8_t next_work_req[ROCKMINER_WORK_REQ_SIZE];
+	struct work *works[2];
+	uint8_t last_taskid;
+	struct timeval tv_midtask_timeout;
+	int requested_work;
+};
+
+static
+int rockminer_open(const char *devpath)
+{
+	return serial_open(devpath, ROCKMINER_IO_SPEED, ROCKMINER_READ_TIMEOUT, true);
+}
+
+static
+void rockminer_log_protocol(int fd, const void *buf, size_t bufLen, const char *prefix)
+{
+	char hex[(bufLen * 2) + 1];
+	bin2hex(hex, buf, bufLen);
+	applog(LOG_DEBUG, "%s fd=%d: DEVPROTO: %s %s", rockminer_drv.dname, fd, prefix, hex);
+}
+
+static
+int rockminer_read(int fd, void *buf, size_t bufLen)
+{
+	int result = read(fd, buf, bufLen);
+	
+	if (result < 0)
+		applog(LOG_ERR, "%s: %s fd %d", rockminer_drv.dname, "Failed to read", fd);
+	else if ((result > 0) && opt_dev_protocol && opt_debug)
+		rockminer_log_protocol(fd, buf, bufLen, "RECV");
+
+	return result;
+}
+
+static
+int rockminer_write(int fd, const void *buf, size_t bufLen)
+{
+	if (opt_dev_protocol && opt_debug)
+		rockminer_log_protocol(fd, buf, bufLen, "SEND");
+
+	return write(fd, buf, bufLen);
+}
+
+static
+void rockminer_job_buf_init(uint8_t * const buf, const uint8_t chipid)
+{
+	memset(&buf[0x20], 0, 0x10);
+	buf[0x30] = 0xaa;
+	// 0x31 is frequency, filled in elsewhere
+	buf[0x32] = chipid;
+	buf[0x33] = 0x55;
+}
+
+static
+void rockminer_job_buf_set_freq(uint8_t * const buf, const unsigned short freq)
+{
+	buf[0x31] = (freq / 10) - 1;
+}
+
+static
+bool rockminer_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_product(info, "R-BOX miner") || lowlevel_match_product(info, "RX-BOX miner");
+}
+
+static const uint8_t golden_midstate[] = {
+	0x4a, 0x54, 0x8f, 0xe4, 0x71, 0xfa, 0x3a, 0x9a,
+	0x13, 0x71, 0x14, 0x45, 0x56, 0xc3, 0xf6, 0x4d,
+	0x25, 0x00, 0xb4, 0x82, 0x60, 0x08, 0xfe, 0x4b,
+	0xbf, 0x76, 0x98, 0xc9, 0x4e, 0xba, 0x79, 0x46,
+};
+
+static const uint8_t golden_datatail[] = {
+	                        0xce, 0x22, 0xa7, 0x2f,
+	0x4f, 0x67, 0x26, 0x14, 0x1a, 0x0b, 0x32, 0x87,
+};
+
+static const uint8_t golden_result[] = {
+	0x00, 0x01, 0x87, 0xa2,
+};
+
+int8_t rockminer_bisect_chips(const int fd, uint8_t * const buf)
+{
+	static const int max_concurrent_tests = 4;
+	int concurrent_tests = max_concurrent_tests;
+	uint8_t tests[max_concurrent_tests];
+	uint8_t reply[ROCKMINER_REPLY_SIZE];
+	uint8_t minvalid = 0, maxvalid = ROCKMINER_MAX_CHIPS - 1;
+	uint8_t pertest;
+	char msg[0x10];
+	ssize_t rsz;
+	
+	do {
+		pertest = (maxvalid + 1 - minvalid) / concurrent_tests;
+		if (!pertest)
+			pertest = 1;
+		msg[0] = '\0';
+		for (int i = 0; i < concurrent_tests; ++i)
+		{
+			uint8_t chipid = (minvalid + pertest * (i + 1)) - 1;
+			if (chipid > maxvalid)
+			{
+				concurrent_tests = i;
+				break;
+			}
+			tests[i] = chipid;
+			
+			buf[0x32] = chipid;
+			if (rockminer_write(fd, buf, ROCKMINER_WORK_REQ_SIZE) != ROCKMINER_WORK_REQ_SIZE)
+				applogr(-1, LOG_DEBUG, "%s(%d): Error sending request for chip %d", __func__, fd, chipid);
+			
+			tailsprintf(msg, sizeof(msg), "%d ", chipid);
+		}
+		
+		msg[strlen(msg)-1] = '\0';
+		applog(LOG_DEBUG, "%s(%d): Testing chips %s (within range %d-%d)", __func__, fd, msg, minvalid, maxvalid);
+		
+		while ( (rsz = rockminer_read(fd, reply, sizeof(reply))) == sizeof(reply))
+		{
+			const uint8_t chipid = reply[5] & 0x3f;
+			if (chipid > minvalid)
+			{
+				applog(LOG_DEBUG, "%s(%d): Saw chip %d", __func__, fd, chipid);
+				minvalid = chipid;
+				if (minvalid >= tests[concurrent_tests-1])
+					break;
+			}
+		}
+		
+		for (int i = concurrent_tests; i--; )
+		{
+			if (tests[i] > minvalid)
+			{
+				applog(LOG_DEBUG, "%s(%d): Didn't see chip %d", __func__, fd, tests[i]);
+				maxvalid = tests[i] - 1;
+			}
+			else
+				break;
+		}
+	} while (minvalid != maxvalid);
+	
+	return maxvalid + 1;
+}
+
+static
+bool rockminer_detect_one(const char * const devpath)
+{
+	int fd, chips;
+	uint8_t buf[ROCKMINER_WORK_REQ_SIZE], reply[ROCKMINER_REPLY_SIZE];
+	ssize_t rsz;
+	
+	fd = rockminer_open(devpath);
+	if (fd < 0)
+		return_via_applog(err, , LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Failed to open", devpath);
+	
+	applog(LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Successfully opened", devpath);
+	
+	rockminer_job_buf_init(buf, 0);
+	rockminer_job_buf_set_freq(buf, ROCKMINER_MIN_FREQ_MHZ);
+	memcpy(&buf[   0], golden_midstate, 0x20);
+	memcpy(&buf[0x34], golden_datatail,  0xc);
+	
+	if (rockminer_write(fd, buf, sizeof(buf)) != sizeof(buf))
+		return_via_applog(err, , LOG_DEBUG, "%s: %s %s", rockminer_drv.dname, "Error sending request to ", devpath);
+	
+	while (true)
+	{
+		rsz = rockminer_read(fd, reply, sizeof(reply));
+		if (rsz != sizeof(reply))
+			return_via_applog(err, , LOG_DEBUG, "%s: Short read from %s (%d)", rockminer_drv.dname, devpath, rsz);
+		if ((!memcmp(reply, golden_result, sizeof(golden_result))) && (reply[4] & 0xf) == ROCKMINER_REPLY_NONCE_FOUND)
+			break;
+	}
+	
+	applog(LOG_DEBUG, "%s: Found chip 0 on %s, probing for total chip count", rockminer_drv.dname, devpath);
+	chips = rockminer_bisect_chips(fd, buf);
+	applog(LOG_DEBUG, "%s: Identified %d chips on %s", rockminer_drv.dname, chips, devpath);
+	
+	if (serial_claim_v(devpath, &rockminer_drv))
+		goto err;
+	
+	serial_close(fd);
+	
+	struct cgpu_info * const cgpu = malloc(sizeof(*cgpu));
+	*cgpu = (struct cgpu_info){
+		.drv = &rockminer_drv,
+		.set_device_funcs = rockminer_set_device_funcs,
+		.device_path = strdup(devpath),
+		.deven = DEV_ENABLED,
+		.procs = chips,
+		.threads = 1,
+	};
+	// NOTE: Xcode's clang has a bug where it cannot find fields inside anonymous unions (more details in fpgautils)
+	cgpu->device_fd = -1;
+	
+	return add_cgpu(cgpu);
+
+err:
+	if (fd >= 0)
+		serial_close(fd);
+	return false;
+}
+
+static
+bool rockminer_lowl_probe(const struct lowlevel_device_info * const info)
+{
+	return vcom_lowl_probe_wrapper(info, rockminer_detect_one);
+}
+
+static
+bool rockminer_init(struct thr_info * const master_thr)
+{
+	struct cgpu_info * const dev = master_thr->cgpu;
+	
+	for_each_managed_proc(proc, dev)
+	{
+		struct thr_info * const thr = proc->thr[0];
+		struct rockminer_chip_data * const chip = malloc(sizeof(*chip));
+		
+		thr->cgpu_data = chip;
+		*chip = (struct rockminer_chip_data){
+			.last_taskid = 0,
+		};
+		
+		rockminer_job_buf_init(chip->next_work_req, proc->proc_id);
+		rockminer_job_buf_set_freq(chip->next_work_req, ROCKMINER_DEF_FREQ_MHZ);
+	}
+	
+	timer_set_now(&master_thr->tv_poll);
+	
+	return true;
+}
+
+static
+void rockminer_dead(struct cgpu_info * const dev)
+{
+	serial_close(dev->device_fd);
+	dev->device_fd = -1;
+	for_each_managed_proc(proc, dev)
+	{
+		struct thr_info * const thr = proc->thr[0];
+		thr->queue_full = true;
+	}
+}
+
+static
+bool rockminer_send_work(struct thr_info * const thr)
+{
+	struct cgpu_info * const proc = thr->cgpu;
+	struct cgpu_info * const dev = proc->device;
+	struct rockminer_chip_data * const chip = thr->cgpu_data;
+	const int fd = dev->device_fd;
+	
+	return (rockminer_write(fd, chip->next_work_req, sizeof(chip->next_work_req)) == sizeof(chip->next_work_req));
+}
+
+static
+bool rockminer_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 rockminer_chip_data * const chip = thr->cgpu_data;
+	const int fd = dev->device_fd;
+	
+	if (fd < 0 || !chip->requested_work)
+	{
+		thr->queue_full = true;
+		return false;
+	}
+	
+	memcpy(&chip->next_work_req[   0], work->midstate, 0x20);
+	memcpy(&chip->next_work_req[0x34], &work->data[0x40], 0xc);
+	if (!rockminer_send_work(thr))
+	{
+		rockminer_dead(dev);
+		inc_hw_errors_only(thr);
+		applogr(false, LOG_ERR, "%"PRIpreprv": Failed to send work", proc->proc_repr);
+	}
+	
+	chip->last_taskid = chip->last_taskid ? 0 : 1;
+	if (chip->works[chip->last_taskid])
+		free_work(chip->works[chip->last_taskid]);
+	chip->works[chip->last_taskid] = work;
+	timer_set_delay_from_now(&chip->tv_midtask_timeout, ROCKMINER_MIDTASK_RETRY_US);
+	applog(LOG_DEBUG, "%"PRIpreprv": Work %d queued as task %d", proc->proc_repr, work->id, chip->last_taskid);
+	
+	if (!--chip->requested_work)
+		thr->queue_full = true;
+	
+	return true;
+}
+
+static
+void rockminer_queue_flush(__maybe_unused struct thr_info * const thr)
+{
+	
+}
+
+static
+void rockminer_poll(struct thr_info * const master_thr)
+{
+	struct cgpu_info * const dev = master_thr->cgpu;
+	int fd = dev->device_fd;
+	uint8_t reply[ROCKMINER_REPLY_SIZE];
+	ssize_t rsz;
+	
+	if (fd < 0)
+	{
+		fd = rockminer_open(dev->device_path);
+		if (fd < 0)
+		{
+			timer_set_delay_from_now(&master_thr->tv_poll, ROCKMINER_RETRY_US);
+			for_each_managed_proc(proc, dev)
+			{
+				struct thr_info * const thr = proc->thr[0];
+				inc_hw_errors_only(thr);
+			}
+			applogr(, LOG_ERR, "%s: Failed to open %s", dev->dev_repr, dev->device_path);
+		}
+		dev->device_fd = fd;
+		struct timeval tv_timeout;
+		timer_set_delay_from_now(&tv_timeout, ROCKMINER_TASK_TIMEOUT_US);
+		for_each_managed_proc(proc, dev)
+		{
+			struct thr_info * const thr = proc->thr[0];
+			struct rockminer_chip_data * const chip = thr->cgpu_data;
+			
+			chip->requested_work = 1;
+			thr->queue_full = false;
+			chip->tv_midtask_timeout = tv_timeout;
+		}
+	}
+	
+	while ( (rsz = rockminer_read(fd, reply, sizeof(reply))) == sizeof(reply))
+	{
+// 		const uint8_t status = reply[4] >> 4;
+		const enum rockminer_replies cmd = reply[4] & 0xf;
+// 		const uint8_t prodid = reply[5] >> 6;
+		const uint8_t chipid = reply[5] & 0x3f;
+		const uint8_t taskid = reply[6] & 1;
+		const uint8_t temp = reply[7];
+		struct cgpu_info * const proc = device_proc_by_id(dev, chipid);
+		if (unlikely(!proc))
+		{
+			for_each_managed_proc(proc, dev)
+			{
+				struct thr_info * const thr = proc->thr[0];
+				inc_hw_errors_only(thr);
+			}
+			applog(LOG_ERR, "%s: Chip id %d out of range", dev->dev_repr, chipid);
+			continue;
+		}
+		struct thr_info * const thr = proc->thr[0];
+		struct rockminer_chip_data * const chip = thr->cgpu_data;
+		
+		if (temp != 128)
+			proc->temp = temp;
+		
+		switch (cmd) {
+			case ROCKMINER_REPLY_NONCE_FOUND:
+			{
+				const uint32_t nonce = upk_u32be(reply, 0);
+				struct work *work;
+				if (chip->works[taskid] && test_nonce(chip->works[taskid], nonce, false))
+				{}
+				else
+				if (chip->works[taskid ? 0 : 1] && test_nonce(chip->works[taskid ? 0 : 1], nonce, false))
+				{
+					applog(LOG_DEBUG, "%"PRIpreprv": We have task ids inverted; fixing", proc->proc_repr);
+					work = chip->works[0];
+					chip->works[0] = chip->works[1];
+					chip->works[1] = work;
+					chip->last_taskid = chip->last_taskid ? 0 : 1;
+				}
+				work = chip->works[taskid];
+				submit_nonce(thr, work, nonce);
+				break;
+			}
+			case ROCKMINER_REPLY_TASK_COMPLETE:
+				applog(LOG_DEBUG, "%"PRIpreprv": Task %d completed", proc->proc_repr, taskid);
+				hashes_done2(thr, 0x100000000, NULL);
+				timer_set_delay_from_now(&chip->tv_midtask_timeout, ROCKMINER_MIDTASK_TIMEOUT_US);
+				break;
+			case ROCKMINER_REPLY_GET_TASK:
+				applog(LOG_DEBUG, "%"PRIpreprv": Task %d requested", proc->proc_repr, taskid);
+				thr->queue_full = false;
+				++chip->requested_work;
+				timer_set_delay_from_now(&chip->tv_midtask_timeout, ROCKMINER_TASK_TIMEOUT_US);
+				break;
+		}
+	}
+	if (rsz < 0)
+		rockminer_dead(dev);
+	
+	struct timeval tv_now;
+	timer_set_now(&tv_now);
+	for_each_managed_proc(proc, dev)
+	{
+		struct thr_info * const thr = proc->thr[0];
+		struct rockminer_chip_data * const chip = thr->cgpu_data;
+		
+		if (timer_passed(&chip->tv_midtask_timeout, &tv_now))
+		{
+			// A task completed, but no request followed
+			// This means it missed our last task send, so we need to resend it
+			applog(LOG_WARNING, "%"PRIpreprv": No task request? Probably lost, resending task %d", proc->proc_repr, chip->last_taskid);
+			inc_hw_errors_only(thr);
+			timer_set_delay(&chip->tv_midtask_timeout, &tv_now, ROCKMINER_MIDTASK_RETRY_US);
+			struct work *work;
+			if ((!(work = chip->works[chip->last_taskid])) || stale_work(work, false))
+			{
+				// Either no work was queued, or it was stale
+				// Instead of resending, just queue a new one
+				if (!chip->requested_work)
+					chip->requested_work = 1;
+				thr->queue_full = false;
+			}
+			else
+			if (!rockminer_send_work(thr))
+			{
+				rockminer_dead(dev);
+				timer_set_delay_from_now(&master_thr->tv_poll, ROCKMINER_RETRY_US);
+				inc_hw_errors_only(thr);
+				applogr(, LOG_ERR, "%"PRIpreprv": Failed to resend work", proc->proc_repr);
+			}
+		}
+	}
+	
+	timer_set_delay_from_now(&master_thr->tv_poll, ROCKMINER_POLL_US);
+}
+
+static
+const char *rockminer_set_clock(struct cgpu_info * const proc, const char * const optname, const char *newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	struct thr_info * const thr = proc->thr[0];
+	struct rockminer_chip_data * const chip = thr->cgpu_data;
+	bool unsafe = false;
+	
+	if (!strncasecmp(newvalue, "unsafe:", 7))
+	{
+		newvalue += 7;
+		unsafe = true;
+	}
+	
+	const int val = atoi(newvalue);
+	if (val < ROCKMINER_MIN_FREQ_MHZ || val > ROCKMINER_MAX_FREQ_MHZ)
+		return "Invalid clock speed";
+	else
+	if (val > ROCKMINER_MAX_SAFE_FREQ_MHZ && !unsafe)
+		return "Dangerous clock speed (use \"unsafe:N\" to force)";
+	
+	applog(LOG_DEBUG, "%"PRIpreprv": Changing clock frequency for future jobs to %d MHz", proc->proc_repr, val);
+	rockminer_job_buf_set_freq(chip->next_work_req, val);
+	
+	return NULL;
+}
+
+static const struct bfg_set_device_definition rockminer_set_device_funcs[] = {
+	{"clock", rockminer_set_clock, "clock frequency"},
+	{NULL}
+};
+
+static
+int rockminer_get_clock(struct cgpu_info * const proc)
+{
+	struct thr_info * const thr = proc->thr[0];
+	struct rockminer_chip_data * const chip = thr->cgpu_data;
+	return ((int)chip->next_work_req[0x31] + 1) * 10;
+}
+
+static
+struct api_data *rockminer_get_extra_device_status(struct cgpu_info * const proc)
+{
+	struct api_data *root = NULL;
+	
+	double d = rockminer_get_clock(proc);
+	root = api_add_freq(root, "Frequency", &d, true);
+	
+	return root;
+}
+
+#ifdef HAVE_CURSES
+static
+void rockminer_tui_wlogprint_choices(struct cgpu_info * const proc)
+{
+	wlogprint("[C]lock speed ");
+}
+
+static
+const char *rockminer_tui_handle_choice(struct cgpu_info * const proc, const int input)
+{
+	static char buf[0x100];  // Static for replies
+	
+	switch (input)
+	{
+		case 'c': case 'C':
+		{
+			sprintf(buf, "Set clock speed (range %d-%d, multiple of 10)", ROCKMINER_MIN_FREQ_MHZ, ROCKMINER_MAX_FREQ_MHZ);
+			char * const val = curses_input(buf);
+			const char * const msg = rockminer_set_clock(proc, "clock", val ?: "", NULL, NULL);
+			free(val);
+			if (msg)
+			{
+				snprintf(buf, sizeof(buf), "%s\n", msg);
+				return buf;
+			}
+			return "Clock speed changed\n";
+		}
+	}
+	return NULL;
+}
+
+static
+void rockminer_wlogprint_status(struct cgpu_info * const proc)
+{
+	wlogprint("Clock speed: %d\n", rockminer_get_clock(proc));
+}
+#endif
+
+struct device_drv rockminer_drv = {
+	.dname = "rockminer",
+	.name = "RKM",
+	
+	.lowl_match = rockminer_lowl_match,
+	.lowl_probe = rockminer_lowl_probe,
+	
+	.thread_init = rockminer_init,
+	
+	.minerloop = minerloop_queue,
+	.queue_append = rockminer_queue_append,
+	.queue_flush = rockminer_queue_flush,
+	.poll = rockminer_poll,
+	
+	.get_api_extra_device_status = rockminer_get_extra_device_status,
+	
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = rockminer_wlogprint_status,
+	.proc_tui_wlogprint_choices = rockminer_tui_wlogprint_choices,
+	.proc_tui_handle_choice = rockminer_tui_handle_choice,
+#endif
+};

+ 124 - 14
driver-stratum.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -36,6 +36,7 @@
 #define _ssm_client_xnonce2sz  work2d_xnonce2sz
 #define _ssm_client_xnonce2sz  work2d_xnonce2sz
 static char *_ssm_notify;
 static char *_ssm_notify;
 static int _ssm_notify_sz;
 static int _ssm_notify_sz;
+static struct stratumsrv_job *_ssm_last_ssj;
 static struct event *ev_notify;
 static struct event *ev_notify;
 static notifier_t _ssm_update_notifier;
 static notifier_t _ssm_update_notifier;
 
 
@@ -44,6 +45,7 @@ struct stratumsrv_job {
 	
 	
 	struct timeval tv_prepared;
 	struct timeval tv_prepared;
 	struct stratum_work swork;
 	struct stratum_work swork;
+	float job_pdiff[WORK2D_MAX_DIVISIONS+1];
 	
 	
 	UT_hash_handle hh;
 	UT_hash_handle hh;
 };
 };
@@ -56,17 +58,39 @@ static struct event_base *_smm_evbase;
 static bool _smm_running;
 static bool _smm_running;
 static struct evconnlistener *_smm_listener;
 static struct evconnlistener *_smm_listener;
 
 
+struct stratumsrv_conn_userlist {
+	struct proxy_client *client;
+	struct stratumsrv_conn *conn;
+	struct stratumsrv_conn_userlist *client_next;
+	struct stratumsrv_conn_userlist *next;
+};
+
 struct stratumsrv_conn {
 struct stratumsrv_conn {
 	struct bufferevent *bev;
 	struct bufferevent *bev;
 	uint32_t xnonce1_le;
 	uint32_t xnonce1_le;
 	struct timeval tv_hashes_done;
 	struct timeval tv_hashes_done;
 	bool hashes_done_ext;
 	bool hashes_done_ext;
+	float current_share_pdiff;
+	float desired_share_pdiff;
+	struct stratumsrv_conn_userlist *authorised_users;
 	
 	
 	struct stratumsrv_conn *next;
 	struct stratumsrv_conn *next;
 };
 };
 
 
 static struct stratumsrv_conn *_ssm_connections;
 static struct stratumsrv_conn *_ssm_connections;
 
 
+static
+void stratumsrv_send_set_difficulty(struct stratumsrv_conn * const conn, const float share_pdiff)
+{
+	struct bufferevent * const bev = conn->bev;
+	char buf[0x100];
+	const double bdiff = pdiff_to_bdiff(share_pdiff);
+	conn->current_share_pdiff = share_pdiff;
+	const int prec = double_find_precision(bdiff, 10.);
+	const size_t bufsz = snprintf(buf, sizeof(buf), "{\"params\":[%.*f],\"id\":null,\"method\":\"mining.set_difficulty\"}\n", prec, bdiff);
+	bufferevent_write(bev, buf, bufsz);
+}
+
 #define _ssm_gen_dummy_work work2d_gen_dummy_work
 #define _ssm_gen_dummy_work work2d_gen_dummy_work
 
 
 static
 static
@@ -135,17 +159,52 @@ bool stratumsrv_update_notify_str(struct pool * const pool, bool clean)
 	assert(_ssm_notify_sz <= bufsz);
 	assert(_ssm_notify_sz <= bufsz);
 	free(_ssm_notify);
 	free(_ssm_notify);
 	_ssm_notify = buf;
 	_ssm_notify = buf;
+	_ssm_last_ssj = ssj;
 	
 	
+	float pdiff = target_diff(ssj->swork.target);
 	LL_FOREACH(_ssm_connections, conn)
 	LL_FOREACH(_ssm_connections, conn)
 	{
 	{
 		if (unlikely(!conn->xnonce1_le))
 		if (unlikely(!conn->xnonce1_le))
 			continue;
 			continue;
+		float conn_pdiff = conn->desired_share_pdiff;
+		if (pdiff < conn_pdiff)
+			conn_pdiff = pdiff;
+		ssj->job_pdiff[conn->xnonce1_le] = conn_pdiff;
+		if (conn_pdiff != conn->current_share_pdiff)
+			stratumsrv_send_set_difficulty(conn, conn_pdiff);
 		bufferevent_write(conn->bev, _ssm_notify, _ssm_notify_sz);
 		bufferevent_write(conn->bev, _ssm_notify, _ssm_notify_sz);
 	}
 	}
 	
 	
 	return true;
 	return true;
 }
 }
 
 
+void stratumsrv_client_changed_diff(struct proxy_client * const client)
+{
+	int connections_affected = 0, connections_changed = 0;
+	struct stratumsrv_conn_userlist *ule, *ule2;
+	LL_FOREACH(client->stratumsrv_connlist, ule)
+	{
+		struct stratumsrv_conn * const conn = ule->conn;
+		
+		++connections_affected;
+		
+		float desired_share_pdiff = client->desired_share_pdiff;
+		LL_FOREACH(conn->authorised_users, ule2)
+		{
+			struct proxy_client * const other_client = ule2->client;
+			if (other_client->desired_share_pdiff < desired_share_pdiff)
+				desired_share_pdiff = other_client->desired_share_pdiff;
+		}
+		if (conn->desired_share_pdiff != desired_share_pdiff)
+		{
+			conn->desired_share_pdiff = desired_share_pdiff;
+			++connections_changed;
+		}
+	}
+	if (connections_affected)
+		applog(LOG_DEBUG, "Proxy-share difficulty change for user '%s' affected %d connections (%d changed difficulty)", client->username, connections_affected, connections_changed);
+}
+
 static
 static
 void _ssj_free(struct stratumsrv_job * const ssj)
 void _ssj_free(struct stratumsrv_job * const ssj)
 {
 {
@@ -203,6 +262,7 @@ void stratumsrv_boot_all_subscribed(const char * const msg)
 	
 	
 	free(_ssm_notify);
 	free(_ssm_notify);
 	_ssm_notify = NULL;
 	_ssm_notify = NULL;
+	_ssm_last_ssj = NULL;
 	
 	
 	// Boot all connections
 	// Boot all connections
 	LL_FOREACH_SAFE(_ssm_connections, conn, tmp_conn)
 	LL_FOREACH_SAFE(_ssm_connections, conn, tmp_conn)
@@ -316,8 +376,9 @@ void _stratumsrv_success(struct bufferevent * const bev, const char * const idst
 }
 }
 
 
 static
 static
-void stratumsrv_mining_subscribe(struct bufferevent *bev, json_t *params, const char *idstr, uint32_t *xnonce1_p)
+void stratumsrv_mining_subscribe(struct bufferevent * const bev, json_t * const params, const char * const idstr, struct stratumsrv_conn * const conn)
 {
 {
+	uint32_t * const xnonce1_p = &conn->xnonce1_le;
 	char buf[90 + strlen(idstr) + (_ssm_client_octets * 2 * 2) + 0x10];
 	char buf[90 + strlen(idstr) + (_ssm_client_octets * 2 * 2) + 0x10];
 	char xnonce1x[(_ssm_client_octets * 2) + 1];
 	char xnonce1x[(_ssm_client_octets * 2) + 1];
 	int bufsz;
 	int bufsz;
@@ -339,23 +400,34 @@ void stratumsrv_mining_subscribe(struct bufferevent *bev, json_t *params, const
 	bin2hex(xnonce1x, xnonce1_p, _ssm_client_octets);
 	bin2hex(xnonce1x, xnonce1_p, _ssm_client_octets);
 	bufsz = sprintf(buf, "{\"id\":%s,\"result\":[[[\"mining.set_difficulty\",\"x\"],[\"mining.notify\",\"%s\"]],\"%s\",%d],\"error\":null}\n", idstr, xnonce1x, xnonce1x, _ssm_client_xnonce2sz);
 	bufsz = sprintf(buf, "{\"id\":%s,\"result\":[[[\"mining.set_difficulty\",\"x\"],[\"mining.notify\",\"%s\"]],\"%s\",%d],\"error\":null}\n", idstr, xnonce1x, xnonce1x, _ssm_client_xnonce2sz);
 	bufferevent_write(bev, buf, bufsz);
 	bufferevent_write(bev, buf, bufsz);
-	bufferevent_write(bev, "{\"params\":[", 11);
-	if (opt_scrypt)
-		bufferevent_write(bev, "0.000015258556232", 17);
-	else
-		bufferevent_write(bev, "0.9999847412109375", 18);
-	bufferevent_write(bev, "],\"id\":null,\"method\":\"mining.set_difficulty\"}\n", 46);
+	
+	float pdiff = target_diff(_ssm_last_ssj->swork.target);
+	if (pdiff > conn->desired_share_pdiff)
+		pdiff = conn->desired_share_pdiff;
+	_ssm_last_ssj->job_pdiff[*xnonce1_p] = pdiff;
+	stratumsrv_send_set_difficulty(conn, pdiff);
 	bufferevent_write(bev, _ssm_notify, _ssm_notify_sz);
 	bufferevent_write(bev, _ssm_notify, _ssm_notify_sz);
 }
 }
 
 
 static
 static
-void stratumsrv_mining_authorize(struct bufferevent *bev, json_t *params, const char *idstr, uint32_t *xnonce1_p)
+void stratumsrv_mining_authorize(struct bufferevent * const bev, json_t * const params, const char * const idstr, struct stratumsrv_conn * const conn)
 {
 {
 	struct proxy_client * const client = stratumsrv_find_or_create_client(__json_array_string(params, 0));
 	struct proxy_client * const client = stratumsrv_find_or_create_client(__json_array_string(params, 0));
 	
 	
 	if (unlikely(!client))
 	if (unlikely(!client))
 		return_stratumsrv_failure(20, "Failed creating new cgpu");
 		return_stratumsrv_failure(20, "Failed creating new cgpu");
 	
 	
+	if ((!conn->authorised_users) || client->desired_share_pdiff < conn->desired_share_pdiff)
+		conn->desired_share_pdiff = client->desired_share_pdiff;
+	
+	struct stratumsrv_conn_userlist *ule = malloc(sizeof(*ule));
+	*ule = (struct stratumsrv_conn_userlist){
+		.client = client,
+		.conn = conn,
+	};
+	LL_PREPEND(conn->authorised_users, ule);
+	LL_PREPEND2(client->stratumsrv_connlist, ule, client_next);
+	
 	_stratumsrv_success(bev, idstr);
 	_stratumsrv_success(bev, idstr);
 }
 }
 
 
@@ -373,7 +445,6 @@ void stratumsrv_mining_submit(struct bufferevent *bev, json_t *params, const cha
 	const char * const nonce = __json_array_string(params, 4);
 	const char * const nonce = __json_array_string(params, 4);
 	uint8_t xnonce2[work2d_xnonce2sz];
 	uint8_t xnonce2[work2d_xnonce2sz];
 	uint32_t ntime_n, nonce_n;
 	uint32_t ntime_n, nonce_n;
-	const float nonce_diff = opt_scrypt ? (1./0x10000) : 1.;
 	bool is_stale;
 	bool is_stale;
 	
 	
 	if (unlikely(!client))
 	if (unlikely(!client))
@@ -395,6 +466,13 @@ void stratumsrv_mining_submit(struct bufferevent *bev, json_t *params, const cha
 	if (!ssj)
 	if (!ssj)
 		return_stratumsrv_failure(21, "Job not found");
 		return_stratumsrv_failure(21, "Job not found");
 	
 	
+	float nonce_diff = ssj->job_pdiff[*xnonce1_p];
+	if (unlikely(nonce_diff <= 0))
+	{
+		applog(LOG_WARNING, "Unknown share difficulty for SSM job %s", ssj->my_job_id);
+		nonce_diff = conn->current_share_pdiff;
+	}
+	
 	hex2bin(xnonce2, extranonce2, work2d_xnonce2sz);
 	hex2bin(xnonce2, extranonce2, work2d_xnonce2sz);
 	
 	
 	// Submit nonce
 	// Submit nonce
@@ -416,7 +494,7 @@ void stratumsrv_mining_submit(struct bufferevent *bev, json_t *params, const cha
 		timer_set_now(&tv_now);
 		timer_set_now(&tv_now);
 		timersub(&tv_now, &conn->tv_hashes_done, &tv_delta);
 		timersub(&tv_now, &conn->tv_hashes_done, &tv_delta);
 		conn->tv_hashes_done = tv_now;
 		conn->tv_hashes_done = tv_now;
-		const uint64_t hashes = opt_scrypt ? 0x10000 : 0x100000000;
+		const uint64_t hashes = (float)0x100000000 * nonce_diff;
 		hashes_done(thr, hashes, &tv_delta, NULL);
 		hashes_done(thr, hashes, &tv_delta, NULL);
 	}
 	}
 }
 }
@@ -460,7 +538,7 @@ bool stratumsrv_process_line(struct bufferevent * const bev, const char * const
 	json = JSON_LOADS(ln, &jerr);
 	json = JSON_LOADS(ln, &jerr);
 	if (!json)
 	if (!json)
 	{
 	{
-		if (strncmp(ln, "GET ", 4))
+		if (strncmp(ln, "GET ", 4) && strncmp(ln, "POST ", 5) && ln[0] != '\x16' /* TLS handshake */)
 			applog(LOG_ERR, "SSM: JSON parse error: %s", ln);
 			applog(LOG_ERR, "SSM: JSON parse error: %s", ln);
 		return false;
 		return false;
 	}
 	}
@@ -493,10 +571,10 @@ errout:
 		stratumsrv_mining_hashes_done(bev, params, idstr, conn);
 		stratumsrv_mining_hashes_done(bev, params, idstr, conn);
 	else
 	else
 	if (!strcasecmp(method, "mining.authorize"))
 	if (!strcasecmp(method, "mining.authorize"))
-		stratumsrv_mining_authorize(bev, params, idstr, &conn->xnonce1_le);
+		stratumsrv_mining_authorize(bev, params, idstr, conn);
 	else
 	else
 	if (!strcasecmp(method, "mining.subscribe"))
 	if (!strcasecmp(method, "mining.subscribe"))
-		stratumsrv_mining_subscribe(bev, params, idstr, &conn->xnonce1_le);
+		stratumsrv_mining_subscribe(bev, params, idstr, conn);
 	else
 	else
 		_stratumsrv_failure(bev, idstr, -3, "Method not supported");
 		_stratumsrv_failure(bev, idstr, -3, "Method not supported");
 	
 	
@@ -509,10 +587,18 @@ static
 void stratumsrv_client_close(struct stratumsrv_conn * const conn)
 void stratumsrv_client_close(struct stratumsrv_conn * const conn)
 {
 {
 	struct bufferevent * const bev = conn->bev;
 	struct bufferevent * const bev = conn->bev;
+	struct stratumsrv_conn_userlist *ule, *uletmp;
 	
 	
 	bufferevent_free(bev);
 	bufferevent_free(bev);
 	LL_DELETE(_ssm_connections, conn);
 	LL_DELETE(_ssm_connections, conn);
 	release_work2d_(conn->xnonce1_le);
 	release_work2d_(conn->xnonce1_le);
+	LL_FOREACH_SAFE(conn->authorised_users, ule, uletmp)
+	{
+		struct proxy_client * const client = ule->client;
+		LL_DELETE(conn->authorised_users, ule);
+		LL_DELETE(client->stratumsrv_connlist, ule);
+		free(ule);
+	}
 	free(conn);
 	free(conn);
 }
 }
 
 
@@ -548,6 +634,25 @@ void stratumsrv_event(struct bufferevent *bev, short events, void *p)
 	}
 	}
 }
 }
 
 
+static
+const char *stratumsrv_init_diff(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	struct stratumsrv_conn * const conn = proc->device_data;
+	
+	const double nv = atof(newvalue);
+	if (nv <= 0)
+		return "Invalid difficulty";
+	
+	conn->desired_share_pdiff = nv;
+	
+	return NULL;
+}
+
+static const struct bfg_set_device_definition stratumsrv_set_device_funcs_newconnect[] = {
+	{"diff", stratumsrv_init_diff, NULL},
+	{NULL},
+};
+
 static
 static
 void stratumlistener(struct evconnlistener *listener, evutil_socket_t sock, struct sockaddr *addr, int len, void *p)
 void stratumlistener(struct evconnlistener *listener, evutil_socket_t sock, struct sockaddr *addr, int len, void *p)
 {
 {
@@ -557,7 +662,9 @@ void stratumlistener(struct evconnlistener *listener, evutil_socket_t sock, stru
 	conn = malloc(sizeof(*conn));
 	conn = malloc(sizeof(*conn));
 	*conn = (struct stratumsrv_conn){
 	*conn = (struct stratumsrv_conn){
 		.bev = bev,
 		.bev = bev,
+		.desired_share_pdiff = opt_scrypt ? (1./0x10000) : 1.,
 	};
 	};
+	drv_set_defaults(&proxy_drv, stratumsrv_set_device_funcs_newconnect, conn, NULL, NULL, 1);
 	LL_PREPEND(_ssm_connections, conn);
 	LL_PREPEND(_ssm_connections, conn);
 	bufferevent_setcb(bev, stratumsrv_read, NULL, stratumsrv_event, conn);
 	bufferevent_setcb(bev, stratumsrv_read, NULL, stratumsrv_event, conn);
 	bufferevent_enable(bev, EV_READ | EV_WRITE);
 	bufferevent_enable(bev, EV_READ | EV_WRITE);
@@ -586,6 +693,9 @@ void stratumsrv_change_port()
 	_smm_listener = evconnlistener_new_bind(evbase, stratumlistener, NULL, (
 	_smm_listener = evconnlistener_new_bind(evbase, stratumlistener, NULL, (
 		LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | LEV_OPT_REUSEABLE
 		LEV_OPT_CLOSE_ON_FREE | LEV_OPT_CLOSE_ON_EXEC | LEV_OPT_REUSEABLE
 	), 0x10, (void*)&sin, sizeof(sin));
 	), 0x10, (void*)&sin, sizeof(sin));
+	
+	// NOTE: libevent doesn't seem to implement LEV_OPT_CLOSE_ON_EXEC for Windows, so we must do this ourselves
+	set_cloexec_socket(evconnlistener_get_fd(_smm_listener), true);
 }
 }
 
 
 static
 static

+ 1 - 1
driver-twinfury.c

@@ -1,6 +1,6 @@
 /*
 /*
  * Copyright 2013 Andreas Auer
  * Copyright 2013 Andreas Auer
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free

+ 3 - 1
driver-x6500.c

@@ -1,5 +1,6 @@
 /*
 /*
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2014 Luke Dashjr
+ * Copyright 2013 Nate Woolls
  * Copyright 2012 Andrew Smith
  * Copyright 2012 Andrew Smith
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
@@ -137,6 +138,7 @@ bool x6500_lowl_probe(const struct lowlevel_device_info * const info)
 	const char * const serial = info->serial;
 	const char * const serial = info->serial;
 	if (info->lowl != &lowl_ft232r)
 	if (info->lowl != &lowl_ft232r)
 	{
 	{
+		bfg_probe_result_flags = BPR_WRONG_DEVTYPE;
 		if (info->lowl != &lowl_usb)
 		if (info->lowl != &lowl_usb)
 			applog(LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not ft232r!",
 			applog(LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not ft232r!",
 			       __func__, product, serial);
 			       __func__, product, serial);

+ 355 - 0
driver-zeusminer.c

@@ -0,0 +1,355 @@
+/*
+ * Copyright 2014 Nate Woolls
+ * Copyright 2014 ZeusMiner Team
+ * Copyright 2014 Luke Dashjr
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+
+#include "miner.h"
+#include "driver-icarus.h"
+#include "lowl-vcom.h"
+
+#define ZEUSMINER_IO_SPEED          115200
+
+#define ZEUSMINER_CHIP_GEN1_CORES   8
+#define ZEUSMINER_CHIP_CORES        ZEUSMINER_CHIP_GEN1_CORES
+#define ZEUSMINER_CHIPS_COUNT_MAX   1
+#define ZEUSMINER_CHIPS_COUNT       6
+#define ZEUSMINER_DEFAULT_CLOCK     328
+#define ZEUSMINER_MIN_CLOCK         200
+#define ZEUSMINER_MAX_CLOCK         383
+
+
+BFG_REGISTER_DRIVER(zeusminer_drv)
+
+static
+const struct bfg_set_device_definition zeusminer_set_device_funcs_probe[];
+
+static
+const struct bfg_set_device_definition zeusminer_set_device_funcs_live[];
+
+// device helper functions
+
+static
+uint32_t zeusminer_calc_clk_header(uint16_t freq)
+{
+	//set clk_reg based on chip_clk
+	uint32_t clk_reg = (uint32_t)freq * 2 / 3;
+	
+	//clock speed mask for header
+	uint32_t clk_header = (clk_reg << 24) + ((0xff - clk_reg) << 16);
+	
+	return clk_header;
+}
+
+// ICARUS_INFO functions - driver-icarus.h
+
+// device detection
+
+static
+bool zeusminer_detect_one(const char *devpath)
+{
+	struct device_drv *drv = &zeusminer_drv;
+	
+	struct ICARUS_INFO *info = calloc(1, sizeof(struct ICARUS_INFO));
+	if (unlikely(!info))
+		quit(1, "Failed to malloc ICARUS_INFO");
+	
+	char scrypt_golden_ob[] =
+	"55aa"																//Freq is set to 0x55*1.5=85Mhz
+	"0001"																//We want to find a Nonce which result's diff is at least 32768
+	"00038000"															//Starting Nonce
+	"063b0b1b"															//Bits (target in compact form)
+	"028f3253"															//Timestamp
+	"5e900609c15dc49a42b1d8492a6dd4f8f15295c989a1decf584a6aa93be26066"	//Merkle root
+	"d3185f55ef635b5865a7a79b7fa74121a6bb819da416328a9bd2f8cef72794bf"	//Previous hash
+	"02000000";															//Version
+	
+	const char scrypt_golden_nonce[] = "00038d26";
+	
+	*info = (struct ICARUS_INFO){
+		.baud = ZEUSMINER_IO_SPEED,
+		.timing_mode = MODE_DEFAULT,
+		// if do_icarus_timing is true, the timing adjustment may
+		// result in a read_count that considers the device Idle
+		.do_icarus_timing = false,
+		.probe_read_count = 5,
+		.golden_nonce = scrypt_golden_nonce,
+		.chips = ZEUSMINER_CHIPS_COUNT,
+		.freq = ZEUSMINER_DEFAULT_CLOCK,
+	};
+	
+	//pick up any user-defined settings passed in via --set
+	drv_set_defaults(drv, zeusminer_set_device_funcs_probe, info, devpath, detectone_meta_info.serial, 1);
+	
+	info->work_division = upper_power_of_two_u32(info->chips * ZEUSMINER_CHIP_CORES);
+	info->fpga_count = info->chips * ZEUSMINER_CHIP_CORES;
+	
+	//send the requested Chip Speed with the detect golden OB
+	//we use the time this request takes in order to calc hashes
+	//so we need to use the same Chip Speed used when hashing
+	uint32_t clk_header = zeusminer_calc_clk_header(info->freq);
+	char clk_header_str[10];
+	sprintf(clk_header_str, "%08x", clk_header + 1);
+	memcpy(scrypt_golden_ob, clk_header_str, 8);
+	
+	info->golden_ob = scrypt_golden_ob;
+	
+	if (!icarus_detect_custom(devpath, drv, info) &&
+		//ZM doesn't respond to detection 1 out of ~30 times
+		!icarus_detect_custom(devpath, drv, info))
+	{
+		free(info);
+		return false;
+	}
+	
+	double duration_sec;
+	const double hash_count = (double)0xd26;
+	uint64_t default_hashes_per_core = (((info->freq * 2) / 3) * 1024) / ZEUSMINER_CHIP_CORES;
+	
+	if (info->ignore_golden_nonce)
+		duration_sec = hash_count / default_hashes_per_core;
+	else
+		duration_sec = ((double)(info->golden_tv.tv_sec) + ((double)(info->golden_tv.tv_usec)) / ((double)1000000));
+	
+	//determines how the hash rate is calculated when no nonce is returned
+	info->Hs = (double)(duration_sec / hash_count / info->chips / ZEUSMINER_CHIP_CORES);
+	
+	//set the read_count (how long to wait for a result) based on chips, cores, and time to find a nonce
+	int chips_count_max = ZEUSMINER_CHIPS_COUNT_MAX;
+	if (info->chips > chips_count_max)
+		chips_count_max = upper_power_of_two_u32(info->chips);
+	//golden_speed_per_core is the number of hashes / second / core
+	uint64_t golden_speed_per_core = (uint64_t)(hash_count / duration_sec);
+	//don't combine the following two lines - overflows leaving info->read_count at 0
+	info->read_count = (uint32_t)((4294967296 * 10) / (ZEUSMINER_CHIP_CORES * chips_count_max * golden_speed_per_core * 2));
+	info->read_count = info->read_count * 3 / 4;
+	
+	return true;
+}
+
+// support for --set-device
+// must be set before probing the device
+
+static
+bool zeusminer_set_clock_freq(struct cgpu_info * const device, int const freq)
+{
+	struct ICARUS_INFO * const info = device->device_data;
+
+	if (freq < ZEUSMINER_MIN_CLOCK || freq > ZEUSMINER_MAX_CLOCK)
+		return false;
+
+	info->freq = freq;
+
+	return true;
+}
+
+static
+const char *zeusminer_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)
+{
+	int val = atoi(setting);
+	
+	if (!zeusminer_set_clock_freq(device, val))
+	{
+		sprintf(replybuf, "invalid clock: '%s' valid range %d-%d",
+		        setting, ZEUSMINER_MIN_CLOCK, ZEUSMINER_MAX_CLOCK);
+		return replybuf;
+	}
+	
+	return NULL;
+}
+
+static
+const char *zeusminer_set_chips(struct cgpu_info * const device, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	struct ICARUS_INFO * const info = device->device_data;
+	
+	info->chips = atoi(setting);
+	
+	return NULL;
+}
+
+static
+const char *zeusminer_set_ignore_golden_nonce(struct cgpu_info * const device, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	struct ICARUS_INFO * const info = device->device_data;
+	
+	info->ignore_golden_nonce = atoi(setting) == 1;
+	
+	return NULL;
+}
+
+// for setting clock and chips during probe / detect
+static
+const struct bfg_set_device_definition zeusminer_set_device_funcs_probe[] = {
+	{ "clock", zeusminer_set_clock, NULL },
+	{ "chips", zeusminer_set_chips, NULL },
+	{ "ignore_golden_nonce",zeusminer_set_ignore_golden_nonce, NULL },
+	{ NULL },
+};
+
+// for setting clock while mining
+static
+const struct bfg_set_device_definition zeusminer_set_device_funcs_live[] = {
+	{ "clock", zeusminer_set_clock, NULL },
+	{ NULL },
+};
+
+static
+bool zeusminer_lowl_probe(const struct lowlevel_device_info * const info)
+{
+	return vcom_lowl_probe_wrapper(info, zeusminer_detect_one);
+}
+
+// device_drv functions - miner.h
+
+static
+bool zeusminer_thread_init(struct thr_info * const thr)
+{
+	struct cgpu_info * const device = thr->cgpu;
+	
+	device->min_nonce_diff = 1./0x10000;
+	device->set_device_funcs = zeusminer_set_device_funcs_live;
+	
+	return icarus_init(thr);
+}
+
+static
+bool zeusminer_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused uint64_t max_nonce)
+{
+	struct cgpu_info * const device = thr->cgpu;
+	struct icarus_state * const state = thr->cgpu_data;
+	struct ICARUS_INFO * const info = device->device_data;
+	
+	uint32_t clk_header = zeusminer_calc_clk_header(info->freq);
+	uint32_t diff = work->nonce_diff * 0x10000;
+	uint32_t target_me = 0xffff / diff;
+	uint32_t header = clk_header + target_me;
+	
+	pk_u32be(state->ob_bin, 0, header);
+	bswap_32mult(&state->ob_bin[4], work->data, 80/4);
+	
+	return true;
+}
+
+// display the Chip # in the UI when viewing per-proc details
+static
+bool zeusminer_override_statline_temp2(char *buf, size_t bufsz, struct cgpu_info *device, __maybe_unused bool per_processor)
+{
+	if (per_processor && ((device->proc_id % ZEUSMINER_CHIP_CORES) == 0))
+	{
+		tailsprintf(buf, bufsz, "C:%-3d", device->proc_id / ZEUSMINER_CHIP_CORES);
+		return true;
+	}
+	return false;
+}
+
+// return the Chip # in via the API when procdetails is called
+static
+struct api_data *zeusminer_get_api_extra_device_detail(struct cgpu_info *device)
+{
+	int chip = device->proc_id / ZEUSMINER_CHIP_CORES;
+	return api_add_int(NULL, "Chip", &chip, true);
+}
+
+/*
+ * specify settings / options via TUI
+ */
+
+#ifdef HAVE_CURSES
+static
+void zeusminer_tui_wlogprint_choices(struct cgpu_info * const proc)
+{
+	wlogprint("[C]lock speed ");
+}
+
+static
+const char *zeusminer_tui_handle_choice(struct cgpu_info * const proc, const int input)
+{
+	static char buf[0x100];  // Static for replies
+
+	switch (input)
+	{
+		case 'c': case 'C':
+		{
+			sprintf(buf, "Set clock speed");
+			char * const setting = curses_input(buf);
+
+			if (zeusminer_set_clock_freq(proc->device, atoi(setting)))
+			{
+				return "Clock speed changed\n";
+			}
+			else
+			{
+				sprintf(buf, "Invalid clock: '%s' valid range %d-%d",
+						setting, ZEUSMINER_MIN_CLOCK, ZEUSMINER_MAX_CLOCK);
+				return buf;
+			}
+		}
+	}
+	return NULL;
+}
+
+static
+void zeusminer_wlogprint_status(struct cgpu_info * const proc)
+{
+	struct ICARUS_INFO * const info = proc->device->device_data;
+	wlogprint("Clock speed: %d\n", info->freq);
+}
+#endif
+
+// device_drv definition - miner.h
+
+static
+void zeusminer_drv_init()
+{
+	// based on Icarus
+	zeusminer_drv = icarus_drv;
+	
+	// metadata
+	zeusminer_drv.dname = "zeusminer";
+	zeusminer_drv.name = "ZUS";
+	zeusminer_drv.supported_algos = POW_SCRYPT;
+	
+	// detect device
+	zeusminer_drv.lowl_probe = zeusminer_lowl_probe;
+	
+	// initialize thread
+	zeusminer_drv.thread_init = zeusminer_thread_init;
+	
+	// Icarus scanhash mining hooks
+	zeusminer_drv.job_prepare = zeusminer_job_prepare;
+	
+	// specify driver probe priority
+	// currently setup specifically to probe before DualMiner
+	zeusminer_drv.probe_priority = -100;
+
+	// output the chip # when viewing per-proc stats
+	// so we can easily ID chips vs cores
+	zeusminer_drv.override_statline_temp2 = zeusminer_override_statline_temp2;
+
+	// output the chip # via RPC API
+	zeusminer_drv.get_api_extra_device_detail = zeusminer_get_api_extra_device_detail;
+
+	// TUI support - e.g. setting clock via UI
+#ifdef HAVE_CURSES
+	zeusminer_drv.proc_wlogprint_status = zeusminer_wlogprint_status;
+	zeusminer_drv.proc_tui_wlogprint_choices = zeusminer_tui_wlogprint_choices;
+	zeusminer_drv.proc_tui_handle_choice = zeusminer_tui_handle_choice;
+#endif
+}
+
+struct device_drv zeusminer_drv = {
+	.drv_init = zeusminer_drv_init,
+};

+ 2 - 1
driver-ztex.c

@@ -1,6 +1,6 @@
 /*
 /*
  * Copyright 2012 nelisky
  * Copyright 2012 nelisky
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2014 Luke Dashjr
  * Copyright 2012-2013 Denis Ahrens
  * Copyright 2012-2013 Denis Ahrens
  * Copyright 2012 Xiangfu
  * Copyright 2012 Xiangfu
  *
  *
@@ -89,6 +89,7 @@ bool ztex_lowl_probe(const struct lowlevel_device_info * const info)
 	const char * const serial = info->serial;
 	const char * const serial = info->serial;
 	if (info->lowl != &lowl_usb)
 	if (info->lowl != &lowl_usb)
 	{
 	{
+		bfg_probe_result_flags = BPR_WRONG_DEVTYPE;
 		applog(LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not usb!",
 		applog(LOG_DEBUG, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not usb!",
 		       __func__, product, serial);
 		       __func__, product, serial);
 		return false;
 		return false;

+ 97 - 213
gc3355.c

@@ -1,6 +1,6 @@
 /*
 /*
  * Copyright 2014 Nate Woolls
  * Copyright 2014 Nate Woolls
- * Copyright 2013 Luke Dashjr
+ * Copyright 2014 Luke Dashjr
  * Copyright 2014 GridSeed Team
  * Copyright 2014 GridSeed Team
  * Copyright 2014 Dualminer Team
  * Copyright 2014 Dualminer Team
  *
  *
@@ -10,6 +10,8 @@
  * any later version.  See COPYING for more details.
  * any later version.  See COPYING for more details.
  */
  */
 
 
+#include "config.h"
+
 #include "gc3355.h"
 #include "gc3355.h"
 
 
 #include <stdint.h>
 #include <stdint.h>
@@ -31,9 +33,9 @@
 int opt_sha2_units = -1;
 int opt_sha2_units = -1;
 int opt_pll_freq = 0; // default is set in gc3355_set_pll_freq
 int opt_pll_freq = 0; // default is set in gc3355_set_pll_freq
 
 
-#define GC3355_CHIP_NAME  "gc3355"
-#define DEFAULT_ORB_SHA2_CORES  16
-
+#define GC3355_CHIP_NAME         "gc3355"
+#define GC3355_COMMAND_DELAY_MS  20
+#define GC3355_WRITE_DELAY_MS    10
 
 
 // General GC3355 commands
 // General GC3355 commands
 
 
@@ -44,12 +46,6 @@ const char *firmware_request_cmd[] =
 	NULL
 	NULL
 };
 };
 
 
-static
-const char *no_fifo_cmd[] = {
-	"55AAC000D0D0D0D00000000001000000",
-	NULL
-};
-
 // SHA-2 commands
 // SHA-2 commands
 
 
 static
 static
@@ -394,22 +390,9 @@ void gc3355_log_protocol(int fd, const char *buf, size_t size, const char *prefi
 	       GC3355_CHIP_NAME, fd, prefix, (unsigned long)size, hex);
 	       GC3355_CHIP_NAME, fd, prefix, (unsigned long)size, hex);
 }
 }
 
 
-int gc3355_read(int fd, char *buf, size_t size)
+ssize_t gc3355_read(int fd, char *buf, size_t size)
 {
 {
-	size_t read;
-	int tries = 20;
-	
-	while (tries > 0)
-	{
-		read = serial_read(fd, buf, size);
-		if (read > 0)
-			break;
-		
-		tries--;
-	}
-	
-	if (unlikely(tries == 0))
-		return -1;
+	size_t read = serial_read(fd, buf, size);
 	
 	
 	if ((read > 0) && opt_dev_protocol)
 	if ((read > 0) && opt_dev_protocol)
 		gc3355_log_protocol(fd, buf, read, "RECV");
 		gc3355_log_protocol(fd, buf, read, "RECV");
@@ -421,12 +404,21 @@ ssize_t gc3355_write(int fd, const void * const buf, const size_t size)
 {
 {
 	if (opt_dev_protocol)
 	if (opt_dev_protocol)
 		gc3355_log_protocol(fd, buf, size, "SEND");
 		gc3355_log_protocol(fd, buf, size, "SEND");
-	
-	return write(fd, buf, size);
+
+	ssize_t result = write(fd, buf, size);
+
+	// gc3355 can suffer register corruption if multiple writes are
+	// made in a short period of time.
+	// This is not possible to reproduce on Mac OS X where the serial
+	// drivers seem to carry an additional overhead / latency.
+	// This is reproducable on Linux though by removing the following:
+	cgsleep_ms(GC3355_WRITE_DELAY_MS);
+
+	return result;
 }
 }
 
 
 static
 static
-void _gc3355_send_cmds_bin(int fd, const char *cmds[], bool is_bin, int size)
+void gc3355_send_cmds(int fd, const char *cmds[])
 {
 {
 	int i = 0;
 	int i = 0;
 	unsigned char ob_bin[512];
 	unsigned char ob_bin[512];
@@ -436,22 +428,14 @@ void _gc3355_send_cmds_bin(int fd, const char *cmds[], bool is_bin, int size)
 		if (cmd == NULL)
 		if (cmd == NULL)
 			break;
 			break;
 
 
-		if (is_bin)
-			gc3355_write(fd, cmd, size);
-		else
-		{
-			int bin_size = strlen(cmd) / 2;
-			hex2bin(ob_bin, cmd, bin_size);
-			gc3355_write(fd, ob_bin, bin_size);
-		}
-		
+		int bin_size = strlen(cmd) / 2;
+		hex2bin(ob_bin, cmd, bin_size);
+		gc3355_write(fd, ob_bin, bin_size);
+
 		cgsleep_ms(GC3355_COMMAND_DELAY_MS);
 		cgsleep_ms(GC3355_COMMAND_DELAY_MS);
 	}
 	}
 }
 }
 
 
-#define gc3355_send_cmds_bin(fd, cmds, size)  _gc3355_send_cmds_bin(fd, cmds, true, size)
-#define gc3355_send_cmds(fd, cmds)  _gc3355_send_cmds_bin(fd, cmds, false, -1)
-
 void gc3355_scrypt_only_reset(int fd)
 void gc3355_scrypt_only_reset(int fd)
 {
 {
 	gc3355_send_cmds(fd, scrypt_only_reset_cmd);
 	gc3355_send_cmds(fd, scrypt_only_reset_cmd);
@@ -508,159 +492,64 @@ void gc3355_scrypt_only_init(int fd)
 	gc3355_scrypt_only_reset(fd);
 	gc3355_scrypt_only_reset(fd);
 }
 }
 
 
-static
-void gc3355_open_sha2_cores(int fd, int sha2_cores)
-{
-	unsigned char cmd[24], c1, c2;
-	uint16_t	mask;
-	int i;
-	
-	mask = 0x00;
-	for (i = 0; i < sha2_cores; i++)
-		mask = mask << 1 | 0x01;
-	
-	if (mask == 0)
-		return;
-	
-	c1 = mask & 0x00ff;
-	c2 = mask >> 8;
-	
-	memset(cmd, 0, sizeof(cmd));
-	memcpy(cmd, "\x55\xaa\xef\x02", 4);
-	for (i = 4; i < 24; i++) {
-		cmd[i] = ((i % 2) == 0) ? c1 : c2;
-		gc3355_write(fd, cmd, sizeof(cmd));
-		cgsleep_ms(GC3355_COMMAND_DELAY_MS);
-	}
-	return;
-}
-
-static
-void gc3355_init_sha2_nonce(int fd)
-{
-	char **cmds, *p;
-	uint32_t nonce, step;
-	int i;
-	
-	cmds = calloc(sizeof(char *) *(GC3355_ORB_DEFAULT_CHIPS + 1), 1);
-	
-	if (unlikely(!cmds))
-		quit(1, "Failed to calloc init nonce commands data array");
-	
-	step = 0xffffffff / GC3355_ORB_DEFAULT_CHIPS;
-	
-	for (i = 0; i < GC3355_ORB_DEFAULT_CHIPS; i++)
-	{
-		p = calloc(8, 1);
-		
-		if (unlikely(!p))
-			quit(1, "Failed to calloc init nonce commands data");
-		
-		memcpy(p, "\x55\xaa\x00\x00", 4);
-		
-		p[2] = i;
-		nonce = htole32(step * i);
-		memcpy(p + 4, &nonce, sizeof(nonce));
-		cmds[i] = p;
-	}
-	
-	cmds[i] = NULL;
-	gc3355_send_cmds_bin(fd, (const char **)cmds, 8);
-	
-	for (i = 0; i < GC3355_ORB_DEFAULT_CHIPS; i++)
-		free(cmds[i]);
-	
-	free(cmds);
-	return;
-}
-
 void gc3355_sha2_init(int fd)
 void gc3355_sha2_init(int fd)
 {
 {
 	gc3355_send_cmds(fd, sha2_gating_cmd);
 	gc3355_send_cmds(fd, sha2_gating_cmd);
 	gc3355_send_cmds(fd, sha2_init_cmd);
 	gc3355_send_cmds(fd, sha2_init_cmd);
 }
 }
 
 
-static
-void gc3355_reset_chips(int fd)
+void gc3355_init_miner(int fd, int pll_freq)
 {
 {
-	// reset chips
 	gc3355_send_cmds(fd, gcp_chip_reset_cmd);
 	gc3355_send_cmds(fd, gcp_chip_reset_cmd);
-	gc3355_send_cmds(fd, sha2_chip_reset_cmd);
+
+	// zzz
+	cgsleep_ms(GC3355_COMMAND_DELAY_MS);
+
+	// initialize units
+	gc3355_send_cmds(fd, multichip_init_cmd);
+	gc3355_scrypt_init(fd);
+
+	//set freq
+	gc3355_set_pll_freq(fd, pll_freq);
 }
 }
 
 
-void gc3355_init_device(int fd, int pll_freq, bool scrypt_only, bool detect_only, bool usbstick)
+void gc3355_init_dualminer(int fd, int pll_freq, bool scrypt_only, bool detect_only)
 {
 {
-	gc3355_reset_chips(fd);
+	gc3355_send_cmds(fd, gcp_chip_reset_cmd);
 
 
-	if (usbstick)
-		gc3355_reset_dtr(fd);
+	// zzz
+	cgsleep_ms(GC3355_COMMAND_DELAY_MS);
 
 
-	if (usbstick)
-	{
-		// initialize units
-		if (opt_scrypt && scrypt_only)
-			gc3355_scrypt_only_init(fd);
-		else
-		{
-			gc3355_sha2_init(fd);
-			gc3355_scrypt_init(fd);
-		}
+	gc3355_send_cmds(fd, sha2_chip_reset_cmd);
 
 
-		//set freq
-		gc3355_set_pll_freq(fd, pll_freq);
-	}
+	// initialize units
+	gc3355_reset_dtr(fd);
+
+	if (opt_scrypt && scrypt_only)
+		gc3355_scrypt_only_init(fd);
 	else
 	else
 	{
 	{
-		// zzz
-		cgsleep_ms(GC3355_COMMAND_DELAY_MS);
-		
-		// initialize units
-		gc3355_send_cmds(fd, multichip_init_cmd);
+		gc3355_sha2_init(fd);
 		gc3355_scrypt_init(fd);
 		gc3355_scrypt_init(fd);
-
-		//set freq
-		gc3355_set_pll_freq(fd, pll_freq);
-		
-		//init sha2 nonce
-		gc3355_init_sha2_nonce(fd);
 	}
 	}
 
 
+	//set freq
+	gc3355_set_pll_freq(fd, pll_freq);
+
 	// zzz
 	// zzz
 	cgsleep_ms(GC3355_COMMAND_DELAY_MS);
 	cgsleep_ms(GC3355_COMMAND_DELAY_MS);
 
 
 	if (!detect_only)
 	if (!detect_only)
 	{
 	{
 		if (!opt_scrypt)
 		if (!opt_scrypt)
-		{
-			if (usbstick)
-				// open sha2 units
-				gc3355_open_sha2_units(fd, opt_sha2_units);
-			else
-			{
-				// open sha2 cores
-				gc3355_open_sha2_cores(fd, DEFAULT_ORB_SHA2_CORES);
-			}
-		}
+			// open sha2 units
+			gc3355_open_sha2_units(fd, opt_sha2_units);
 
 
-		if (usbstick)
-			// set request to send (RTS) status
-			set_serial_rts(fd, BGV_HIGH);
-		else
-			// no fifo for orb
-			gc3355_send_cmds(fd, no_fifo_cmd);
+		// set request to send (RTS) status
+		set_serial_rts(fd, BGV_HIGH);
 	}
 	}
 }
 }
 
 
-void gc3355_init_usborb(int fd, int pll_freq, bool scrypt_only, bool detect_only)
-{
-	gc3355_init_device(fd, pll_freq, scrypt_only, detect_only, false);
-}
-
-void gc3355_init_usbstick(int fd, int pll_freq, bool scrypt_only, bool detect_only)
-{
-	gc3355_init_device(fd, pll_freq, scrypt_only, detect_only, true);
-}
-
 void gc3355_scrypt_reset(int fd)
 void gc3355_scrypt_reset(int fd)
 {
 {
 	gc3355_send_cmds(fd, scrypt_reset_cmd);
 	gc3355_send_cmds(fd, scrypt_reset_cmd);
@@ -668,65 +557,62 @@ void gc3355_scrypt_reset(int fd)
 
 
 void gc3355_scrypt_prepare_work(unsigned char cmd[156], struct work *work)
 void gc3355_scrypt_prepare_work(unsigned char cmd[156], struct work *work)
 {
 {
+	// See https://github.com/gridseed/gc3355-doc/blob/master/GC3355_Register_Spec.pdf
+
 	// command header
 	// command header
-	cmd[0] = 0x55;
-	cmd[1] = 0xaa;
-	cmd[2] = 0x1f;
-	cmd[3] = 0x00;
+	cmd[0] = 0x55;  // static header
+	cmd[1] = 0xaa;  // static header
+	cmd[2] = 0x1f;  // 0x1 (for Scrypt) | chip_id (0xf for broadcast)
+	cmd[3] = 0x00;  // identifies the following task data, beginning with 0x00
+	                // gc3355 supports sending batches of work at once
+	                // in which case this would be incremented for each batch
 	
 	
-	// task data
+	// task data - starts at 0x0 (with 4 byte offset for header)
 	memcpy(cmd + 4, work->target, 32);
 	memcpy(cmd + 4, work->target, 32);
 	memcpy(cmd + 36, work->midstate, 32);
 	memcpy(cmd + 36, work->midstate, 32);
 	memcpy(cmd + 68, work->data, 80);
 	memcpy(cmd + 68, work->data, 80);
-	
-	// nonce_max
+
+	// nonce min - starts at 0x23 (with 4 byte offset for header)
+	cmd[144] = 0x00;
+	cmd[145] = 0x00;
+	cmd[146] = 0x00;
+	cmd[147] = 0x00;
+
+	// nonce max - starts at 0x24 (with 4 byte offset for header)
 	cmd[148] = 0xff;
 	cmd[148] = 0xff;
 	cmd[149] = 0xff;
 	cmd[149] = 0xff;
 	cmd[150] = 0xff;
 	cmd[150] = 0xff;
 	cmd[151] = 0xff;
 	cmd[151] = 0xff;
-	
-	// taskid
-	int workid = work->id;
-	memcpy(cmd + 152, &(workid), 4);
+
+	// 0x25 - 0x28 are for specific Scrypt unit configs, don't set without reason
 }
 }
 
 
-void gc3355_sha2_prepare_work(unsigned char cmd[52], struct work *work, bool simple)
+void gc3355_sha2_prepare_work(unsigned char cmd[52], struct work *work)
 {
 {
-	if (simple)
-	{
-		// command header
-		cmd[0] = 0x55;
-		cmd[1] = 0xaa;
-		cmd[2] = 0x0f;
-		cmd[3] = 0x01; // SHA header sig
-		
-		memcpy(cmd + 4, work->midstate, 32);
-		memcpy(cmd + 36, work->data + 64, 12);
-		
-		// taskid
-		int workid = work->id;
-		memcpy(cmd + 48, &(workid), 4);
-	}
-	else
-	{
-		// command header
-		cmd[0] = 0x55;
-		cmd[1] = 0xaa;
-		cmd[2] = 0x0f;
-		cmd[3] = 0x00; // Scrypt header sig - used by DualMiner in Dual Mode
-		
-		uint8_t temp_bin[64];
-		memset(temp_bin, 0, 64);
-		
-		memcpy(temp_bin, work->midstate, 32);
-		memcpy(temp_bin + 52, work->data + 64, 12);
-		
-		memcpy(cmd + 8, work->midstate, 32);
-		memcpy(cmd + 40, temp_bin + 52, 12);
-	}
+	// See https://github.com/gridseed/gc3355-doc/blob/master/GC3355_Register_Spec.pdf
+
+	// command header
+	cmd[0] = 0x55;  // static header
+	cmd[1] = 0xaa;  // static header
+	cmd[2] = 0x0f;  // 0x0 (for SHA2) | chip_id (0xf for broadcast)
+	cmd[3] = 0x00;  // identifies the following task data, beginning with 0x00
+	                // gc3355 supports sending batches of work at once
+	                // in which case this would be incremented for each batch
+
+	// initial nonce - starts at 0x0 (with 4 byte offset for header)
+	cmd[4] = 0x00;
+	cmd[5] = 0x00;
+	cmd[6] = 0x00;
+	cmd[7] = 0x00;
+
+	// task data - starts at 0x1 (with 4 byte offset for header)
+	memcpy(cmd + 8, work->midstate, 32);
+	memcpy(cmd + 40, work->data + 64, 12);
+
+	// 0x1e - 0xff are for specific SHA2 unit configs, don't set without reason
 }
 }
 
 
-uint32_t gc3355_get_firmware_version(int fd)
+int64_t gc3355_get_firmware_version(int fd)
 {
 {
 	gc3355_send_cmds(fd, firmware_request_cmd);
 	gc3355_send_cmds(fd, firmware_request_cmd);
 	
 	
@@ -734,17 +620,15 @@ uint32_t gc3355_get_firmware_version(int fd)
 	int read = gc3355_read(fd, buf, GC3355_READ_SIZE);
 	int read = gc3355_read(fd, buf, GC3355_READ_SIZE);
 	if (read != GC3355_READ_SIZE)
 	if (read != GC3355_READ_SIZE)
 	{
 	{
-		applog(LOG_ERR, "%s: Failed reading work from %d", GC3355_CHIP_NAME, fd);
+		applog(LOG_DEBUG, "%s: Failed reading work from %d", GC3355_CHIP_NAME, fd);
 		return -1;
 		return -1;
 	}
 	}
 	
 	
 	// firmware response begins with 55aac000 90909090
 	// firmware response begins with 55aac000 90909090
 	if (memcmp(buf, "\x55\xaa\xc0\x00\x90\x90\x90\x90", GC3355_READ_SIZE - 4) != 0)
 	if (memcmp(buf, "\x55\xaa\xc0\x00\x90\x90\x90\x90", GC3355_READ_SIZE - 4) != 0)
-	{
 		return -1;
 		return -1;
-	}
 	
 	
-	uint32_t fw_version = le32toh(*(uint32_t *)(buf + 8));
+	uint32_t fw_version = be32toh(*(uint32_t *)(buf + 8));
 	
 	
 	return fw_version;
 	return fw_version;
 }
 }

+ 11 - 15
gc3355.h

@@ -2,6 +2,7 @@
  * Copyright 2014 Nate Woolls
  * Copyright 2014 Nate Woolls
  * Copyright 2014 GridSeed Team
  * Copyright 2014 GridSeed Team
  * Copyright 2014 Dualminer Team
  * Copyright 2014 Dualminer Team
+ * Copyright 2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -26,37 +27,32 @@ int opt_pll_freq;
 
 
 // GridSeed common code begins here
 // GridSeed common code begins here
 
 
-#define GC3355_COMMAND_DELAY_MS 20
 #define GC3355_ORB_DEFAULT_CHIPS   5
 #define GC3355_ORB_DEFAULT_CHIPS   5
+#define GC3355_BLADE_DEFAULT_CHIPS	40
 #define GC3355_READ_SIZE          12
 #define GC3355_READ_SIZE          12
 
 
-struct gc3355_orb_info
+struct gc3355_info
 {
 {
 	uint16_t freq;
 	uint16_t freq;
-	int needwork;
+	unsigned chips;
 };
 };
 
 
 #define gc3355_open(path)  serial_open(path, 115200, 1, true)
 #define gc3355_open(path)  serial_open(path, 115200, 1, true)
 #define gc3355_close(fd)  serial_close(fd)
 #define gc3355_close(fd)  serial_close(fd)
 
 
-extern int gc3355_read(int fd, char *buf, size_t size);
+extern ssize_t gc3355_read(int fd, char *buf, size_t size);
 extern ssize_t gc3355_write(int fd, const void * const buf, const size_t size);
 extern ssize_t gc3355_write(int fd, const void * const buf, const size_t size);
 
 
-extern void gc3355_init_usborb(int fd, int pll_freq, bool scrypt_only, bool detect_only);
-
-extern
-void gc3355_reset_dtr(int fd);
-
-extern void gc3355_init_usbstick(int fd, int pll_freq, bool scrypt_only, bool detect_only);
+extern void gc3355_init_miner(int fd, int pll_freq);
+extern void gc3355_init_dualminer(int fd, int pll_freq, bool scrypt_only, bool detect_only);
 
 
 extern void gc3355_scrypt_reset(int fd);
 extern void gc3355_scrypt_reset(int fd);
-
-extern
-void gc3355_scrypt_only_reset(int fd);
+extern void gc3355_scrypt_only_reset(int fd);
 
 
 extern void gc3355_scrypt_prepare_work(unsigned char cmd[156], struct work *);
 extern void gc3355_scrypt_prepare_work(unsigned char cmd[156], struct work *);
-extern void gc3355_sha2_prepare_work(unsigned char cmd[52], struct work *, bool simple);
-extern uint32_t gc3355_get_firmware_version(int fd);
+extern void gc3355_sha2_prepare_work(unsigned char cmd[52], struct work *);
+
+extern int64_t gc3355_get_firmware_version(int fd);
 extern void gc3355_set_pll_freq(int fd, int pll_freq);
 extern void gc3355_set_pll_freq(int fd, int pll_freq);
 
 
 #define gc3355_get_cts_status(fd)  ((get_serial_cts(fd) == BGV_LOW) ? 1 : 0)
 #define gc3355_get_cts_status(fd)  ((get_serial_cts(fd) == BGV_LOW) ? 1 : 0)

+ 24 - 0
gen-version.sh

@@ -0,0 +1,24 @@
+#!/bin/sh
+gitdesc=
+if [ -e .git ]; then
+	# Some versions of git require `git diff` to scan and update dirty-or-not status
+	git diff >/dev/null 2>/dev/null
+	
+	gitdesc=$(git describe)
+fi
+if [ -z "$gitdesc" ]; then
+	current=$(sed 's/^\#define[[:space:]]\+BFG_GIT_DESCRIBE[[:space:]]\+\"\(.*\)\"$/\1/;t;d' version.h)
+	if [ -z "$current" ]; then
+		gitdesc='"PACKAGE_VERSION"-unknown'
+	else
+		gitdesc="$current"
+	fi
+fi
+version=$(echo "$gitdesc" | sed 's/^bfgminer-//')
+cat <<EOF
+#define BFG_GIT_DESCRIBE "$gitdesc"
+#ifdef VERSION
+#  undef VERSION
+#endif
+#define VERSION "$version"
+EOF

+ 1 - 1
hexdump.c

@@ -3,7 +3,7 @@
  * output is equal to 'hexdump -C'
  * output is equal to 'hexdump -C'
  * should be compatible to 64bit architectures
  * should be compatible to 64bit architectures
  *
  *
- * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
+ * Copyright 2009 Daniel Mack
  *
  *
  * This program is free software: you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by

+ 2 - 1
httpsrv.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -29,6 +29,7 @@
 
 
 #include "logging.h"
 #include "logging.h"
 #include "util.h"
 #include "util.h"
+#include "version.h"
 
 
 static struct MHD_Daemon *httpsrv;
 static struct MHD_Daemon *httpsrv;
 
 

+ 1 - 1
jtag.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2012 Luke Dashjr
+ * Copyright 2012-2013 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free

+ 1 - 0
libbase58

@@ -0,0 +1 @@
+Subproject commit 619e4e15e323a93b4068c42535da7be977fb3de3

+ 64 - 48
libbitfury.c

@@ -1,7 +1,7 @@
 /*
 /*
  * Copyright 2013 bitfury
  * Copyright 2013 bitfury
  * Copyright 2013 Anatoly Legkodymov
  * Copyright 2013 Anatoly Legkodymov
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * of this software and associated documentation files (the "Software"), to deal
@@ -41,7 +41,7 @@
 #define BITFURY_REFRESH_DELAY 100
 #define BITFURY_REFRESH_DELAY 100
 #define BITFURY_DETECT_TRIES 3000 / BITFURY_REFRESH_DELAY
 #define BITFURY_DETECT_TRIES 3000 / BITFURY_REFRESH_DELAY
 
 
-unsigned bitfury_decnonce(unsigned in);
+uint32_t bitfury_decnonce(uint32_t);
 
 
 /* Configuration registers - control oscillators and such stuff. PROGRAMMED when magic number is matches, UNPROGRAMMED (default) otherwise */
 /* Configuration registers - control oscillators and such stuff. PROGRAMMED when magic number is matches, UNPROGRAMMED (default) otherwise */
 static
 static
@@ -77,7 +77,7 @@ const int8_t bitfury_counters[16] = { 64, 64,
 #define S1(x) (rotrFixed(x,6)^rotrFixed(x,11)^rotrFixed(x,25))
 #define S1(x) (rotrFixed(x,6)^rotrFixed(x,11)^rotrFixed(x,25))
 
 
 /* SHA256 CONSTANTS */
 /* SHA256 CONSTANTS */
-static const unsigned SHA_K[64] = {
+static const uint32_t SHA_K[64] = {
         0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
         0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
         0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
         0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
         0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
         0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
@@ -91,20 +91,24 @@ static const unsigned SHA_K[64] = {
 
 
 
 
 static
 static
-void libbitfury_ms3_compute(unsigned *p)
+void libbitfury_ms3_compute(uint32_t *p)
 {
 {
-	unsigned a,b,c,d,e,f,g,h, ne, na,  i;
+	uint32_t cp[8];
+	uint32_t a,b,c,d,e,f,g,h, ne, na,  i;
 
 
-	a = p[0]; b = p[1]; c = p[2]; d = p[3]; e = p[4]; f = p[5]; g = p[6]; h = p[7];
+	swap32tole(cp, p, 8);
+	a = cp[0]; b = cp[1]; c = cp[2]; d = cp[3]; e = cp[4]; f = cp[5]; g = cp[6]; h = cp[7];
 
 
 	for (i = 0; i < 3; i++) {
 	for (i = 0; i < 3; i++) {
-		ne = p[i+16] + SHA_K[i] + h + Ch(e,f,g) + S1(e) + d;
-		na = p[i+16] + SHA_K[i] + h + Ch(e,f,g) + S1(e) + S0(a) + Maj(a,b,c);
+		const uint32_t x = le32toh(p[i+16]);
+		ne = x + SHA_K[i] + h + Ch(e,f,g) + S1(e) + d;
+		na = x + SHA_K[i] + h + Ch(e,f,g) + S1(e) + S0(a) + Maj(a,b,c);
 		d = c; c = b; b = a; a = na;
 		d = c; c = b; b = a; a = na;
 		h = g; g = f; f = e; e = ne;
 		h = g; g = f; f = e; e = ne;
 	}
 	}
 
 
 	p[15] = a; p[14] = b; p[13] = c; p[12] = d; p[11] = e; p[10] = f; p[9] = g; p[8] = h;
 	p[15] = a; p[14] = b; p[13] = c; p[12] = d; p[11] = e; p[10] = f; p[9] = g; p[8] = h;
+	swap32tole(&p[8], &p[8], 8);
 }
 }
 
 
 static
 static
@@ -123,20 +127,33 @@ static
 void bitfury_send_init(struct spi_port *port) {
 void bitfury_send_init(struct spi_port *port) {
 	/* Prepare internal buffers */
 	/* Prepare internal buffers */
 	/* PREPARE BUFFERS (INITIAL PROGRAMMING) */
 	/* PREPARE BUFFERS (INITIAL PROGRAMMING) */
-	unsigned w[16];
-	unsigned atrvec[] = {
-		0xb0e72d8e, 0x1dc5b862, 0xe9e7c4a6, 0x3050f1f5, 0x8a1a6b7e, 0x7ec384e8, 0x42c1c3fc, 0x8ed158a1, /* MIDSTATE */
-		0,0,0,0,0,0,0,0,
-		0x8a0bb7b7, 0x33af304f, 0x0b290c1a, 0xf0c4e61f, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
-	};
-
-	libbitfury_ms3_compute(&atrvec[0]);
-	memset(&w, 0, sizeof(w)); w[3] = 0xffffffff; w[4] = 0x80000000; w[15] = 0x00000280;
-	spi_emit_data(port, 0x1000, w, 16*4);
-	spi_emit_data(port, 0x1400, w,  8*4);
-	memset(w, 0, sizeof(w)); w[0] = 0x80000000; w[7] = 0x100;
-	spi_emit_data(port, 0x1900, &w[0],8*4); /* Prepare MS and W buffers! */
-	spi_emit_data(port, 0x3000, &atrvec[0], 19*4);
+	{
+		uint32_t w[] = {
+			0,0,0,0xffffffff,
+			0x80000000,0,0,0,
+			0,0,0,0,
+			0,0,0,0x00000280,
+		};
+		swap32tole(w, w, sizeof(w)/4);
+		spi_emit_data(port, 0x1000, w, 16*4);
+		spi_emit_data(port, 0x1400, w,  8*4);
+	}
+	{
+		uint32_t w[] = {
+			0x80000000,0,0,0,
+			0,0,0,0x100,
+		};
+		swap32tole(w, w, sizeof(w)/4);
+		spi_emit_data(port, 0x1900, &w[0],8*4); /* Prepare MS and W buffers! */
+		uint32_t atrvec[] = {
+			0xb0e72d8e, 0x1dc5b862, 0xe9e7c4a6, 0x3050f1f5, 0x8a1a6b7e, 0x7ec384e8, 0x42c1c3fc, 0x8ed158a1, /* MIDSTATE */
+			0,0,0,0,0,0,0,0,
+			0x8a0bb7b7, 0x33af304f, 0x0b290c1a, 0xf0c4e61f, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
+		};
+		libbitfury_ms3_compute(&atrvec[0]);
+		swap32tole(atrvec, atrvec, sizeof(atrvec)/4);
+		spi_emit_data(port, 0x3000, &atrvec[0], 19*4);
+	}
 }
 }
 
 
 static
 static
@@ -145,6 +162,7 @@ void bitfury_set_freq(struct spi_port *port, int bits) {
 	const uint8_t *
 	const uint8_t *
 	osc6 = (unsigned char *)&freq;
 	osc6 = (unsigned char *)&freq;
 	freq = (1ULL << bits) - 1ULL;
 	freq = (1ULL << bits) - 1ULL;
+	freq = htole64(freq);
 
 
 	spi_emit_data(port, 0x6000, osc6, 8); /* Program internal on-die slow oscillator frequency */
 	spi_emit_data(port, 0x6000, osc6, 8); /* Program internal on-die slow oscillator frequency */
 	bitfury_config_reg(port, 4, 1); /* Enable slow oscillator */
 	bitfury_config_reg(port, 4, 1); /* Enable slow oscillator */
@@ -177,16 +195,16 @@ void bitfury_send_freq(struct spi_port *port, int slot, int chip_n, int bits) {
 }
 }
 
 
 static
 static
-unsigned int libbitfury_c_diff(unsigned ocounter, unsigned counter) {
+uint32_t libbitfury_c_diff(uint32_t ocounter, uint32_t counter) {
 	return counter >  ocounter ? counter - ocounter : (0x003FFFFF - ocounter) + counter;
 	return counter >  ocounter ? counter - ocounter : (0x003FFFFF - ocounter) + counter;
 }
 }
 
 
 static
 static
-int libbitfury_get_counter(unsigned int *newbuf, unsigned int *oldbuf) {
+uint32_t libbitfury_get_counter(uint32_t *newbuf, uint32_t *oldbuf) {
 	int j;
 	int j;
 	for(j = 0; j < 16; j++) {
 	for(j = 0; j < 16; j++) {
 		if (newbuf[j] != oldbuf[j]) {
 		if (newbuf[j] != oldbuf[j]) {
-			unsigned counter = bitfury_decnonce(newbuf[j]);
+			uint32_t counter = bitfury_decnonce(newbuf[j]);
 			if ((counter & 0xFFC00000) == 0xdf800000) {
 			if ((counter & 0xFFC00000) == 0xdf800000) {
 				counter -= 0xdf800000;
 				counter -= 0xdf800000;
 				return counter;
 				return counter;
@@ -199,7 +217,7 @@ int libbitfury_get_counter(unsigned int *newbuf, unsigned int *oldbuf) {
 static
 static
 int libbitfury_detect_chip(struct spi_port *port, int chip_n) {
 int libbitfury_detect_chip(struct spi_port *port, int chip_n) {
 	/* Test vectors to calculate (using address-translated loads) */
 	/* Test vectors to calculate (using address-translated loads) */
-	unsigned atrvec[] = {
+	uint32_t atrvec[] = {
 		0xb0e72d8e, 0x1dc5b862, 0xe9e7c4a6, 0x3050f1f5, 0x8a1a6b7e, 0x7ec384e8, 0x42c1c3fc, 0x8ed158a1, /* MIDSTATE */
 		0xb0e72d8e, 0x1dc5b862, 0xe9e7c4a6, 0x3050f1f5, 0x8a1a6b7e, 0x7ec384e8, 0x42c1c3fc, 0x8ed158a1, /* MIDSTATE */
 		0,0,0,0,0,0,0,0,
 		0,0,0,0,0,0,0,0,
 		0x8a0bb7b7, 0x33af304f, 0x0b290c1a, 0xf0c4e61f, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
 		0x8a0bb7b7, 0x33af304f, 0x0b290c1a, 0xf0c4e61f, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
@@ -221,9 +239,9 @@ int libbitfury_detect_chip(struct spi_port *port, int chip_n) {
 		0x6f3806c3, 0x41f82a4f, 0x3fd40c1a, 0x00334b39, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
 		0x6f3806c3, 0x41f82a4f, 0x3fd40c1a, 0x00334b39, /* WDATA: hashMerleRoot[7], nTime, nBits, nNonce */
 	};
 	};
 	int i;
 	int i;
-	unsigned newbuf[17], oldbuf[17];
-	unsigned ocounter;
-	int odiff = 0;
+	uint32_t newbuf[17] = {0}, oldbuf[17] = {0};
+	uint32_t ocounter;
+	long odiff = 0;
 
 
 	memset(newbuf, 0, 17 * 4);
 	memset(newbuf, 0, 17 * 4);
 	memset(oldbuf, 0, 17 * 4);
 	memset(oldbuf, 0, 17 * 4);
@@ -231,6 +249,8 @@ int libbitfury_detect_chip(struct spi_port *port, int chip_n) {
 	libbitfury_ms3_compute(&atrvec[0]);
 	libbitfury_ms3_compute(&atrvec[0]);
 	libbitfury_ms3_compute(&atrvec[20]);
 	libbitfury_ms3_compute(&atrvec[20]);
 	libbitfury_ms3_compute(&atrvec[40]);
 	libbitfury_ms3_compute(&atrvec[40]);
+	
+	swap32tole(atrvec, atrvec, sizeof(atrvec)/4);
 
 
 
 
 	spi_clear_buf(port);
 	spi_clear_buf(port);
@@ -250,11 +270,11 @@ int libbitfury_detect_chip(struct spi_port *port, int chip_n) {
 		spi_emit_fasync(port, chip_n);
 		spi_emit_fasync(port, chip_n);
 		spi_emit_data(port, 0x3000, &atrvec[0], 19*4);
 		spi_emit_data(port, 0x3000, &atrvec[0], 19*4);
 		spi_txrx(port);
 		spi_txrx(port);
-		memcpy(newbuf, spi_getrxbuf(port) + 4 + chip_n, 17*4);
+		swap32tole(newbuf, spi_getrxbuf(port) + 4 + chip_n, 17);
 
 
 		counter = libbitfury_get_counter(newbuf, oldbuf);
 		counter = libbitfury_get_counter(newbuf, oldbuf);
 		if (ocounter) {
 		if (ocounter) {
-			unsigned int cdiff = libbitfury_c_diff(ocounter, counter);
+			uint32_t cdiff = libbitfury_c_diff(ocounter, counter);
 
 
 			if (abs(odiff - cdiff) < 5000)
 			if (abs(odiff - cdiff) < 5000)
 				return 1;
 				return 1;
@@ -278,9 +298,9 @@ int libbitfury_detectChips1(struct spi_port *port) {
 }
 }
 
 
 // in  = 1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10  f  e  d  c  b  a  9  8  7  6  5  4  3  2  1  0
 // in  = 1f 1e 1d 1c 1b 1a 19 18 17 16 15 14 13 12 11 10  f  e  d  c  b  a  9  8  7  6  5  4  3  2  1  0
-unsigned bitfury_decnonce(unsigned in)
+uint32_t bitfury_decnonce(uint32_t in)
 {
 {
-	unsigned out;
+	uint32_t out;
 
 
 	/* First part load */
 	/* First part load */
 	out = (in & 0xFF) << 24; in >>= 8;
 	out = (in & 0xFF) << 24; in >>= 8;
@@ -303,14 +323,14 @@ unsigned bitfury_decnonce(unsigned in)
 
 
 static
 static
 int libbitfury_rehash(const void *midstate, const uint32_t m7, const uint32_t ntime, const uint32_t nbits, uint32_t nnonce) {
 int libbitfury_rehash(const void *midstate, const uint32_t m7, const uint32_t ntime, const uint32_t nbits, uint32_t nnonce) {
-	unsigned char in[16];
-	unsigned int *in32 = (unsigned int *)in;
-	unsigned int *mid32 = (unsigned int *)midstate;
-	unsigned out32[8];
-	unsigned char *out = (unsigned char *) out32;
+	uint8_t in[16];
+	uint32_t *in32 = (uint32_t *)in;
+	const uint32_t *mid32 = midstate;
+	uint32_t out32[8];
+	uint8_t *out = (uint8_t *) out32;
 #ifdef BITFURY_REHASH_DEBUG
 #ifdef BITFURY_REHASH_DEBUG
-	static unsigned history[512];
-	static unsigned history_p;
+	static uint32_t history[512];
+	static uint32_t history_p;
 #endif
 #endif
 	sha256_ctx ctx;
 	sha256_ctx ctx;
 
 
@@ -320,11 +340,10 @@ int libbitfury_rehash(const void *midstate, const uint32_t m7, const uint32_t nt
 	ctx.tot_len = 64;
 	ctx.tot_len = 64;
 	ctx.len = 0;
 	ctx.len = 0;
 
 
-	nnonce = bswap_32(nnonce);
 	in32[0] = bswap_32(m7);
 	in32[0] = bswap_32(m7);
 	in32[1] = bswap_32(ntime);
 	in32[1] = bswap_32(ntime);
 	in32[2] = bswap_32(nbits);
 	in32[2] = bswap_32(nbits);
-	in32[3] = nnonce;
+	in32[3] = bswap_32(nnonce);
 
 
 	sha256_update(&ctx, in, 16);
 	sha256_update(&ctx, in, 16);
 	sha256_final(&ctx, out);
 	sha256_final(&ctx, out);
@@ -362,15 +381,12 @@ bool bitfury_fudge_nonce(const void *midstate, const uint32_t m7, const uint32_t
 }
 }
 
 
 void work_to_bitfury_payload(struct bitfury_payload *p, struct work *w) {
 void work_to_bitfury_payload(struct bitfury_payload *p, struct work *w) {
-	unsigned char flipped_data[80];
-
 	memset(p, 0, sizeof(struct bitfury_payload));
 	memset(p, 0, sizeof(struct bitfury_payload));
-	swap32yes(flipped_data, w->data, 80 / 4);
 
 
 	memcpy(p->midstate, w->midstate, 32);
 	memcpy(p->midstate, w->midstate, 32);
-	p->m7 = bswap_32(*(unsigned *)(flipped_data + 64));
-	p->ntime = bswap_32(*(unsigned *)(flipped_data + 68));
-	p->nbits = bswap_32(*(unsigned *)(flipped_data + 72));
+	p->m7 = *(uint32_t *)&w->data[0x40];
+	p->ntime = *(uint32_t *)&w->data[0x44];
+	p->nbits = *(uint32_t *)&w->data[0x48];
 }
 }
 
 
 void bitfury_payload_to_atrvec(uint32_t *atrvec, struct bitfury_payload *p)
 void bitfury_payload_to_atrvec(uint32_t *atrvec, struct bitfury_payload *p)

+ 12 - 12
libbitfury.h

@@ -12,12 +12,12 @@ struct work;
 #define BITFURY_STAT_N 1024
 #define BITFURY_STAT_N 1024
 
 
 struct bitfury_payload {
 struct bitfury_payload {
-	unsigned char midstate[32];
-	unsigned int junk[8];
-	unsigned m7;
-	unsigned ntime;
-	unsigned nbits;
-	unsigned nnonce;
+	uint8_t midstate[32];
+	uint32_t junk[8];
+	uint32_t m7;
+	uint32_t ntime;
+	uint32_t nbits;
+	uint32_t nnonce;
 };
 };
 
 
 struct freq_stat {
 struct freq_stat {
@@ -33,9 +33,9 @@ struct freq_stat {
 
 
 struct bitfury_device {
 struct bitfury_device {
 	struct spi_port *spi;
 	struct spi_port *spi;
-	unsigned char osc6_bits;
-	unsigned newbuf[17];
-	unsigned oldbuf[17];
+	uint8_t osc6_bits;
+	uint32_t newbuf[17];
+	uint32_t oldbuf[17];
 	bool oldjob;
 	bool oldjob;
 	int active;
 	int active;
 	int chipgen;
 	int chipgen;
@@ -45,11 +45,11 @@ struct bitfury_device {
 	struct freq_stat chip_stat;
 	struct freq_stat chip_stat;
 	struct timeval timer1;
 	struct timeval timer1;
 	struct timeval tv_stat;
 	struct timeval tv_stat;
-	unsigned int counter1, counter2;
+	uint32_t counter1, counter2;
 	double mhz;
 	double mhz;
 	int mhz_last;
 	int mhz_last;
 	int mhz_best;
 	int mhz_best;
-	unsigned slot;
+	uint32_t slot;
 	unsigned fasync;
 	unsigned fasync;
 	unsigned strange_counter;
 	unsigned strange_counter;
 	bool force_reinit;
 	bool force_reinit;
@@ -64,7 +64,7 @@ extern void bitfury_send_reinit(struct spi_port *, int slot, int chip_n, int n);
 extern void bitfury_send_shutdown(struct spi_port *, int slot, int chip_n);
 extern void bitfury_send_shutdown(struct spi_port *, int slot, int chip_n);
 extern void bitfury_send_freq(struct spi_port *, int slot, int chip_n, int bits);
 extern void bitfury_send_freq(struct spi_port *, int slot, int chip_n, int bits);
 extern int libbitfury_detectChips1(struct spi_port *);
 extern int libbitfury_detectChips1(struct spi_port *);
-extern unsigned bitfury_decnonce(unsigned);
+extern uint32_t bitfury_decnonce(uint32_t);
 extern bool bitfury_fudge_nonce(const void *midstate, const uint32_t m7, const uint32_t ntime, const uint32_t nbits, uint32_t *nonce_p);
 extern bool bitfury_fudge_nonce(const void *midstate, const uint32_t m7, const uint32_t ntime, const uint32_t nbits, uint32_t *nonce_p);
 
 
 #endif /* __LIBBITFURY_H__ */
 #endif /* __LIBBITFURY_H__ */

+ 1 - 1
libblkmaker

@@ -1 +1 @@
-Subproject commit 385f2ddd7c11532d73175009d864dc646596c554
+Subproject commit d46062c7e66bd57e5e2640c4289c127c150bb495

+ 7 - 3
logging.c

@@ -1,6 +1,6 @@
 /*
 /*
- * Copyright 2011-2012 Con Kolivas
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2011-2013 Con Kolivas
+ * Copyright 2012-2014 Luke Dashjr
  * Copyright 2013 Andrew Smith
  * Copyright 2013 Andrew Smith
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
@@ -34,7 +34,11 @@ static void _my_log_curses(int prio, const char *datetime, const char *str)
 		;
 		;
 	else
 	else
 #endif
 #endif
-		printf(" %s %s%s", datetime, str, "                    \n");
+	{
+		last_logstatusline_len = -1;
+		printf("\n %s %s\r", datetime, str);
+		fflush(stdout);
+	}
 }
 }
 
 
 /* high-level logging function, based on global opt_log_level */
 /* high-level logging function, based on global opt_log_level */

+ 25 - 3
logging.h

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  * Copyright 2012 zefir
  * Copyright 2012 zefir
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
@@ -43,6 +43,11 @@ extern bool want_per_device_stats;
 /* global log_level, messages with lower or equal prio are logged */
 /* global log_level, messages with lower or equal prio are logged */
 extern int opt_log_level;
 extern int opt_log_level;
 
 
+#define return_via(label, stmt)  do {  \
+	stmt;  \
+	goto label;  \
+} while (0)
+
 #define LOGBUFSIZ 0x1000
 #define LOGBUFSIZ 0x1000
 
 
 extern void _applog(int prio, const char *str);
 extern void _applog(int prio, const char *str);
@@ -70,6 +75,12 @@ extern void _applog(int prio, const char *str);
 	return rv;  \
 	return rv;  \
 } while (0)
 } while (0)
 
 
+#define return_via_applog(label, expr, prio, ...)  do {  \
+	applog(prio, __VA_ARGS__);  \
+	expr;  \
+	goto label;  \
+} while (0)
+
 #define appperror(prio, s)  do {  \
 #define appperror(prio, s)  do {  \
 	const char *_tmp43 = bfg_strerror(errno, BST_ERRNO);  \
 	const char *_tmp43 = bfg_strerror(errno, BST_ERRNO);  \
 	if (s && s[0])  \
 	if (s && s[0])  \
@@ -92,6 +103,12 @@ extern void _applog(int prio, const char *str);
 	return rv;  \
 	return rv;  \
 } while (0)
 } while (0)
 
 
+#define return_via_applogfailinfo(label, expr, prio, failed, fmt, ...)  do {  \
+	applogfailinfo(prio, failed, fmt, __VA_ARGS__);  \
+	expr;  \
+	goto label;  \
+} while (0)
+
 #define applogfail(prio, failed)  do {  \
 #define applogfail(prio, failed)  do {  \
 	applog(prio, "Failed to %s"IN_FMT_FFL,  \
 	applog(prio, "Failed to %s"IN_FMT_FFL,  \
 	       failed,  \
 	       failed,  \
@@ -103,14 +120,19 @@ extern void _applog(int prio, const char *str);
 	return rv;  \
 	return rv;  \
 } while (0)
 } while (0)
 
 
+#define return_via_applogfail(label, expr, prio, failed)  do {  \
+	applogfail(prio, failed);  \
+	expr;  \
+	goto label;  \
+} while (0)
+
 extern void _bfg_clean_up(bool);
 extern void _bfg_clean_up(bool);
 
 
 #define quit(status, fmt, ...) do { \
 #define quit(status, fmt, ...) do { \
 	_bfg_clean_up(false);  \
 	_bfg_clean_up(false);  \
 	if (fmt) { \
 	if (fmt) { \
-		fprintf(stderr, fmt, ##__VA_ARGS__);  \
+		fprintf(stderr, "\n" fmt, ##__VA_ARGS__);  \
 	} \
 	} \
-	fprintf(stderr, "\n");  \
 	fflush(stderr);  \
 	fflush(stderr);  \
 	_quit(status); \
 	_quit(status); \
 } while (0)
 } while (0)

+ 1 - 0
lowl-ftdi.c

@@ -251,6 +251,7 @@ void ft232r_close(struct ft232r_device_handle *dev)
 	libusb_release_interface(dev->h, 0);
 	libusb_release_interface(dev->h, 0);
 	libusb_reset_device(dev->h);
 	libusb_reset_device(dev->h);
 	libusb_close(dev->h);
 	libusb_close(dev->h);
+	free(dev);
 }
 }
 
 
 bool ft232r_purge_buffers(struct ft232r_device_handle *dev, enum ft232r_reset_purge purge)
 bool ft232r_purge_buffers(struct ft232r_device_handle *dev, enum ft232r_reset_purge purge)

+ 92 - 0
lowl-mswin.c

@@ -0,0 +1,92 @@
+/*
+ * Copyright 2014 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 <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <objbase.h>
+#include <rpc.h>
+#include <setupapi.h>
+#include <utlist.h>
+
+#include "logging.h"
+#include "lowlevel.h"
+#include "lowl-mswin.h"
+#include "util.h"
+
+static
+struct lowlevel_device_info *mswin_devinfo_scan()
+{
+	struct lowlevel_device_info *devinfo_list = NULL, *info;
+	
+	HDEVINFO devinfo = SetupDiGetClassDevs(NULL, NULL, NULL, (DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
+	if (INVALID_HANDLE_VALUE == devinfo)
+		applogfailinfor(NULL, LOG_DEBUG, "SetupDiGetClassDevs", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+	
+	SP_DEVINFO_DATA devinfodata = {
+		.cbSize = sizeof(devinfodata),
+	};
+	SP_DEVICE_INTERFACE_DATA devifacedata = {
+		.cbSize = sizeof(devifacedata),
+	};
+	for (int i = 0; SetupDiEnumDeviceInfo(devinfo, i, &devinfodata); ++i)
+	{
+		// FIXME: Figure out a way to get all GUIDs here
+		if (!SetupDiEnumDeviceInterfaces(devinfo, &devinfodata, &WIN_GUID_DEVINTERFACE_MonarchKMDF, 0, &devifacedata))
+		{
+			applogfailinfo(LOG_DEBUG, "SetupDiEnumDeviceInterfaces", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+			continue;
+		}
+		DWORD detailsz;
+		if (!(!SetupDiGetDeviceInterfaceDetail(devinfo, &devifacedata, NULL, 0, &detailsz, NULL) && GetLastError() == ERROR_INSUFFICIENT_BUFFER))
+		{
+			applogfailinfo(LOG_ERR, "SetupDiEnumDeviceInterfaceDetail (1)", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+			continue;
+		}
+		PSP_DEVICE_INTERFACE_DETAIL_DATA detail = alloca(detailsz);
+		detail->cbSize = sizeof(*detail);
+		if (!SetupDiGetDeviceInterfaceDetail(devinfo, &devifacedata, detail, detailsz, &detailsz, NULL))
+		{
+			applogfailinfo(LOG_ERR, "SetupDiEnumDeviceInterfaceDetail (2)", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+			continue;
+		}
+		
+		char *devid = malloc(6 + strlen(detail->DevicePath) + 1);
+		sprintf(devid, "mswin:%s", detail->DevicePath);
+		
+		info = malloc(sizeof(struct lowlevel_device_info));
+		*info = (struct lowlevel_device_info){
+			.lowl = &lowl_mswin,
+			.devid = devid,
+			.path = strdup(detail->DevicePath),
+			.lowl_data = (void *)&WIN_GUID_DEVINTERFACE_MonarchKMDF,
+		};
+		LL_PREPEND(devinfo_list, info);
+	}
+	
+	SetupDiDestroyDeviceInfoList(devinfo);
+	
+	return devinfo_list;
+}
+
+bool lowl_mswin_match_guid(const struct lowlevel_device_info * const info, const GUID * const guid)
+{
+	if (info->lowl != &lowl_mswin)
+		return false;
+	return IsEqualGUID(info->lowl_data, guid);
+}
+
+struct lowlevel_driver lowl_mswin = {
+	.dname = "mswin",
+	.devinfo_scan = mswin_devinfo_scan,
+};

+ 12 - 0
lowl-mswin.h

@@ -0,0 +1,12 @@
+#ifndef BFG_LOWL_MSWIN_H
+#define BFG_LOWL_MSWIN_H
+
+#include <stdbool.h>
+
+#include <rpc.h>
+
+static const GUID WIN_GUID_DEVINTERFACE_MonarchKMDF = { 0xdcdb8d6f, 0x98b0, 0x4d1c, {0xa2, 0x77, 0x71, 0x17, 0x69, 0x70, 0x54, 0x31} };
+
+extern bool lowl_mswin_match_guid(const struct lowlevel_device_info *, const GUID *);
+
+#endif

+ 12 - 7
lowl-pci.c

@@ -102,7 +102,7 @@ struct lowl_pci_handle {
 	off_t baroff[6];
 	off_t baroff[6];
 #endif
 #endif
 #ifdef USE_LOWL_PCI_MMAP
 #ifdef USE_LOWL_PCI_MMAP
-	uint32_t *bar[6];
+	volatile uint32_t *bar[6];
 	size_t barsz[6];
 	size_t barsz[6];
 #endif
 #endif
 };
 };
@@ -113,20 +113,24 @@ void lowl_pci_close_mmap(struct lowl_pci_handle * const lph)
 {
 {
 	for (int i = 0; i < 6; ++i)
 	for (int i = 0; i < 6; ++i)
 		if (lph->bar[i])
 		if (lph->bar[i])
-			munmap(lph->bar[i], lph->barsz[i]);
+			munmap((void*)lph->bar[i], lph->barsz[i]);
 	free(lph);
 	free(lph);
 }
 }
 
 
 static
 static
 const uint32_t *lowl_pci_get_words_mmap(struct lowl_pci_handle * const lph, void * const buf, const size_t words, const int bar, const off_t offset)
 const uint32_t *lowl_pci_get_words_mmap(struct lowl_pci_handle * const lph, void * const buf, const size_t words, const int bar, const off_t offset)
 {
 {
-	return &lph->bar[bar][offset];
+	volatile uint32_t *src = &lph->bar[bar][offset];
+	uint32_t *dest = buf;
+	for (int i = 0; i < words; ++i)
+		*(dest++) = *(src++);
+	return buf;
 }
 }
 
 
 static
 static
 bool lowl_pci_set_words_mmap(struct lowl_pci_handle * const lph, const uint32_t *buf, const size_t words, const int bar, const off_t offset)
 bool lowl_pci_set_words_mmap(struct lowl_pci_handle * const lph, const uint32_t *buf, const size_t words, const int bar, const off_t offset)
 {
 {
-	uint32_t *dest = &lph->bar[bar][offset];
+	volatile uint32_t *dest = &lph->bar[bar][offset];
 	for (int i = 0; i < words; ++i)
 	for (int i = 0; i < words; ++i)
 		*(dest++) = *(buf++);
 		*(dest++) = *(buf++);
 	return true;
 	return true;
@@ -158,7 +162,7 @@ const void *lowl_pci_get_data_from_words(struct lowl_pci_handle * const lph, voi
 	const off_t offset8  = offset % 4;
 	const off_t offset8  = offset % 4;
 	const size_t words = (sz + offset8 + 3) / 4;
 	const size_t words = (sz + offset8 + 3) / 4;
 	const uint32_t * const wdata = lowl_pci_get_words(lph, buf, words, bar, offset32);
 	const uint32_t * const wdata = lowl_pci_get_words(lph, buf, words, bar, offset32);
-	swap32tobe(buf, wdata, words);
+	swap32tobe((uint32_t *)buf, wdata, words);
 	return &buf[offset8];
 	return &buf[offset8];
 }
 }
 
 
@@ -242,7 +246,7 @@ struct lowl_pci_handle *lowl_pci_open_uio(const char * const path, const struct
 err:
 err:
 	for (int i = 0; i < 6; ++i)
 	for (int i = 0; i < 6; ++i)
 		if (lph->bar[i])
 		if (lph->bar[i])
-			munmap(lph->bar[i], lph->barsz[i]);
+			munmap((void*)lph->bar[i], lph->barsz[i]);
 	free(lph);
 	free(lph);
 	return NULL;
 	return NULL;
 }
 }
@@ -396,7 +400,7 @@ struct lowl_pci_handle *lowl_pci_open_vfio(const char * const path, const struct
 err:
 err:
 	for (int i = 0; i < 6; ++i)
 	for (int i = 0; i < 6; ++i)
 		if (lph->bar[i])
 		if (lph->bar[i])
-			munmap(lph->bar[i], lph->barsz[i]);
+			munmap((void*)lph->bar[i], lph->barsz[i]);
 	if (device != -1)
 	if (device != -1)
 		close(device);
 		close(device);
 	if (group != -1)
 	if (group != -1)
@@ -490,4 +494,5 @@ void lowl_pci_close(struct lowl_pci_handle * const lph)
 struct lowlevel_driver lowl_pci = {
 struct lowlevel_driver lowl_pci = {
 	.dname = "pci",
 	.dname = "pci",
 	.devinfo_scan = pci_devinfo_scan,
 	.devinfo_scan = pci_devinfo_scan,
+	.exclude_from_all = true,
 };
 };

+ 70 - 14
lowl-spi.c

@@ -1,6 +1,6 @@
 /*
 /*
  * Copyright 2013 bitfury
  * Copyright 2013 bitfury
- * Copyright 2013 Luke Dashjr
+ * Copyright 2013-2014 Luke Dashjr
  *
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * of this software and associated documentation files (the "Software"), to deal
@@ -85,12 +85,52 @@ void spi_init(void)
 
 
 #ifdef HAVE_LINUX_SPI
 #ifdef HAVE_LINUX_SPI
 
 
+int spi_open(struct spi_port * const spi, const char * const devpath)
+{
+	const int fd = open(devpath, O_RDWR);
+	if (fd < 0)
+		return fd;
+	
+	if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &spi->speed) < 0
+	 || ioctl(fd, SPI_IOC_WR_MODE, &spi->mode) < 0
+	 || ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &spi->bits) < 0)
+	{
+		close(fd);
+		return -1;
+	}
+	
+	spi->fd = fd;
+	return fd;
+}
+
 #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
 #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
 #define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
 #define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
 #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
 #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
 
 
 #define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
 #define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
 #define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
 #define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
+#define GPIO_LEV *(gpio+13)
+
+void bfg_gpio_setpin_output(const unsigned pin)
+{
+	INP_GPIO(pin);
+	OUT_GPIO(pin);
+}
+
+void bfg_gpio_set_high(const unsigned mask)
+{
+	GPIO_SET = mask;
+}
+
+void bfg_gpio_set_low(const unsigned mask)
+{
+	GPIO_CLR = mask;
+}
+
+unsigned bfg_gpio_get()
+{
+	return GPIO_LEV;
+}
 
 
 // Bit-banging reset, to reset more chips in chain - toggle for longer period... Each 3 reset cycles reset first chip in chain
 // Bit-banging reset, to reset more chips in chain - toggle for longer period... Each 3 reset cycles reset first chip in chain
 static
 static
@@ -196,6 +236,23 @@ bool sys_spi_txrx(struct spi_port *port)
 	return true;
 	return true;
 }
 }
 
 
+bool linux_spi_txrx(struct spi_port * const spi)
+{
+	const void * const wrbuf = spi_gettxbuf(spi);
+	void * const rdbuf = spi_getrxbuf(spi);
+	const size_t bufsz = spi_getbufsz(spi);
+	const int fd = spi->fd;
+	struct spi_ioc_transfer xf = {
+		.tx_buf = (uintptr_t) wrbuf,
+		.rx_buf = (uintptr_t) rdbuf,
+		.len = bufsz,
+		.delay_usecs = spi->delay,
+		.speed_hz = spi->speed,
+		.bits_per_word = spi->bits,
+	};
+	return (ioctl(fd, SPI_IOC_MESSAGE(1), &xf) > 0);
+}
+
 #endif
 #endif
 
 
 static
 static
@@ -208,11 +265,7 @@ void *spi_emit_buf_reverse(struct spi_port *port, const void *p, size_t sz)
 	for (size_t i = 0; i < sz; ++i)
 	for (size_t i = 0; i < sz; ++i)
 	{
 	{
 		// Reverse bit order in each byte!
 		// Reverse bit order in each byte!
-		unsigned char p = str[i];
-		p = ((p & 0xaa)>>1) | ((p & 0x55) << 1);
-		p = ((p & 0xcc)>>2) | ((p & 0x33) << 2);
-		p = ((p & 0xf0)>>4) | ((p & 0x0f) << 4);
-		port->spibuf[port->spibufsz++] = p;
+		port->spibuf[port->spibufsz++] = bitflip8(str[i]);
 	}
 	}
 	return rv;
 	return rv;
 }
 }
@@ -273,17 +326,20 @@ void spi_bfsb_select_bank(int bank)
 	int i;
 	int i;
 	for(i=0;i<4;i++)
 	for(i=0;i<4;i++)
 	{
 	{
+		if (i == bank)
+			continue;
+		
 		INP_GPIO(banks[i]);
 		INP_GPIO(banks[i]);
 		OUT_GPIO(banks[i]);
 		OUT_GPIO(banks[i]);
-		if(i==bank)
-		{
-			GPIO_SET = 1 << banks[i]; // enable bank
-		} 
-		else
-		{
-			GPIO_CLR = 1 << banks[i];// disable bank
-		}
+		GPIO_CLR = 1 << banks[i];
 	}
 	}
+	
+	if (bank != -1)
+	{
+		OUT_GPIO(banks[bank]);
+		GPIO_SET = 1 << banks[bank];
+	}
+	
 	last_bank = bank;
 	last_bank = bank;
 }
 }
 #endif
 #endif

+ 11 - 0
lowl-spi.h

@@ -10,6 +10,13 @@
 /* Initialize SPI using this function */
 /* Initialize SPI using this function */
 void spi_init(void);
 void spi_init(void);
 
 
+#ifdef HAVE_LINUX_SPI_SPIDEV_H
+extern void bfg_gpio_setpin_output(unsigned pin);
+extern void bfg_gpio_set_high(unsigned mask);
+extern void bfg_gpio_set_low(unsigned mask);
+extern unsigned bfg_gpio_get();
+#endif
+
 /* Do not allocate spi_port on the stack! OS X, at least, has a 512 KB default stack size for secondary threads
 /* Do not allocate spi_port on the stack! OS X, at least, has a 512 KB default stack size for secondary threads
    This includes struct assignments which get allocated on the stack before being assigned to */
    This includes struct assignments which get allocated on the stack before being assigned to */
 struct spi_port {
 struct spi_port {
@@ -29,6 +36,8 @@ struct spi_port {
 	uint16_t delay;
 	uint16_t delay;
 	uint8_t mode;
 	uint8_t mode;
 	uint8_t bits;
 	uint8_t bits;
+	int chipselect;
+	int *chipselect_current;
 };
 };
 
 
 extern struct spi_port *sys_spi;
 extern struct spi_port *sys_spi;
@@ -79,7 +88,9 @@ bool spi_txrx(struct spi_port *port)
 	return port->txrx(port);
 	return port->txrx(port);
 }
 }
 
 
+extern int spi_open(struct spi_port *, const char *);
 extern bool sys_spi_txrx(struct spi_port *);
 extern bool sys_spi_txrx(struct spi_port *);
+extern bool linux_spi_txrx(struct spi_port *);
 
 
 void spi_bfsb_select_bank(int bank);
 void spi_bfsb_select_bank(int bank);
 
 

+ 1 - 1
lowl-usb.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free

+ 138 - 1
lowl-vcom.c

@@ -1,8 +1,9 @@
 /*
 /*
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2014 Luke Dashjr
  * Copyright 2013 Con Kolivas
  * Copyright 2013 Con Kolivas
  * Copyright 2012 Andrew Smith
  * Copyright 2012 Andrew Smith
  * Copyright 2013 Xiangfu
  * Copyright 2013 Xiangfu
+ * Copyright 2014 Nate Woolls
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -78,6 +79,12 @@ enum {
 #include <sys/ioctl.h>
 #include <sys/ioctl.h>
 #endif
 #endif
 
 
+#ifdef __APPLE__
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/usb/IOUSBLib.h>
+#endif
+
 #include "logging.h"
 #include "logging.h"
 #include "lowlevel.h"
 #include "lowlevel.h"
 #include "miner.h"
 #include "miner.h"
@@ -187,6 +194,115 @@ void _vcom_devinfo_scan_udev(struct lowlevel_device_info ** const devinfo_list)
 }
 }
 #endif
 #endif
 
 
+#ifdef __APPLE__
+static
+const char * _iokit_get_string_descriptor(IOUSBDeviceInterface300 ** const usb_device, const uint8_t string_idx)
+{
+	UInt16 buf[64];
+	IOUSBDevRequest dev_req;
+
+	dev_req.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+	dev_req.bRequest = kUSBRqGetDescriptor;
+	dev_req.wValue = (kUSBStringDesc << 8) | string_idx;
+	dev_req.wIndex = 0x409; //English
+	dev_req.wLength = sizeof(buf);
+	dev_req.pData = buf;
+
+	kern_return_t kret = (*usb_device)->DeviceRequest(usb_device, &dev_req);
+	if (kret != 0)
+		return NULL;
+
+	size_t str_len = (dev_req.wLenDone / 2) - 1;
+
+	return ucs2_to_utf8_dup(&buf[1], str_len);
+}
+
+static
+IOUSBDeviceInterface300 ** _iokit_get_service_device(const io_service_t usb_svc)
+{
+	IOCFPlugInInterface ** plugin;
+	SInt32 score;
+	IOUSBDeviceInterface300 ** usb_device;
+
+	IOCreatePlugInInterfaceForService(usb_svc, kIOUSBDeviceUserClientTypeID,
+									  kIOCFPlugInInterfaceID, &plugin, &score);
+	(*plugin)->QueryInterface(plugin,
+							  CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID300),
+							  (LPVOID)&usb_device);
+	(*plugin)->Release(plugin);
+
+	return usb_device;
+}
+
+static
+bool _iokit_get_device_path(const io_service_t usb_svc, char * const buf, const size_t buf_len)
+{
+	CFTypeRef dev_path_cf = IORegistryEntrySearchCFProperty(usb_svc, kIOServicePlane, CFSTR("IOCalloutDevice"),
+															kCFAllocatorDefault, kIORegistryIterateRecursively);
+	if (dev_path_cf)
+	{
+		CFStringGetCString(dev_path_cf, buf, buf_len, kCFStringEncodingASCII);
+		CFRelease(dev_path_cf);
+
+		return true;
+	}
+
+	return false;
+}
+
+static
+void _vcom_devinfo_scan_iokit_service(struct lowlevel_device_info ** const devinfo_list, const io_service_t usb_svc)
+{
+	IOUSBDeviceInterface300 ** usb_device = _iokit_get_service_device(usb_svc);
+
+	char dev_path[PATH_MAX];
+	if (_iokit_get_device_path(usb_svc, dev_path, PATH_MAX))
+	{
+		UInt8 manuf_idx;
+		UInt8 prod_idx;
+		UInt8 serialno_idx;
+
+		(*usb_device)->USBGetManufacturerStringIndex(usb_device, &manuf_idx);
+		(*usb_device)->USBGetProductStringIndex(usb_device, &prod_idx);
+		(*usb_device)->USBGetSerialNumberStringIndex(usb_device, &serialno_idx);
+
+		const char * dev_manuf = _iokit_get_string_descriptor(usb_device, manuf_idx);
+		const char * dev_product = _iokit_get_string_descriptor(usb_device, prod_idx);
+		const char * dev_serial = _iokit_get_string_descriptor(usb_device, serialno_idx);
+
+		struct lowlevel_device_info *devinfo;
+		devinfo = _vcom_devinfo_findorcreate(devinfo_list, dev_path);
+
+		BFGINIT(devinfo->manufacturer, (char *)dev_manuf);
+		BFGINIT(devinfo->product, (char *)dev_product);
+		BFGINIT(devinfo->serial, (char *)dev_serial);
+	}
+}
+
+static
+void _vcom_devinfo_scan_iokit(struct lowlevel_device_info ** const devinfo_list)
+{
+	CFMutableDictionaryRef matching_dict = IOServiceMatching(kIOUSBDeviceClassName);
+	if (matching_dict == NULL)
+		return;
+
+	io_iterator_t iterator;
+	kern_return_t kret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dict, &iterator);
+	if (kret != KERN_SUCCESS)
+		return;
+
+	io_service_t usb_svc;
+	while ((usb_svc = IOIteratorNext(iterator)))
+	{
+		_vcom_devinfo_scan_iokit_service(devinfo_list, usb_svc);
+
+		IOObjectRelease(usb_svc);
+	}
+
+	IOObjectRelease(iterator);
+}
+#endif
+
 #ifndef WIN32
 #ifndef WIN32
 static
 static
 void _vcom_devinfo_scan_devserial(struct lowlevel_device_info ** const devinfo_list)
 void _vcom_devinfo_scan_devserial(struct lowlevel_device_info ** const devinfo_list)
@@ -684,6 +800,7 @@ bool vcom_lowl_probe_wrapper(const struct lowlevel_device_info * const info, det
 				bfg_need_detect_rescan = true;
 				bfg_need_detect_rescan = true;
 		}
 		}
 #endif
 #endif
+		bfg_probe_result_flags = BPR_WRONG_DEVTYPE;
 		return false;
 		return false;
 	}
 	}
 	detectone_meta_info = (struct detectone_meta_info_t){
 	detectone_meta_info = (struct detectone_meta_info_t){
@@ -757,6 +874,9 @@ struct lowlevel_device_info *vcom_devinfo_scan()
 #endif
 #endif
 #ifdef HAVE_LIBUDEV
 #ifdef HAVE_LIBUDEV
 	_vcom_devinfo_scan_udev(&devinfo_hash);
 	_vcom_devinfo_scan_udev(&devinfo_hash);
+#endif
+#ifdef __APPLE__
+	_vcom_devinfo_scan_iokit(&devinfo_hash);
 #endif
 #endif
 	// Missing Manufacturer:
 	// Missing Manufacturer:
 #ifdef WIN32
 #ifdef WIN32
@@ -936,6 +1056,23 @@ bool valid_baud(int baud)
 	}
 	}
 }
 }
 
 
+bool vcom_set_timeout(const int fdDev, const uint8_t timeout)
+{
+#ifdef WIN32
+	const HANDLE hSerial = (HANDLE)_get_osfhandle(fdDev);
+	// Code must specify a valid timeout value (0 means don't timeout)
+	const DWORD ctoms = ((DWORD)timeout * 100);
+	COMMTIMEOUTS cto = {ctoms, 0, ctoms, 0, ctoms};
+	return (SetCommTimeouts(hSerial, &cto) != 0);
+#else
+	struct termios my_termios;
+	
+	tcgetattr(fdDev, &my_termios);
+	my_termios.c_cc[VTIME] = (cc_t)timeout;
+	return (tcsetattr(fdDev, TCSANOW, &my_termios) == 0);
+#endif
+}
+
 /* NOTE: Linux only supports uint8_t (decisecond) timeouts; limiting it in
 /* NOTE: Linux only supports uint8_t (decisecond) timeouts; limiting it in
  *       this interface buys us warnings when bad constants are passed in.
  *       this interface buys us warnings when bad constants are passed in.
  */
  */

+ 1 - 0
lowl-vcom.h

@@ -39,6 +39,7 @@ extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char *eol);
 	_serial_read(fd, buf, bufsiz, &eol)
 	_serial_read(fd, buf, bufsiz, &eol)
 extern int serial_close(int fd);
 extern int serial_close(int fd);
 
 
+extern bool vcom_set_timeout(int fd, uint8_t timeout);
 extern enum bfg_gpio_value get_serial_cts(int fd);
 extern enum bfg_gpio_value get_serial_cts(int fd);
 extern enum bfg_gpio_value set_serial_dtr(int fd, enum bfg_gpio_value dtr);
 extern enum bfg_gpio_value set_serial_dtr(int fd, enum bfg_gpio_value dtr);
 extern enum bfg_gpio_value set_serial_rts(int fd, enum bfg_gpio_value rts);
 extern enum bfg_gpio_value set_serial_rts(int fd, enum bfg_gpio_value rts);

+ 13 - 1
lowlevel.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -109,6 +109,11 @@ struct lowlevel_device_info *lowlevel_scan()
 	LL_CONCAT(devinfo_list, devinfo_mid_list);
 	LL_CONCAT(devinfo_list, devinfo_mid_list);
 #endif
 #endif
 	
 	
+#ifdef NEED_BFG_LOWL_MSWIN
+	devinfo_mid_list = lowl_mswin.devinfo_scan();
+	LL_CONCAT(devinfo_list, devinfo_mid_list);
+#endif
+	
 #ifdef NEED_BFG_LOWL_PCI
 #ifdef NEED_BFG_LOWL_PCI
 	devinfo_mid_list = lowl_pci.devinfo_scan();
 	devinfo_mid_list = lowl_pci.devinfo_scan();
 	LL_CONCAT(devinfo_list, devinfo_mid_list);
 	LL_CONCAT(devinfo_list, devinfo_mid_list);
@@ -211,11 +216,14 @@ struct _device_claim {
 struct device_drv *bfg_claim_any(struct device_drv * const api, const char *verbose, const char * const devpath)
 struct device_drv *bfg_claim_any(struct device_drv * const api, const char *verbose, const char * const devpath)
 {
 {
 	static struct _device_claim *claims = NULL;
 	static struct _device_claim *claims = NULL;
+	static pthread_mutex_t claims_lock = PTHREAD_MUTEX_INITIALIZER;
 	struct _device_claim *c;
 	struct _device_claim *c;
 	
 	
+	mutex_lock(&claims_lock);
 	HASH_FIND_STR(claims, devpath, c);
 	HASH_FIND_STR(claims, devpath, c);
 	if (c)
 	if (c)
 	{
 	{
+		mutex_unlock(&claims_lock);
 		if (verbose && opt_debug)
 		if (verbose && opt_debug)
 		{
 		{
 			char logbuf[LOGBUFSIZ];
 			char logbuf[LOGBUFSIZ];
@@ -236,12 +244,16 @@ struct device_drv *bfg_claim_any(struct device_drv * const api, const char *verb
 	}
 	}
 	
 	
 	if (!api)
 	if (!api)
+	{
+		mutex_unlock(&claims_lock);
 		return NULL;
 		return NULL;
+	}
 	
 	
 	c = malloc(sizeof(*c));
 	c = malloc(sizeof(*c));
 	c->devpath = strdup(devpath);
 	c->devpath = strdup(devpath);
 	c->drv = api;
 	c->drv = api;
 	HASH_ADD_KEYPTR(hh, claims, c->devpath, strlen(devpath), c);
 	HASH_ADD_KEYPTR(hh, claims, c->devpath, strlen(devpath), c);
+	mutex_unlock(&claims_lock);
 	return NULL;
 	return NULL;
 }
 }
 
 

+ 5 - 0
lowlevel.h

@@ -15,6 +15,8 @@ typedef bool (*lowl_found_devinfo_func_t)(struct lowlevel_device_info *, void *)
 
 
 struct lowlevel_driver {
 struct lowlevel_driver {
 	const char *dname;
 	const char *dname;
+	bool exclude_from_all;
+	
 	struct lowlevel_device_info *(*devinfo_scan)();
 	struct lowlevel_device_info *(*devinfo_scan)();
 	void (*devinfo_free)(struct lowlevel_device_info *);
 	void (*devinfo_free)(struct lowlevel_device_info *);
 };
 };
@@ -68,6 +70,9 @@ extern struct lowlevel_driver lowl_hid;
 #ifdef USE_NANOFURY
 #ifdef USE_NANOFURY
 extern struct lowlevel_driver lowl_mcp2210;
 extern struct lowlevel_driver lowl_mcp2210;
 #endif
 #endif
+#ifdef NEED_BFG_LOWL_MSWIN
+extern struct lowlevel_driver lowl_mswin;
+#endif
 #ifdef NEED_BFG_LOWL_PCI
 #ifdef NEED_BFG_LOWL_PCI
 extern struct lowlevel_driver lowl_pci;
 extern struct lowlevel_driver lowl_pci;
 #endif
 #endif

+ 98 - 0
m4/bundled_lib.m4

@@ -0,0 +1,98 @@
+dnl * Copyright 2014 Luke Dashjr
+dnl *
+dnl * This program is free software; you can redistribute it and/or modify it
+dnl * under the terms of the GNU General Public License as published by the Free
+dnl * Software Foundation; either version 3 of the License, or (at your option)
+dnl * any later version.  See COPYING for more details.
+
+m4_divert_text([DEFAULTS], [
+origin_LDFLAGS=
+origin_LDFLAGS_checked=false
+maybe_ldconfig=
+maybe_ldconfig_checked=false
+BUNDLED_LIB_RULES=
+])
+
+AC_SUBST(BUNDLED_LIB_RULES)
+
+AC_DEFUN([BFG_CHECK_LD_ORIGIN],[
+if ! $origin_LDFLAGS_checked; then
+	save_LDFLAGS="$LDFLAGS"
+	LDFLAGS="$LDFLAGS -Wl,-zorigin"
+	AC_MSG_CHECKING([whether the linker recognizes the -zorigin option])
+	AC_TRY_LINK([],[],[
+		AC_MSG_RESULT([yes])
+		origin_LDFLAGS=',-zorigin'
+	],[
+		AC_MSG_RESULT([no])
+	])
+	LDFLAGS="$save_LDFLAGS"
+	origin_LDFLAGS_checked=true
+fi
+])
+
+AC_DEFUN([BFG_CHECK_LDCONFIG],[
+if ! $maybe_ldconfig_checked; then
+	_ROOTPATH=$PATH$PATH_SEPARATOR`echo $PATH | sed s/bin/sbin/g`
+	possible_ldconfigs="${target}-ldconfig"
+	if test "x$cross_compiling" != "xyes"; then
+		possible_ldconfigs="${possible_ldconfigs} ldconfig"
+	fi
+	AC_CHECK_PROGS([LDCONFIG],[${possible_ldconfigs}],[],[$_ROOTPATH])
+	if test "x$LDCONFIG" != "x"; then
+		maybe_ldconfig=" && $LDCONFIG"
+	fi
+	maybe_ldconfig_checked=true
+fi
+])
+
+AC_DEFUN([BFG_BUNDLED_LIB_VARS],[
+	BFG_CHECK_LD_ORIGIN
+	_AC_SRCDIRS(["$ac_dir"])
+	$1_CFLAGS='-I'"${ac_abs_top_srcdir}"'/$2'
+	$1_LIBS='-L'"${ac_abs_top_srcdir}"'/$2/.libs -Wl,-rpath,\$$ORIGIN/$2/.libs'"$origin_LDFLAGS"' m4_foreach_w([mylib],[$3],[ -l[]mylib])'
+	$1_SUBDIRS=$2
+	$1_EXTRADEPS=$1_directory
+	BUNDLED_LIB_RULES="$BUNDLED_LIB_RULES
+$1_directory:
+	\$(MAKE) -C $2
+"
+	AM_SUBST_NOTMAKE([BUNDLED_LIB_RULES])
+	if $have_cygwin; then
+		$1_EXTRADEPS="$$1_EXTRADEPS m4_foreach_w([mylib],[$3],[ cyg[]mylib[]-0.dll])"
+		BUNDLED_LIB_RULES="$BUNDLED_LIB_RULES[]m4_foreach_w([mylib],[$3],[
+cyg[]mylib[]-0.dll: $2/.libs/cyg[]mylib[]-0.dll
+	cp -p \$< \$[]@
+])"
+	fi
+])
+
+dnl BFG_BUNDLED_LIB([PKG-NAME],PKGCONF-NAME],[DEFAULT:YES/NO/AUTO],[PATH],[LIBS],[DEPENDENT-PKGS],[CONFIGURE-ARGS],[CONFIGURE-ARGS])
+AC_DEFUN([BFG_BUNDLED_LIB],[
+	AC_ARG_WITH([system-$1],[ifelse([$3],[no],AC_HELP_STRING([--with-system-$1], [Use system $1 rather than bundled one (default disabled)]),AC_HELP_STRING([--without-system-$1], [Use bundled $1 rather than system one]))],[true],[with_system_$1=$3])
+	if test "x$with_system_$1" != "xno"; then
+		PKG_CHECK_MODULES([$1],[$2],[
+			with_system_$1=yes
+		],[
+			if test "x$with_system_$1" = "xyes"; then
+				AC_MSG_ERROR([Could not find system $1])
+			else
+				AC_MSG_NOTICE([Didn't find system $1, using bundled copy])
+				with_system_$1=no
+			fi
+		])
+	fi
+	if test "x$with_system_$1" = "xno"; then
+		BFG_BUNDLED_LIB_VARS([$1],[$4],[$5])
+		BFG_CUSTOM_SUBDIR([$4],[$7],[$8 m4_foreach_w([mydep],[$6],[ mydep[]_LIBS='$mydep[]_LIBS' mydep[]_CFLAGS='$mydep[]_CFLAGS'])])
+		BFG_CHECK_LDCONFIG
+	else
+		$1_SUBDIRS=
+		$1_EXTRADEPS=
+	fi
+	AC_SUBST($1_CFLAGS)
+	AC_SUBST($1_LIBS)
+	AC_SUBST($1_SUBDIRS)
+	AC_SUBST($1_EXTRADEPS)
+	AM_CONDITIONAL(NEED_[]m4_toupper([$1]), [test x$with_system_$1 != xyes])
+])

+ 34 - 0
m4/custom_subdirs.m4

@@ -0,0 +1,34 @@
+dnl * Copyright 2014 Luke Dashjr
+dnl *
+dnl * This program is free software; you can redistribute it and/or modify it
+dnl * under the terms of the GNU General Public License as published by the Free
+dnl * Software Foundation; either version 3 of the License, or (at your option)
+dnl * any later version.  See COPYING for more details.
+
+m4_divert_text([DEFAULTS], [
+custom_subdirs=
+])
+
+AC_DEFUN([BFG_CUSTOM_SUBDIR],[
+	if false; then
+		AC_CONFIG_SUBDIRS([$1])
+	fi
+	custom_subdirs="$custom_subdirs $1"
+	custom_subdir_[]AS_TR_SH([$1])_args="$2"
+	custom_subdir_[]AS_TR_SH([$1])_forceargs="$3"
+])
+
+AC_DEFUN([BFG_CUSTOM_SUBDIRS_OUTPUT],[
+	if test "$no_recursion" != yes; then
+		orig_subdirs="$subdirs"
+		orig_ac_configure_args="$ac_configure_args"
+		for custom_subdir in $custom_subdirs; do
+			subdirs="$custom_subdir"
+			custom_subdir_base="AS_TR_SH([$custom_subdir])"
+			eval 'ac_configure_args="$custom_subdir_'"$custom_subdir_base"'_args $orig_ac_configure_args $custom_subdir_'"$custom_subdir_base"'_forceargs"'
+			_AC_OUTPUT_SUBDIRS
+		done
+		subdirs="$orig_subdirs"
+		ac_configure_args="$orig_ac_configure_args"
+	fi
+])

+ 95 - 35
make-release

@@ -1,5 +1,5 @@
 #!/bin/bash
 #!/bin/bash
-# Copyright 2012-2013 Luke Dashjr
+# Copyright 2012-2014 Luke Dashjr
 #
 #
 # This program is free software; you can redistribute it and/or modify it
 # 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
 # under the terms of the GNU General Public License as published by the Free
@@ -35,15 +35,20 @@ git branch TMP "$tag"
 git clone . "$TMPDIR" -b TMP --depth 1
 git clone . "$TMPDIR" -b TMP --depth 1
 git branch -D TMP
 git branch -D TMP
 cd "$TMPDIR"
 cd "$TMPDIR"
+sed 's/^\[submodule "\(.*\)"\]$/\1/;t;d' .gitmodules |
+ while read submodule; do
+	git config submodule.$submodule.url "$IDIR/.git/modules/$submodule"
+done
 git submodule update --init
 git submodule update --init
 {
 {
 	git archive --prefix "$sw"/ --format tar "$tag"
 	git archive --prefix "$sw"/ --format tar "$tag"
-	git submodule --quiet foreach --recursive 'test x$name = xccan-upstream || git archive --prefix "'"$sw"'/$path/" --format tar HEAD'
+	git submodule --quiet foreach --recursive 'test x$name = xccan || git archive --prefix "'"$sw"'/$path/" --format tar HEAD'
 	(
 	(
 		cd ccan-upstream
 		cd ccan-upstream
-		git archive --prefix "'"$sw"'/$path/" --format tar HEAD ccan/{build_assert,cast,compiler,opt,typesafe_cb}
+		git archive --prefix "$sw/ccan-upstream/" --format tar HEAD ccan/{build_assert,cast,compiler,opt,typesafe_cb} licenses/{CC0,GPL-3,LGPL-2.1}
 	)
 	)
 } | tar -xivp
 } | tar -xivp
+./gen-version.sh >"$sw"/version.h
 cd "$sw"
 cd "$sw"
 NOSUBMODULES=1 \
 NOSUBMODULES=1 \
 NOCONFIGURE=1 \
 NOCONFIGURE=1 \
@@ -51,25 +56,10 @@ NOCONFIGURE=1 \
 find . -name autom4te.cache |
 find . -name autom4te.cache |
  xargs rm -r
  xargs rm -r
 cd ..
 cd ..
-zip -r "$OUTDIR/${sw}.zip" "$sw"
+zip -y -r "$OUTDIR/${sw}.zip" "$sw"
 tar -cJvpf "$OUTDIR/${sw}.txz" "$sw"
 tar -cJvpf "$OUTDIR/${sw}.txz" "$sw"
 SRCDIR="$TMPDIR/$sw"
 SRCDIR="$TMPDIR/$sw"
 
 
-dlls='
-	backtrace.dll
-	pdcurses.dll
-	libcurl-4.dll
-	libevent-2-0-5.dll
-	libhidapi-0.dll
-	pthreadGC2.dll
-	libjansson-4.dll
-	libusb-1.0.dll
-	zlib1.dll
-'
-libmicrohttpd_dlls='
-	libmicrohttpd-10.dll
-	libplibc-1.dll
-'
 docs='
 docs='
 	AUTHORS
 	AUTHORS
 	COPYING
 	COPYING
@@ -84,7 +74,7 @@ docs='
 for build in "${builds[@]}"; do
 for build in "${builds[@]}"; do
 	PKGNAME="${sw}-${build}"
 	PKGNAME="${sw}-${build}"
 	PKGDIR="$TMPDIR/$PKGNAME"
 	PKGDIR="$TMPDIR/$PKGNAME"
-	cd "$TMPDIR"
+	cd "$SRCDIR"
 	mkdir -vp "$PKGDIR"
 	mkdir -vp "$PKGDIR"
 	for v in machine CFLAGS; do
 	for v in machine CFLAGS; do
 		eval "${v}"="'$(eval echo "\${${build}_${v}}")'"
 		eval "${v}"="'$(eval echo "\${${build}_${v}}")'"
@@ -96,8 +86,6 @@ for build in "${builds[@]}"; do
 		sed 's/$/\r/' <"$doc" >"$PKGDIR/${doc}.txt"
 		sed 's/$/\r/' <"$doc" >"$PKGDIR/${doc}.txt"
 	done
 	done
 	
 	
-	NOCONFIGURE=1 \
-	./autogen.sh
 	./configure \
 	./configure \
 		--prefix='C:\\Program Files\\BFGMiner\\' \
 		--prefix='C:\\Program Files\\BFGMiner\\' \
 		CFLAGS="${CFLAGS} -Wall" \
 		CFLAGS="${CFLAGS} -Wall" \
@@ -109,16 +97,19 @@ for build in "${builds[@]}"; do
 		--enable-modminer \
 		--enable-modminer \
 		--enable-ztex \
 		--enable-ztex \
 		--enable-scrypt \
 		--enable-scrypt \
+		--without-system-libbase58 \
 		--host="$machine"
 		--host="$machine"
 	make $MAKEOPTS
 	make $MAKEOPTS
 	if test "x$DEBUG_RELEASE" != "x1"; then
 	if test "x$DEBUG_RELEASE" != "x1"; then
 		"$machine"-strip \
 		"$machine"-strip \
 			libblkmaker/.libs/*.dll \
 			libblkmaker/.libs/*.dll \
+			libbase58/.libs/*.dll \
 			*.exe
 			*.exe
 	fi
 	fi
 	cp -vr \
 	cp -vr \
 		*.exe \
 		*.exe \
 		libblkmaker/.libs/*.dll \
 		libblkmaker/.libs/*.dll \
+		libbase58/.libs/*.dll \
 		opencl \
 		opencl \
 		example.conf \
 		example.conf \
 		windows-build.txt \
 		windows-build.txt \
@@ -126,19 +117,88 @@ for build in "${builds[@]}"; do
 		"$PKGDIR/"
 		"$PKGDIR/"
 	mkdir "$PKGDIR/bitstreams"
 	mkdir "$PKGDIR/bitstreams"
 	
 	
-	mydlls="$dlls"
-	if "${machine}-objdump" -p bfgminer.exe | grep -q "DLL Name: libmicrohttpd"; then
-		mydlls="$mydlls $libmicrohttpd_dlls"
-	fi
-	for dll in $mydlls; do
-		libdir="/usr/$machine/usr/lib"
-		[ -e "$libdir/$dll" ] ||
-			libdir="/usr/$machine/usr/bin"
-		[ -e "$libdir/$dll" ] ||
-			continue
-		cp -v -L "$libdir/$dll" "$PKGDIR"
-		"$machine"-strip "$PKGDIR/$dll"
-	done
+	ls "$PKGDIR" | grep '\.\(exe\|dll\)$' |
+	 perl -e '
+		use strict;
+		use warnings;
+		use File::Basename;
+		use File::Glob;
+		
+		my ($PKGDIR, $machine) = @ARGV;
+		my @todo = map { chomp; $_ } <STDIN>;
+		my %have = map { lc $_=>undef } (@todo, qw(
+			advapi32.dll
+			imagehlp.dll
+			kernel32.dll
+			msvcrt.dll
+			setupapi.dll
+			shell32.dll
+			user32.dll
+			winmm.dll
+			ws2_32.dll
+			wsock32.dll
+		));
+		# Optional/dlopen libs
+		push @todo, qw(
+			backtrace.dll
+			libhidapi-0.dll
+			libfootest.dll
+		);
+		sub ciexist {
+			my ($f) = @_;
+			my $lcf = lc $f;
+			for my $match (File::Glob::bsd_glob("${f}*", File::Glob::GLOB_CSH | File::Glob::GLOB_NOCASE)) {
+				my $matchlc = lc $match;
+				if ($matchlc eq $lcf) {
+					return basename($match);
+				}
+			}
+			undef
+		}
+		sub copydll {
+			my ($dlllc, $opt) = @_;
+			my $dll;
+			my $libdir;
+			for my $check_libdir (
+				"/usr/$machine/usr/lib",
+				"/usr/$machine/usr/bin",
+			) {
+				$dll = ciexist "$check_libdir/${dlllc}";
+				if ($dll) {
+					$libdir = $check_libdir;
+					last
+				}
+			}
+			if (not defined $libdir) {
+				return if $opt;
+				die "Cannot find $dlllc\n"
+			}
+			system("cp -v -L \"$libdir/$dll\" \"$PKGDIR\"") && die "Copy $dll failed\n";
+			system("\"${machine}-strip\" \"$PKGDIR/$dll\"") && die "Strip $dll failed\n";
+			push @todo, $dll;
+			$have{$dlllc} = undef;
+			1
+		}
+		while (my $c = shift @todo) {
+			if (not ciexist "$PKGDIR/$c") {
+				copydll $c, 1;
+				# copydll will add it to @todo again if found
+				next
+			}
+			
+			my $found;
+			print("Processing dependencies for ${c}...\n");
+			my $objdump = `"${machine}-objdump" -p "${PKGDIR}/${c}"`;
+			while ($objdump =~ /\G(?:\n|.)*?^\s*DLL Name\:\s*(.*)$/mg) {
+				my $dlllc = lc $1;
+				++$found;
+				next if exists $have{$dlllc};
+				
+				copydll $dlllc;
+			}
+			die "Failed to objdump $c\n" unless $found;
+		}
+' "$PKGDIR" "$machine"
 	
 	
 	make clean
 	make clean
 	cd "$PKGDIR/.."
 	cd "$PKGDIR/.."

File diff suppressed because it is too large
+ 371 - 132
miner.c


+ 80 - 9
miner.h

@@ -1,5 +1,6 @@
 /*
 /*
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2014 Luke Dashjr
+ * Copyright 2014 Nate Woolls
  * Copyright 2011-2013 Con Kolivas
  * Copyright 2011-2013 Con Kolivas
  * Copyright 2012-2013 Andrew Smith
  * Copyright 2012-2013 Andrew Smith
  * Copyright 2011 Glenn Francis Murray
  * Copyright 2011 Glenn Francis Murray
@@ -282,6 +283,14 @@ struct thr_info;
 struct work;
 struct work;
 struct lowlevel_device_info;
 struct lowlevel_device_info;
 
 
+enum bfg_probe_result_flags_values {
+	BPR_CONTINUE_PROBES = 1<< 0,
+	BPR_DONT_RESCAN     = 1<< 1,
+	BPR_WRONG_DEVTYPE   = BPR_CONTINUE_PROBES | BPR_DONT_RESCAN,
+};
+extern unsigned *_bfg_probe_result_flags();
+#define bfg_probe_result_flags (*_bfg_probe_result_flags())
+
 struct device_drv {
 struct device_drv {
 	const char *dname;
 	const char *dname;
 	const char *name;
 	const char *name;
@@ -308,6 +317,7 @@ struct device_drv {
 	void (*proc_wlogprint_status)(struct cgpu_info *);
 	void (*proc_wlogprint_status)(struct cgpu_info *);
 	void (*proc_tui_wlogprint_choices)(struct cgpu_info *);
 	void (*proc_tui_wlogprint_choices)(struct cgpu_info *);
 	const char *(*proc_tui_handle_choice)(struct cgpu_info *, int input);
 	const char *(*proc_tui_handle_choice)(struct cgpu_info *, int input);
+	void (*zero_stats)(struct cgpu_info *);
 
 
 	// Thread-specific functions
 	// Thread-specific functions
 	bool (*thread_prepare)(struct thr_info *);
 	bool (*thread_prepare)(struct thr_info *);
@@ -657,6 +667,16 @@ static inline void string_elist_del(struct string_elist **head, struct string_el
 }
 }
 
 
 
 
+struct bfg_loaded_configfile {
+	char *filename;
+	int fileconf_load;
+	
+	struct bfg_loaded_configfile *next;
+};
+
+extern struct bfg_loaded_configfile *bfg_loaded_configfiles;
+
+
 static inline uint32_t swab32(uint32_t v)
 static inline uint32_t swab32(uint32_t v)
 {
 {
 	return bswap_32(v);
 	return bswap_32(v);
@@ -690,14 +710,14 @@ static inline void swap32yes(void*out, const void*in, size_t sz) {
 // end
 // end
 
 
 #ifdef WORDS_BIGENDIAN
 #ifdef WORDS_BIGENDIAN
-#  define swap32tobe(out, in, sz)  ((out == in) ? (void)0 : memmove(out, in, sz))
+#  define swap32tobe(out, in, sz)  ((out == in) ? (void)0 : (void)memmove(out, in, (sz)*4))
 #  define LOCAL_swap32be(type, var, sz)  ;
 #  define LOCAL_swap32be(type, var, sz)  ;
 #  define swap32tole(out, in, sz)  swap32yes(out, in, sz)
 #  define swap32tole(out, in, sz)  swap32yes(out, in, sz)
 #  define LOCAL_swap32le(type, var, sz)  LOCAL_swap32(type, var, sz)
 #  define LOCAL_swap32le(type, var, sz)  LOCAL_swap32(type, var, sz)
 #else
 #else
 #  define swap32tobe(out, in, sz)  swap32yes(out, in, sz)
 #  define swap32tobe(out, in, sz)  swap32yes(out, in, sz)
 #  define LOCAL_swap32be(type, var, sz)  LOCAL_swap32(type, var, sz)
 #  define LOCAL_swap32be(type, var, sz)  LOCAL_swap32(type, var, sz)
-#  define swap32tole(out, in, sz)  ((out == in) ? (void)0 : memmove(out, in, sz))
+#  define swap32tole(out, in, sz)  ((out == in) ? (void)0 : (void)memmove(out, in, (sz)*4))
 #  define LOCAL_swap32le(type, var, sz)  ;
 #  define LOCAL_swap32le(type, var, sz)  ;
 #endif
 #endif
 
 
@@ -716,6 +736,29 @@ static inline void swab256(void *dest_p, const void *src_p)
 	dest[7] = swab32(src[0]);
 	dest[7] = swab32(src[0]);
 }
 }
 
 
+static inline
+void bswap_96p(void * const dest_p, const void * const src_p)
+{
+	uint32_t * const dest = dest_p;
+	const uint32_t * const src = src_p;
+	
+	dest[0] = bswap_32(src[2]);
+	dest[1] = bswap_32(src[1]);
+	dest[2] = bswap_32(src[0]);
+}
+
+static inline
+void bswap_32mult(void * const dest_p, const void * const src_p, const size_t sz)
+{
+	const uint32_t *s = src_p;
+	const uint32_t *s_end = &s[sz];
+	uint32_t *d = dest_p;
+	d = &d[sz - 1];
+	
+	for ( ; s < s_end; ++s, --d)
+		*d = bswap_32(*s);
+}
+
 #define flip32(dest_p, src_p) swap32yes(dest_p, src_p, 32 / 4)
 #define flip32(dest_p, src_p) swap32yes(dest_p, src_p, 32 / 4)
 
 
 #define WATCHDOG_INTERVAL  2
 #define WATCHDOG_INTERVAL  2
@@ -909,6 +952,7 @@ extern bool opt_fail_only;
 extern bool opt_autofan;
 extern bool opt_autofan;
 extern bool opt_autoengine;
 extern bool opt_autoengine;
 extern bool use_curses;
 extern bool use_curses;
+extern int last_logstatusline_len;
 #ifdef HAVE_LIBUSB
 #ifdef HAVE_LIBUSB
 extern bool have_libusb;
 extern bool have_libusb;
 #endif
 #endif
@@ -982,16 +1026,27 @@ extern int _bfg_console_prev_cancelstate;
 static inline
 static inline
 void bfg_console_lock(void)
 void bfg_console_lock(void)
 {
 {
-	_bfg_console_cancel_disabled = !pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &_bfg_console_prev_cancelstate);
+	int prev_cancelstate;
+	bool cancel_disabled = !pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &prev_cancelstate);
 	mutex_lock(&console_lock);
 	mutex_lock(&console_lock);
+	_bfg_console_cancel_disabled = cancel_disabled;
+	if (cancel_disabled)
+		_bfg_console_prev_cancelstate = prev_cancelstate;
 }
 }
 
 
 static inline
 static inline
 void bfg_console_unlock(void)
 void bfg_console_unlock(void)
 {
 {
-	mutex_unlock(&console_lock);
-	if (_bfg_console_cancel_disabled)
-		pthread_setcancelstate(_bfg_console_prev_cancelstate, &_bfg_console_prev_cancelstate);
+	int prev_cancelstate;
+	bool cancel_disabled = _bfg_console_cancel_disabled;
+	if (cancel_disabled)
+	{
+		prev_cancelstate = _bfg_console_prev_cancelstate;
+		mutex_unlock(&console_lock);
+		pthread_setcancelstate(prev_cancelstate, &prev_cancelstate);
+	}
+	else
+		mutex_unlock(&console_lock);
 }
 }
 
 
 
 
@@ -1004,6 +1059,8 @@ extern bool stale_work_future(struct work *, bool share, unsigned long ustime);
 extern void set_target_to_pdiff(void *dest_target, double pdiff);
 extern void set_target_to_pdiff(void *dest_target, double pdiff);
 #define bdiff_to_pdiff(n) (n * 1.0000152587)
 #define bdiff_to_pdiff(n) (n * 1.0000152587)
 extern void set_target_to_bdiff(void *dest_target, double bdiff);
 extern void set_target_to_bdiff(void *dest_target, double bdiff);
+#define pdiff_to_bdiff(n) (n * 0.9999847412109375)
+extern double target_diff(const unsigned char *target);
 
 
 extern void kill_work(void);
 extern void kill_work(void);
 extern void app_restart(void);
 extern void app_restart(void);
@@ -1209,6 +1266,7 @@ struct pool {
 	bool probed;
 	bool probed;
 	int force_rollntime;
 	int force_rollntime;
 	enum pool_enable enabled;
 	enum pool_enable enabled;
+	bool failover_only;  // NOTE: Ignored by failover and loadbalance strategies (use priority and quota respectively)
 	bool submit_old;
 	bool submit_old;
 	bool removed;
 	bool removed;
 	bool lp_started;
 	bool lp_started;
@@ -1224,6 +1282,7 @@ struct pool {
 	char *lp_id;
 	char *lp_id;
 	enum pool_protocol lp_proto;
 	enum pool_protocol lp_proto;
 	curl_socket_t lp_socket;
 	curl_socket_t lp_socket;
+	bool lp_active;
 
 
 	unsigned int getwork_requested;
 	unsigned int getwork_requested;
 	unsigned int stale_shares;
 	unsigned int stale_shares;
@@ -1241,6 +1300,7 @@ struct pool {
 	char *rpc_proxy;
 	char *rpc_proxy;
 
 
 	pthread_mutex_t pool_lock;
 	pthread_mutex_t pool_lock;
+	pthread_mutex_t pool_test_lock;
 	cglock_t data_lock;
 	cglock_t data_lock;
 
 
 	struct thread_q *submit_q;
 	struct thread_q *submit_q;
@@ -1268,6 +1328,7 @@ struct pool {
 	char *stratum_url;
 	char *stratum_url;
 	char *stratum_port;
 	char *stratum_port;
 	CURL *stratum_curl;
 	CURL *stratum_curl;
+	char curl_err_str[CURL_ERROR_SIZE];
 	SOCKETTYPE sock;
 	SOCKETTYPE sock;
 	char *sockbuf;
 	char *sockbuf;
 	size_t sockbuf_size;
 	size_t sockbuf_size;
@@ -1284,6 +1345,9 @@ struct pool {
 	bool stratum_init;
 	bool stratum_init;
 	bool stratum_notify;
 	bool stratum_notify;
 	struct stratum_work swork;
 	struct stratum_work swork;
+	uint8_t next_target[0x20];
+	char *next_nonce1;
+	int next_n2size;
 	pthread_t stratum_thread;
 	pthread_t stratum_thread;
 	pthread_mutex_t stratum_lock;
 	pthread_mutex_t stratum_lock;
 	char *admin_msg;
 	char *admin_msg;
@@ -1299,6 +1363,9 @@ struct pool {
 #define GETWORK_MODE_STRATUM 'S'
 #define GETWORK_MODE_STRATUM 'S'
 #define GETWORK_MODE_GBT 'G'
 #define GETWORK_MODE_GBT 'G'
 
 
+typedef unsigned work_device_id_t;
+#define PRIwdi "04x"
+
 struct work {
 struct work {
 	unsigned char	data[128];
 	unsigned char	data[128];
 	unsigned char	midstate[32];
 	unsigned char	midstate[32];
@@ -1335,7 +1402,7 @@ struct work {
 
 
 	unsigned char	work_restart_id;
 	unsigned char	work_restart_id;
 	int		id;
 	int		id;
-	int		device_id;
+	work_device_id_t device_id;
 	UT_hash_handle hh;
 	UT_hash_handle hh;
 	
 	
 	// Please don't use this if it's at all possible, I'd like to get rid of it eventually.
 	// Please don't use this if it's at all possible, I'd like to get rid of it eventually.
@@ -1372,7 +1439,7 @@ struct work {
 
 
 extern void get_datestamp(char *, size_t, time_t);
 extern void get_datestamp(char *, size_t, time_t);
 #define get_now_datestamp(buf, bufsz)  get_datestamp(buf, bufsz, INVALID_TIMESTAMP)
 #define get_now_datestamp(buf, bufsz)  get_datestamp(buf, bufsz, INVALID_TIMESTAMP)
-extern void get_benchmark_work(struct work *);
+extern void get_benchmark_work(struct work *, bool use_swork);
 extern void stratum_work_cpy(struct stratum_work *dst, const struct stratum_work *src);
 extern void stratum_work_cpy(struct stratum_work *dst, const struct stratum_work *src);
 extern void stratum_work_clean(struct stratum_work *);
 extern void stratum_work_clean(struct stratum_work *);
 extern bool pool_has_usable_swork(const struct pool *);
 extern bool pool_has_usable_swork(const struct pool *);
@@ -1426,6 +1493,8 @@ extern double cgpu_utility(struct cgpu_info *);
 extern void kill_work(void);
 extern void kill_work(void);
 extern int prioritize_pools(char *param, int *pid);
 extern int prioritize_pools(char *param, int *pid);
 extern void validate_pool_priorities(void);
 extern void validate_pool_priorities(void);
+extern void enable_pool(struct pool *);
+extern void disable_pool(struct pool *, enum pool_enable);
 extern void switch_pools(struct pool *selected);
 extern void switch_pools(struct pool *selected);
 extern void remove_pool(struct pool *pool);
 extern void remove_pool(struct pool *pool);
 extern void write_config(FILE *fcfg);
 extern void write_config(FILE *fcfg);
@@ -1450,6 +1519,7 @@ extern void clean_work(struct work *work);
 extern void free_work(struct work *work);
 extern void free_work(struct work *work);
 extern void __copy_work(struct work *work, const struct work *base_work);
 extern void __copy_work(struct work *work, const struct work *base_work);
 extern struct work *copy_work(const struct work *base_work);
 extern struct work *copy_work(const struct work *base_work);
+extern const char *bfg_workpadding_bin;
 extern void set_simple_ntime_roll_limit(struct ntime_roll_limits *, uint32_t ntime_base, int ntime_roll, const struct timeval *tvp_ref);
 extern void set_simple_ntime_roll_limit(struct ntime_roll_limits *, uint32_t ntime_base, int ntime_roll, const struct timeval *tvp_ref);
 extern void work_set_simple_ntime_roll_limit(struct work *, int ntime_roll, const struct timeval *tvp_ref);
 extern void work_set_simple_ntime_roll_limit(struct work *, int ntime_roll, const struct timeval *tvp_ref);
 extern int work_ntime_range(struct work *, const struct timeval *tvp_earliest, const struct timeval *tvp_latest, int desired_roll);
 extern int work_ntime_range(struct work *, const struct timeval *tvp_earliest, const struct timeval *tvp_latest, int desired_roll);
@@ -1469,6 +1539,7 @@ void work_set_ntime(struct work * const work, const uint32_t ntime)
 }
 }
 
 
 
 
+extern void work_hash(struct work *);
 extern char *devpath_to_devid(const char *);
 extern char *devpath_to_devid(const char *);
 extern struct thr_info *get_thread(int thr_id);
 extern struct thr_info *get_thread(int thr_id);
 extern struct cgpu_info *get_devices(int id);
 extern struct cgpu_info *get_devices(int id);

+ 32 - 21
ocl.c

@@ -1,6 +1,6 @@
 /*
 /*
  * Copyright 2011-2013 Con Kolivas
  * Copyright 2011-2013 Con Kolivas
- * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2014 Luke Dashjr
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the Free
@@ -339,6 +339,28 @@ int clDevicesNum(void) {
 	return most_devices;
 	return most_devices;
 }
 }
 
 
+cl_int bfg_clBuildProgram(_clState * const clState, const cl_device_id devid, const char * const CompilerOptions)
+{
+	cl_int status;
+	
+	status = clBuildProgram(clState->program, 1, &devid, CompilerOptions, NULL, NULL);
+	
+	if (status != CL_SUCCESS)
+	{
+		applog(LOG_ERR, "Error %d: Building Program (clBuildProgram)", status);
+		size_t logSize;
+		status = clGetProgramBuildInfo(clState->program, devid, CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
+		
+		char *log = malloc(logSize ?: 1);
+		status = clGetProgramBuildInfo(clState->program, devid, CL_PROGRAM_BUILD_LOG, logSize, log, NULL);
+		if (logSize > 0 && log[0])
+			applog(LOG_ERR, "%s", log);
+		free(log);
+	}
+	
+	return status;
+}
+
 static int advance(char **area, unsigned *remaining, const char *marker)
 static int advance(char **area, unsigned *remaining, const char *marker)
 {
 {
 	char *find = memmem(*area, *remaining, marker, strlen(marker));
 	char *find = memmem(*area, *remaining, marker, strlen(marker));
@@ -531,6 +553,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 	find = strstr(extensions, camo);
 	find = strstr(extensions, camo);
 	if (find)
 	if (find)
 		clState->hasBitAlign = true;
 		clState->hasBitAlign = true;
+	free(extensions);
 
 
 	/* Check for OpenCL >= 1.0 support, needed for global offset parameter usage. */
 	/* Check for OpenCL >= 1.0 support, needed for global offset parameter usage. */
 	char * devoclver = malloc(1024);
 	char * devoclver = malloc(1024);
@@ -544,6 +567,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 	find = strstr(devoclver, ocl10);
 	find = strstr(devoclver, ocl10);
 	if (!find)
 	if (!find)
 		clState->hasOpenCL11plus = true;
 		clState->hasOpenCL11plus = true;
+	free(devoclver);
 
 
 	status = clGetDeviceInfo(devices[gpu], CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, sizeof(cl_uint), (void *)&preferred_vwidth, NULL);
 	status = clGetDeviceInfo(devices[gpu], CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, sizeof(cl_uint), (void *)&preferred_vwidth, NULL);
 	if (status != CL_SUCCESS) {
 	if (status != CL_SUCCESS) {
@@ -928,19 +952,11 @@ build:
 		strcat(CompilerOptions, " -D OCL1");
 		strcat(CompilerOptions, " -D OCL1");
 
 
 	applog(LOG_DEBUG, "CompilerOptions: %s", CompilerOptions);
 	applog(LOG_DEBUG, "CompilerOptions: %s", CompilerOptions);
-	status = clBuildProgram(clState->program, 1, &devices[gpu], CompilerOptions , NULL, NULL);
+	status = bfg_clBuildProgram(clState, devices[gpu], CompilerOptions);
 	free(CompilerOptions);
 	free(CompilerOptions);
 
 
-	if (status != CL_SUCCESS) {
-		applog(LOG_ERR, "Error %d: Building Program (clBuildProgram)", status);
-		size_t logSize;
-		status = clGetProgramBuildInfo(clState->program, devices[gpu], CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
-
-		char *log = malloc(logSize);
-		status = clGetProgramBuildInfo(clState->program, devices[gpu], CL_PROGRAM_BUILD_LOG, logSize, log, NULL);
-		applog(LOG_ERR, "%s", log);
+	if (status != CL_SUCCESS)
 		return NULL;
 		return NULL;
-	}
 
 
 	prog_built = true;
 	prog_built = true;
 	
 	
@@ -1055,17 +1071,9 @@ built:
 
 
 	if (!prog_built) {
 	if (!prog_built) {
 		/* create a cl program executable for all the devices specified */
 		/* create a cl program executable for all the devices specified */
-		status = clBuildProgram(clState->program, 1, &devices[gpu], NULL, NULL, NULL);
-		if (status != CL_SUCCESS) {
-			applog(LOG_ERR, "Error %d: Building Program (clBuildProgram)", status);
-			size_t logSize;
-			status = clGetProgramBuildInfo(clState->program, devices[gpu], CL_PROGRAM_BUILD_LOG, 0, NULL, &logSize);
-
-			char *log = malloc(logSize);
-			status = clGetProgramBuildInfo(clState->program, devices[gpu], CL_PROGRAM_BUILD_LOG, logSize, log, NULL);
-			applog(LOG_ERR, "%s", log);
+		status = bfg_clBuildProgram(clState, devices[gpu], NULL);
+		if (status != CL_SUCCESS)
 			return NULL;
 			return NULL;
-		}
 	}
 	}
 
 
 	/* get a kernel object handle for a kernel with the given name */
 	/* get a kernel object handle for a kernel with the given name */
@@ -1074,6 +1082,9 @@ built:
 		applog(LOG_ERR, "Error %d: Creating Kernel from program. (clCreateKernel)", status);
 		applog(LOG_ERR, "Error %d: Creating Kernel from program. (clCreateKernel)", status);
 		return NULL;
 		return NULL;
 	}
 	}
+	
+	free((void*)cgpu->kname);
+	cgpu->kname = strdup(data->kernel_file);
 
 
 #ifdef USE_SCRYPT
 #ifdef USE_SCRYPT
 	if (opt_scrypt) {
 	if (opt_scrypt) {

+ 1 - 1
opencl/poclbm.cl

@@ -1,6 +1,6 @@
 // -ck modified kernel taken from Phoenix taken from poclbm, with aspects of
 // -ck modified kernel taken from Phoenix taken from poclbm, with aspects of
 // phatk and others.
 // phatk and others.
-// Modified version copyright 2011-2012 Con Kolivas
+// Modified version copyright 2011-2013 Con Kolivas
 
 
 // This file is taken and modified from the public-domain poclbm project, and
 // This file is taken and modified from the public-domain poclbm project, and
 // we have therefore decided to keep it public-domain in Phoenix.
 // we have therefore decided to keep it public-domain in Phoenix.

+ 795 - 0
opencl/psw.cl

@@ -0,0 +1,795 @@
+/*-
+ * Copyright 2009 Colin Percival, 2011 ArtForz, 2011 pooler, 2012 mtrlt,
+ * 2013 Optimiztion by Pavel Semjanov,
+ * 2012-2013 Con Kolivas.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+
+// kernel-interface: scrypt
+
+__constant uint ES[2] = { 0x00FF00FF, 0xFF00FF00 };
+__constant uint K[] = {
+	0x428a2f98U,
+	0x71374491U,
+	0xb5c0fbcfU,
+	0xe9b5dba5U,
+	0x3956c25bU,
+	0x59f111f1U,
+	0x923f82a4U,
+	0xab1c5ed5U,
+	0xd807aa98U,
+	0x12835b01U,
+	0x243185beU, // 10
+	0x550c7dc3U,
+	0x72be5d74U,
+	0x80deb1feU,
+	0x9bdc06a7U,
+	0xe49b69c1U,
+	0xefbe4786U,
+	0x0fc19dc6U,
+	0x240ca1ccU,
+	0x2de92c6fU,
+	0x4a7484aaU, // 20
+	0x5cb0a9dcU,
+	0x76f988daU,
+	0x983e5152U,
+	0xa831c66dU,
+	0xb00327c8U,
+	0xbf597fc7U,
+	0xc6e00bf3U,
+	0xd5a79147U,
+	0x06ca6351U,
+	0x14292967U, // 30
+	0x27b70a85U,
+	0x2e1b2138U,
+	0x4d2c6dfcU,
+	0x53380d13U,
+	0x650a7354U,
+	0x766a0abbU,
+	0x81c2c92eU,
+	0x92722c85U,
+	0xa2bfe8a1U,
+	0xa81a664bU, // 40
+	0xc24b8b70U,
+	0xc76c51a3U,
+	0xd192e819U,
+	0xd6990624U,
+	0xf40e3585U,
+	0x106aa070U,
+	0x19a4c116U,
+	0x1e376c08U,
+	0x2748774cU,
+	0x34b0bcb5U, // 50
+	0x391c0cb3U,
+	0x4ed8aa4aU,
+	0x5b9cca4fU,
+	0x682e6ff3U,
+	0x748f82eeU,
+	0x78a5636fU,
+	0x84c87814U,
+	0x8cc70208U,
+	0x90befffaU,
+	0xa4506cebU, // 60
+	0xbef9a3f7U,
+	0xc67178f2U,
+	0x98c7e2a2U,
+	0xfc08884dU,
+	0xcd2a11aeU,
+	0x510e527fU,
+	0x9b05688cU,
+	0xC3910C8EU,
+	0xfb6feee7U,
+	0x2a01a605U, // 70
+	0x0c2e12e0U,
+	0x4498517BU,
+	0x6a09e667U,
+	0xa4ce148bU,
+	0x95F61999U,
+	0xc19bf174U,
+	0xBB67AE85U,
+	0x3C6EF372U,
+	0xA54FF53AU,
+	0x1F83D9ABU, // 80
+	0x5BE0CD19U,
+	0x5C5C5C5CU,
+	0x36363636U,
+	0x80000000U,
+	0x000003FFU,
+	0x00000280U,
+	0x000004a0U,
+	0x00000300U
+};
+
+#define rotl(x,y) rotate(x,y)
+#define Ch(x,y,z) bitselect(z,y,x)
+#define Maj(x,y,z) Ch((x^z),y,z)
+
+#define EndianSwap(n) (rotl(n & ES[0], 24U)|rotl(n & ES[1], 8U))
+
+#define Tr2(x)		(rotl(x, 30U) ^ rotl(x, 19U) ^ rotl(x, 10U))
+#define Tr1(x)		(rotl(x, 26U) ^ rotl(x, 21U) ^ rotl(x, 7U))
+#define Wr2(x)		(rotl(x, 25U) ^ rotl(x, 14U) ^ (x>>3U))
+#define Wr1(x)		(rotl(x, 15U) ^ rotl(x, 13U) ^ (x>>10U))
+
+#define RND(a, b, c, d, e, f, g, h, k)	\
+	h += Tr1(e); 			\
+	h += Ch(e, f, g); 		\
+	h += k;				\
+	d += h;				\
+	h += Tr2(a); 			\
+	h += Maj(a, b, c);
+
+void SHA256(uint4*restrict state0,uint4*restrict state1, const uint4 block0, const uint4 block1, const uint4 block2, const uint4 block3)
+{
+	uint4 S0 = *state0;
+	uint4 S1 = *state1;
+	
+#define A S0.x
+#define B S0.y
+#define C S0.z
+#define D S0.w
+#define E S1.x
+#define F S1.y
+#define G S1.z
+#define H S1.w
+
+	uint4 W[4];
+
+	W[ 0].x = block0.x;
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[0]);
+	W[ 0].y = block0.y;
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[1]);
+	W[ 0].z = block0.z;
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[2]);
+	W[ 0].w = block0.w;
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[3]);
+
+	W[ 1].x = block1.x;
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[4]);
+	W[ 1].y = block1.y;
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[5]);
+	W[ 1].z = block1.z;
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[6]);
+	W[ 1].w = block1.w;
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[7]);
+
+	W[ 2].x = block2.x;
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[8]);
+	W[ 2].y = block2.y;
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[9]);
+	W[ 2].z = block2.z;
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[10]);
+	W[ 2].w = block2.w;
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[11]);
+
+	W[ 3].x = block3.x;
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[12]);
+	W[ 3].y = block3.y;
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[13]);
+	W[ 3].z = block3.z;
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[14]);
+	W[ 3].w = block3.w;
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[76]);
+
+
+#define WUpdate(i) {  \
+	uint4 tmp1, tmp2, tmp3;                                                   \
+	tmp1 = (uint4) (W[(i+0)%4].y, W[(i+0)%4].z, W[(i+0)%4].w, W[(i+1)%4].x);  \
+	tmp2 = (uint4) (W[(i+2)%4].y, W[(i+2)%4].z, W[(i+2)%4].w, W[(i+3)%4].x);  \
+	tmp3 = (uint4) (W[(i+3)%4].z, W[(i+3)%4].w, 0, 0);                        \
+	W[(i+0)%4] += tmp2 + Wr2 (tmp1) + Wr1 (tmp3);                             \
+	tmp1 = (uint4) (0, 0, W[(i+0)%4].x, W[(i+0)%4].y);                        \
+	W[(i+0)%4] += Wr1 (tmp1);                                                 \
+}
+
+	WUpdate (0);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[15]);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[16]);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[17]);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[18]);
+
+	WUpdate (1);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[19]);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[20]);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[21]);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[22]);
+
+	WUpdate (2);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[23]);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[24]);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[25]);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[26]);
+
+	WUpdate (3);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[27]);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[28]);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[29]);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[30]);
+
+	WUpdate (0);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[31]);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[32]);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[33]);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[34]);
+
+	WUpdate (1);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[35]);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[36]);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[37]);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[38]);
+
+	WUpdate (2);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[39]);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[40]);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[41]);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[42]);
+
+	WUpdate (3);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[43]);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[44]);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[45]);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[46]);
+
+	WUpdate (0);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[47]);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[48]);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[49]);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[50]);
+
+	WUpdate (1);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[51]);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[52]);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[53]);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[54]);
+
+	WUpdate (2);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[55]);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[56]);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[57]);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[58]);
+
+	WUpdate (3);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[59]);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[60]);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[61]);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[62]);
+	
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef G
+#undef H
+
+	*state0 += S0;
+	*state1 += S1;
+}
+
+void SHA256_fresh(uint4*restrict state0,uint4*restrict state1, const uint4 block0, const uint4 block1, const uint4 block2, const uint4 block3)
+{
+#define A (*state0).x
+#define B (*state0).y
+#define C (*state0).z
+#define D (*state0).w
+#define E (*state1).x
+#define F (*state1).y
+#define G (*state1).z
+#define H (*state1).w
+
+	uint4 W[4];
+
+	W[0].x = block0.x;
+	D= K[63] +W[0].x;
+	H= K[64] +W[0].x;
+
+	W[0].y = block0.y;
+	C= K[65] +Tr1(D)+Ch(D, K[66], K[67])+W[0].y;
+	G= K[68] +C+Tr2(H)+Ch(H, K[69] ,K[70]);
+
+	W[0].z = block0.z;
+	B= K[71] +Tr1(C)+Ch(C,D,K[66])+W[0].z;
+	F= K[72] +B+Tr2(G)+Maj(G,H, K[73]);
+
+	W[0].w = block0.w;
+	A= K[74] +Tr1(B)+Ch(B,C,D)+W[0].w;
+	E= K[75] +A+Tr2(F)+Maj(F,G,H);
+
+	W[1].x = block1.x;
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[4]);
+	W[1].y = block1.y;
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[5]);
+	W[1].z = block1.z;
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[6]);
+	W[1].w = block1.w;
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[7]);
+	
+	W[2].x = block2.x;
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[8]);
+	W[2].y = block2.y;
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[9]);
+	W[2].z = block2.z;
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[10]);
+	W[2].w = block2.w;
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[11]);
+	
+	W[3].x = block3.x;
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[12]);
+	W[3].y = block3.y;
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[13]);
+	W[3].z = block3.z;
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[14]);
+	W[3].w = block3.w;
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[76]);
+
+	W[0].x += Wr1(W[3].z) + W[2].y + Wr2(W[0].y);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[15]);
+
+	W[0].y += Wr1(W[3].w) + W[2].z + Wr2(W[0].z);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[16]);
+
+	W[0].z += Wr1(W[0].x) + W[2].w + Wr2(W[0].w);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[17]);
+
+	W[0].w += Wr1(W[0].y) + W[3].x + Wr2(W[1].x);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[18]);
+
+	W[1].x += Wr1(W[0].z) + W[3].y + Wr2(W[1].y);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[19]);
+
+	W[1].y += Wr1(W[0].w) + W[3].z + Wr2(W[1].z);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[20]);
+
+	W[1].z += Wr1(W[1].x) + W[3].w + Wr2(W[1].w);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[21]);
+
+	W[1].w += Wr1(W[1].y) + W[0].x + Wr2(W[2].x);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[22]);
+
+	W[2].x += Wr1(W[1].z) + W[0].y + Wr2(W[2].y);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[23]);
+
+	W[2].y += Wr1(W[1].w) + W[0].z + Wr2(W[2].z);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[24]);
+
+	W[2].z += Wr1(W[2].x) + W[0].w + Wr2(W[2].w);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[25]);
+
+	W[2].w += Wr1(W[2].y) + W[1].x + Wr2(W[3].x);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[26]);
+
+	W[3].x += Wr1(W[2].z) + W[1].y + Wr2(W[3].y);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[27]);
+
+	W[3].y += Wr1(W[2].w) + W[1].z + Wr2(W[3].z);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[28]);
+
+	W[3].z += Wr1(W[3].x) + W[1].w + Wr2(W[3].w);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[29]);
+
+	W[3].w += Wr1(W[3].y) + W[2].x + Wr2(W[0].x);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[30]);
+
+	W[0].x += Wr1(W[3].z) + W[2].y + Wr2(W[0].y);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[31]);
+
+	W[0].y += Wr1(W[3].w) + W[2].z + Wr2(W[0].z);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[32]);
+
+	W[0].z += Wr1(W[0].x) + W[2].w + Wr2(W[0].w);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[33]);
+
+	W[0].w += Wr1(W[0].y) + W[3].x + Wr2(W[1].x);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[34]);
+
+	W[1].x += Wr1(W[0].z) + W[3].y + Wr2(W[1].y);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[35]);
+
+	W[1].y += Wr1(W[0].w) + W[3].z + Wr2(W[1].z);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[36]);
+
+	W[1].z += Wr1(W[1].x) + W[3].w + Wr2(W[1].w);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[37]);
+
+	W[1].w += Wr1(W[1].y) + W[0].x + Wr2(W[2].x);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[38]);
+
+	W[2].x += Wr1(W[1].z) + W[0].y + Wr2(W[2].y);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[39]);
+
+	W[2].y += Wr1(W[1].w) + W[0].z + Wr2(W[2].z);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[40]);
+
+	W[2].z += Wr1(W[2].x) + W[0].w + Wr2(W[2].w);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[41]);
+
+	W[2].w += Wr1(W[2].y) + W[1].x + Wr2(W[3].x);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[42]);
+
+	W[3].x += Wr1(W[2].z) + W[1].y + Wr2(W[3].y);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[43]);
+
+	W[3].y += Wr1(W[2].w) + W[1].z + Wr2(W[3].z);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[44]);
+
+	W[3].z += Wr1(W[3].x) + W[1].w + Wr2(W[3].w);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[45]);
+
+	W[3].w += Wr1(W[3].y) + W[2].x + Wr2(W[0].x);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[46]);
+
+	W[0].x += Wr1(W[3].z) + W[2].y + Wr2(W[0].y);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[47]);
+
+	W[0].y += Wr1(W[3].w) + W[2].z + Wr2(W[0].z);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[48]);
+
+	W[0].z += Wr1(W[0].x) + W[2].w + Wr2(W[0].w);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[49]);
+
+	W[0].w += Wr1(W[0].y) + W[3].x + Wr2(W[1].x);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[50]);
+
+	W[1].x += Wr1(W[0].z) + W[3].y + Wr2(W[1].y);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[51]);
+
+	W[1].y += Wr1(W[0].w) + W[3].z + Wr2(W[1].z);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[52]);
+
+	W[1].z += Wr1(W[1].x) + W[3].w + Wr2(W[1].w);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[53]);
+
+	W[1].w += Wr1(W[1].y) + W[0].x + Wr2(W[2].x);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[54]);
+
+	W[2].x += Wr1(W[1].z) + W[0].y + Wr2(W[2].y);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[55]);
+
+	W[2].y += Wr1(W[1].w) + W[0].z + Wr2(W[2].z);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[56]);
+
+	W[2].z += Wr1(W[2].x) + W[0].w + Wr2(W[2].w);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[57]);
+
+	W[2].w += Wr1(W[2].y) + W[1].x + Wr2(W[3].x);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[58]);
+
+	W[3].x += Wr1(W[2].z) + W[1].y + Wr2(W[3].y);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[59]);
+
+	W[3].y += Wr1(W[2].w) + W[1].z + Wr2(W[3].z);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[60]);
+
+	W[3].z += Wr1(W[3].x) + W[1].w + Wr2(W[3].w);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[61]);
+
+	W[3].w += Wr1(W[3].y) + W[2].x + Wr2(W[0].x);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[62]);
+	
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef G
+#undef H
+
+	*state0 += (uint4)(K[73], K[77], K[78], K[79]);
+	*state1 += (uint4)(K[66], K[67], K[80], K[81]);
+}
+
+__constant uint fixedW[64] =
+{
+	0x428a2f99,0xf1374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf794,
+	0xf59b89c2,0x73924787,0x23c6886e,0xa42ca65c,0x15ed3627,0x4d6edcbf,0xe28217fc,0xef02488f,
+	0xb707775c,0x0468c23f,0xe7e72b4c,0x49e1f1a2,0x4b99c816,0x926d1570,0xaa0fc072,0xadb36e2c,
+	0xad87a3ea,0xbcb1d3a3,0x7b993186,0x562b9420,0xbff3ca0c,0xda4b0c23,0x6cd8711a,0x8f337caa,
+	0xc91b1417,0xc359dce1,0xa83253a7,0x3b13c12d,0x9d3d725d,0xd9031a84,0xb1a03340,0x16f58012,
+	0xe64fb6a2,0xe84d923a,0xe93a5730,0x09837686,0x078ff753,0x29833341,0xd5de0b7e,0x6948ccf4,
+	0xe0a1adbe,0x7c728e11,0x511c78e4,0x315b45bd,0xfca71413,0xea28f96a,0x79703128,0x4e1ef848,
+};
+
+void SHA256_fixed(uint4*restrict state0,uint4*restrict state1)
+{
+	uint4 S0 = *state0;
+	uint4 S1 = *state1;
+
+#define A S0.x
+#define B S0.y
+#define C S0.z
+#define D S0.w
+#define E S1.x
+#define F S1.y
+#define G S1.z
+#define H S1.w
+
+	RND(A,B,C,D,E,F,G,H, fixedW[0]);
+	RND(H,A,B,C,D,E,F,G, fixedW[1]);
+	RND(G,H,A,B,C,D,E,F, fixedW[2]);
+	RND(F,G,H,A,B,C,D,E, fixedW[3]);
+	RND(E,F,G,H,A,B,C,D, fixedW[4]);
+	RND(D,E,F,G,H,A,B,C, fixedW[5]);
+	RND(C,D,E,F,G,H,A,B, fixedW[6]);
+	RND(B,C,D,E,F,G,H,A, fixedW[7]);
+	RND(A,B,C,D,E,F,G,H, fixedW[8]);
+	RND(H,A,B,C,D,E,F,G, fixedW[9]);
+	RND(G,H,A,B,C,D,E,F, fixedW[10]);
+	RND(F,G,H,A,B,C,D,E, fixedW[11]);
+	RND(E,F,G,H,A,B,C,D, fixedW[12]);
+	RND(D,E,F,G,H,A,B,C, fixedW[13]);
+	RND(C,D,E,F,G,H,A,B, fixedW[14]);
+	RND(B,C,D,E,F,G,H,A, fixedW[15]);
+	RND(A,B,C,D,E,F,G,H, fixedW[16]);
+	RND(H,A,B,C,D,E,F,G, fixedW[17]);
+	RND(G,H,A,B,C,D,E,F, fixedW[18]);
+	RND(F,G,H,A,B,C,D,E, fixedW[19]);
+	RND(E,F,G,H,A,B,C,D, fixedW[20]);
+	RND(D,E,F,G,H,A,B,C, fixedW[21]);
+	RND(C,D,E,F,G,H,A,B, fixedW[22]);
+	RND(B,C,D,E,F,G,H,A, fixedW[23]);
+	RND(A,B,C,D,E,F,G,H, fixedW[24]);
+	RND(H,A,B,C,D,E,F,G, fixedW[25]);
+	RND(G,H,A,B,C,D,E,F, fixedW[26]);
+	RND(F,G,H,A,B,C,D,E, fixedW[27]);
+	RND(E,F,G,H,A,B,C,D, fixedW[28]);
+	RND(D,E,F,G,H,A,B,C, fixedW[29]);
+	RND(C,D,E,F,G,H,A,B, fixedW[30]);
+	RND(B,C,D,E,F,G,H,A, fixedW[31]);
+	RND(A,B,C,D,E,F,G,H, fixedW[32]);
+	RND(H,A,B,C,D,E,F,G, fixedW[33]);
+	RND(G,H,A,B,C,D,E,F, fixedW[34]);
+	RND(F,G,H,A,B,C,D,E, fixedW[35]);
+	RND(E,F,G,H,A,B,C,D, fixedW[36]);
+	RND(D,E,F,G,H,A,B,C, fixedW[37]);
+	RND(C,D,E,F,G,H,A,B, fixedW[38]);
+	RND(B,C,D,E,F,G,H,A, fixedW[39]);
+	RND(A,B,C,D,E,F,G,H, fixedW[40]);
+	RND(H,A,B,C,D,E,F,G, fixedW[41]);
+	RND(G,H,A,B,C,D,E,F, fixedW[42]);
+	RND(F,G,H,A,B,C,D,E, fixedW[43]);
+	RND(E,F,G,H,A,B,C,D, fixedW[44]);
+	RND(D,E,F,G,H,A,B,C, fixedW[45]);
+	RND(C,D,E,F,G,H,A,B, fixedW[46]);
+	RND(B,C,D,E,F,G,H,A, fixedW[47]);
+	RND(A,B,C,D,E,F,G,H, fixedW[48]);
+	RND(H,A,B,C,D,E,F,G, fixedW[49]);
+	RND(G,H,A,B,C,D,E,F, fixedW[50]);
+	RND(F,G,H,A,B,C,D,E, fixedW[51]);
+	RND(E,F,G,H,A,B,C,D, fixedW[52]);
+	RND(D,E,F,G,H,A,B,C, fixedW[53]);
+	RND(C,D,E,F,G,H,A,B, fixedW[54]);
+	RND(B,C,D,E,F,G,H,A, fixedW[55]);
+	RND(A,B,C,D,E,F,G,H, fixedW[56]);
+	RND(H,A,B,C,D,E,F,G, fixedW[57]);
+	RND(G,H,A,B,C,D,E,F, fixedW[58]);
+	RND(F,G,H,A,B,C,D,E, fixedW[59]);
+	RND(E,F,G,H,A,B,C,D, fixedW[60]);
+	RND(D,E,F,G,H,A,B,C, fixedW[61]);
+	RND(C,D,E,F,G,H,A,B, fixedW[62]);
+	RND(B,C,D,E,F,G,H,A, fixedW[63]);
+	
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef G
+#undef H
+	*state0 += S0;
+	*state1 += S1;
+}
+
+void shittify(uint4 B[8])
+{
+	uint4 tmp[4];
+	tmp[0] = (uint4)(B[1].x,B[2].y,B[3].z,B[0].w);
+	tmp[1] = (uint4)(B[2].x,B[3].y,B[0].z,B[1].w);
+	tmp[2] = (uint4)(B[3].x,B[0].y,B[1].z,B[2].w);
+	tmp[3] = (uint4)(B[0].x,B[1].y,B[2].z,B[3].w);
+	
+#pragma unroll
+	for(uint i=0; i<4; ++i)
+		B[i] = EndianSwap(tmp[i]);
+
+	tmp[0] = (uint4)(B[5].x,B[6].y,B[7].z,B[4].w);
+	tmp[1] = (uint4)(B[6].x,B[7].y,B[4].z,B[5].w);
+	tmp[2] = (uint4)(B[7].x,B[4].y,B[5].z,B[6].w);
+	tmp[3] = (uint4)(B[4].x,B[5].y,B[6].z,B[7].w);
+	
+#pragma unroll
+	for(uint i=0; i<4; ++i)
+		B[i+4] = EndianSwap(tmp[i]);
+}
+
+void unshittify(uint4 B[8])
+{
+	uint4 tmp[4];
+	tmp[0] = (uint4)(B[3].x,B[2].y,B[1].z,B[0].w);
+	tmp[1] = (uint4)(B[0].x,B[3].y,B[2].z,B[1].w);
+	tmp[2] = (uint4)(B[1].x,B[0].y,B[3].z,B[2].w);
+	tmp[3] = (uint4)(B[2].x,B[1].y,B[0].z,B[3].w);
+	
+#pragma unroll
+	for(uint i=0; i<4; ++i)
+		B[i] = EndianSwap(tmp[i]);
+
+	tmp[0] = (uint4)(B[7].x,B[6].y,B[5].z,B[4].w);
+	tmp[1] = (uint4)(B[4].x,B[7].y,B[6].z,B[5].w);
+	tmp[2] = (uint4)(B[5].x,B[4].y,B[7].z,B[6].w);
+	tmp[3] = (uint4)(B[6].x,B[5].y,B[4].z,B[7].w);
+	
+#pragma unroll
+	for(uint i=0; i<4; ++i)
+		B[i+4] = EndianSwap(tmp[i]);
+}
+
+void salsa(uint4 B[8])
+{
+	uint4 w[4];
+
+#pragma unroll
+	for(uint i=0; i<4; ++i)
+		w[i] = (B[i]^=B[i+4]);
+
+#pragma unroll
+	for(uint i=0; i<4; ++i)
+	{
+		w[0] ^= rotl(w[3]     +w[2]     , 7U);
+		w[1] ^= rotl(w[0]     +w[3]     , 9U);
+		w[2] ^= rotl(w[1]     +w[0]     ,13U);
+		w[3] ^= rotl(w[2]     +w[1]     ,18U);
+		w[2] ^= rotl(w[3].wxyz+w[0].zwxy, 7U);
+		w[1] ^= rotl(w[2].wxyz+w[3].zwxy, 9U);
+		w[0] ^= rotl(w[1].wxyz+w[2].zwxy,13U);
+		w[3] ^= rotl(w[0].wxyz+w[1].zwxy,18U);
+	}
+
+#pragma unroll
+	for(uint i=0; i<4; ++i)
+		w[i] = (B[i+4]^=(B[i]+=w[i]));
+
+#pragma unroll
+	for(uint i=0; i<4; ++i)
+	{
+		w[0] ^= rotl(w[3]     +w[2]     , 7U);
+		w[1] ^= rotl(w[0]     +w[3]     , 9U);
+		w[2] ^= rotl(w[1]     +w[0]     ,13U);
+		w[3] ^= rotl(w[2]     +w[1]     ,18U);
+		w[2] ^= rotl(w[3].wxyz+w[0].zwxy, 7U);
+		w[1] ^= rotl(w[2].wxyz+w[3].zwxy, 9U);
+		w[0] ^= rotl(w[1].wxyz+w[2].zwxy,13U);
+		w[3] ^= rotl(w[0].wxyz+w[1].zwxy,18U);
+	}
+
+#pragma unroll
+	for(uint i=0; i<4; ++i)
+		B[i+4] += w[i];
+}
+
+#define Coord(x,y,z) x+y*(x ## SIZE)+z*(y ## SIZE)*(x ## SIZE)
+#define CO Coord(z,x,y)
+
+void scrypt_core(uint4 X[8], __global uint4*restrict lookup)
+{
+	shittify(X);
+	const uint zSIZE = 8;
+	const uint ySIZE = (1024/LOOKUP_GAP+(1024%LOOKUP_GAP>0));
+	const uint xSIZE = CONCURRENT_THREADS;
+	uint x = get_global_id(0)%xSIZE;
+
+	for(uint y=0; y<1024/LOOKUP_GAP; ++y)
+	{
+#pragma unroll
+		for(uint z=0; z<zSIZE; ++z)
+			lookup[CO] = X[z];
+		for(uint i=0; i<LOOKUP_GAP; ++i)
+			salsa(X);
+	}
+#if (LOOKUP_GAP != 1) && (LOOKUP_GAP != 2) && (LOOKUP_GAP != 4) && (LOOKUP_GAP != 8)
+	{
+		uint y = (1024/LOOKUP_GAP);
+#pragma unroll
+		for(uint z=0; z<zSIZE; ++z)
+			lookup[CO] = X[z];
+		for(uint i=0; i<1024%LOOKUP_GAP; ++i)
+			salsa(X);
+	}
+#endif
+	for (uint i=0; i<1024; ++i)
+	{
+		uint4 V[8];
+		uint j = X[7].x & K[85];
+		uint y = (j/LOOKUP_GAP);
+#pragma unroll
+		for(uint z=0; z<zSIZE; ++z)
+			V[z] = lookup[CO];
+
+#if (LOOKUP_GAP == 1)
+#elif (LOOKUP_GAP == 2)
+		if (j&1)
+			salsa(V);
+#else
+		uint val = j%LOOKUP_GAP;
+		for (uint z=0; z<val; ++z)
+			salsa(V);
+#endif
+
+#pragma unroll
+		for(uint z=0; z<zSIZE; ++z)
+			X[z] ^= V[z];
+		salsa(X);
+	}
+	unshittify(X);
+}
+
+#define SCRYPT_FOUND (0xFF)
+#define SETFOUND(Xnonce) output[output[SCRYPT_FOUND]++] = Xnonce
+
+__attribute__((reqd_work_group_size(WORKSIZE, 1, 1)))
+__kernel void search(__global const uint4 * restrict input,
+volatile __global uint*restrict output, __global uint4*restrict padcache,
+const uint4 midstate0, const uint4 midstate16, const uint target)
+{
+	uint gid = get_global_id(0);
+	uint4 X[8];
+	uint4 tstate0, tstate1, ostate0, ostate1, tmp0, tmp1;
+	uint4 data = (uint4)(input[4].x,input[4].y,input[4].z,gid);
+	uint4 pad0 = midstate0, pad1 = midstate16;
+
+	SHA256(&pad0,&pad1, data, (uint4)(K[84],0,0,0), (uint4)(0,0,0,0), (uint4)(0,0,0, K[86]));
+	SHA256_fresh(&ostate0,&ostate1, pad0^ K[82], pad1^ K[82], K[82], K[82]);
+	SHA256_fresh(&tstate0,&tstate1, pad0^ K[83], pad1^ K[83], K[83], K[83]);
+
+	tmp0 = tstate0;
+	tmp1 = tstate1;
+	SHA256(&tstate0, &tstate1, input[0],input[1],input[2],input[3]);
+
+#pragma unroll
+	for (uint i=0; i<4; i++)
+	{
+		pad0 = tstate0;
+		pad1 = tstate1;
+		X[i*2 ] = ostate0;
+		X[i*2+1] = ostate1;
+
+		SHA256(&pad0,&pad1, data, (uint4)(i+1,K[84],0,0), (uint4)(0,0,0,0), (uint4)(0,0,0, K[87]));
+		SHA256(X+i*2,X+i*2+1, pad0, pad1, (uint4)(K[84], 0U, 0U, 0U), (uint4)(0U, 0U, 0U, K[88]));
+	}
+	scrypt_core(X,padcache);
+	SHA256(&tmp0,&tmp1, X[0], X[1], X[2], X[3]);
+	SHA256(&tmp0,&tmp1, X[4], X[5], X[6], X[7]);
+	SHA256_fixed(&tmp0,&tmp1);
+	SHA256(&ostate0,&ostate1, tmp0, tmp1, (uint4)(K[84], 0U, 0U, 0U), (uint4)(0U, 0U, 0U, K[88]));
+
+	bool result = (EndianSwap(ostate1.w) <= target);
+	if (result)
+		SETFOUND(gid);
+}

+ 5 - 2
opencl/scrypt.cl

@@ -1,6 +1,9 @@
 /*-
 /*-
- * Copyright 2009 Colin Percival, 2011 ArtForz, 2011 pooler, 2012 mtrlt,
- * 2012-2013 Con Kolivas.
+ * Copyright 2009 Colin Percival
+ * Copyright 2011 ArtForz
+ * Copyright 2011 pooler
+ * Copyright 2012 mtrlt
+ * Copyright 2012-2013 Con Kolivas
  * All rights reserved.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * Redistribution and use in source and binary forms, with or without

+ 832 - 0
opencl/zuikkis.cl

@@ -0,0 +1,832 @@
+/*-
+ * Copyright 2009 Colin Percival, 2011 ArtForz, 2011 pooler, 2012 mtrlt,
+ * 2012-2013 Con Kolivas.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * This file was originally written by Colin Percival as part of the Tarsnap
+ * online backup system.
+ */
+
+// kernel-interface: scrypt
+
+__constant uint ES[2] = { 0x00FF00FF, 0xFF00FF00 };
+__constant uint K[] = {
+	0x428a2f98U,
+	0x71374491U,
+	0xb5c0fbcfU,
+	0xe9b5dba5U,
+	0x3956c25bU,
+	0x59f111f1U,
+	0x923f82a4U,
+	0xab1c5ed5U,
+	0xd807aa98U,
+	0x12835b01U,
+	0x243185beU, // 10
+	0x550c7dc3U,
+	0x72be5d74U,
+	0x80deb1feU,
+	0x9bdc06a7U,
+	0xe49b69c1U,
+	0xefbe4786U,
+	0x0fc19dc6U,
+	0x240ca1ccU,
+	0x2de92c6fU,
+	0x4a7484aaU, // 20
+	0x5cb0a9dcU,
+	0x76f988daU,
+	0x983e5152U,
+	0xa831c66dU,
+	0xb00327c8U,
+	0xbf597fc7U,
+	0xc6e00bf3U,
+	0xd5a79147U,
+	0x06ca6351U,
+	0x14292967U, // 30
+	0x27b70a85U,
+	0x2e1b2138U,
+	0x4d2c6dfcU,
+	0x53380d13U,
+	0x650a7354U,
+	0x766a0abbU,
+	0x81c2c92eU,
+	0x92722c85U,
+	0xa2bfe8a1U,
+	0xa81a664bU, // 40
+	0xc24b8b70U,
+	0xc76c51a3U,
+	0xd192e819U,
+	0xd6990624U,
+	0xf40e3585U,
+	0x106aa070U,
+	0x19a4c116U,
+	0x1e376c08U,
+	0x2748774cU,
+	0x34b0bcb5U, // 50
+	0x391c0cb3U,
+	0x4ed8aa4aU,
+	0x5b9cca4fU,
+	0x682e6ff3U,
+	0x748f82eeU,
+	0x78a5636fU,
+	0x84c87814U,
+	0x8cc70208U,
+	0x90befffaU,
+	0xa4506cebU, // 60
+	0xbef9a3f7U,
+	0xc67178f2U,
+	0x98c7e2a2U,
+	0xfc08884dU,
+	0xcd2a11aeU,
+	0x510e527fU,
+	0x9b05688cU,
+	0xC3910C8EU,
+	0xfb6feee7U,
+	0x2a01a605U, // 70
+	0x0c2e12e0U,
+	0x4498517BU,
+	0x6a09e667U,
+	0xa4ce148bU,
+	0x95F61999U,
+	0xc19bf174U,
+	0xBB67AE85U,
+	0x3C6EF372U,
+	0xA54FF53AU,
+	0x1F83D9ABU, // 80
+	0x5BE0CD19U,
+	0x5C5C5C5CU,
+	0x36363636U,
+	0x80000000U,
+	0x000003FFU,
+	0x00000280U,
+	0x000004a0U,
+	0x00000300U
+};
+
+#define rotl(x,y) rotate(x,y)
+#define Ch(x,y,z) bitselect(z,y,x)
+#define Maj(x,y,z) Ch((x^z),y,z)
+
+#define EndianSwap(n) (rotl(n & ES[0], 24U)|rotl(n & ES[1], 8U))
+
+#define Tr2(x)		(rotl(x, 30U) ^ rotl(x, 19U) ^ rotl(x, 10U))
+#define Tr1(x)		(rotl(x, 26U) ^ rotl(x, 21U) ^ rotl(x, 7U))
+#define Wr2(x)		(rotl(x, 25U) ^ rotl(x, 14U) ^ (x>>3U))
+#define Wr1(x)		(rotl(x, 15U) ^ rotl(x, 13U) ^ (x>>10U))
+
+#define RND(a, b, c, d, e, f, g, h, k)	\
+	h += Tr1(e); 			\
+	h += Ch(e, f, g); 		\
+	h += k;				\
+	d += h;				\
+	h += Tr2(a); 			\
+	h += Maj(a, b, c);
+
+void SHA256(uint4*restrict state0,uint4*restrict state1, const uint4 block0, const uint4 block1, const uint4 block2, const uint4 block3)
+{
+	uint4 S0 = *state0;
+	uint4 S1 = *state1;
+	
+#define A S0.x
+#define B S0.y
+#define C S0.z
+#define D S0.w
+#define E S1.x
+#define F S1.y
+#define G S1.z
+#define H S1.w
+
+	uint4 W[4];
+
+	W[ 0].x = block0.x;
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[0]);
+	W[ 0].y = block0.y;
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[1]);
+	W[ 0].z = block0.z;
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[2]);
+	W[ 0].w = block0.w;
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[3]);
+
+	W[ 1].x = block1.x;
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[4]);
+	W[ 1].y = block1.y;
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[5]);
+	W[ 1].z = block1.z;
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[6]);
+	W[ 1].w = block1.w;
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[7]);
+
+	W[ 2].x = block2.x;
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[8]);
+	W[ 2].y = block2.y;
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[9]);
+	W[ 2].z = block2.z;
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[10]);
+	W[ 2].w = block2.w;
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[11]);
+
+	W[ 3].x = block3.x;
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[12]);
+	W[ 3].y = block3.y;
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[13]);
+	W[ 3].z = block3.z;
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[14]);
+	W[ 3].w = block3.w;
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[76]);
+
+	W[ 0].x += Wr1(W[ 3].z) + W[ 2].y + Wr2(W[ 0].y);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[15]);
+
+	W[ 0].y += Wr1(W[ 3].w) + W[ 2].z + Wr2(W[ 0].z);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[16]);
+
+	W[ 0].z += Wr1(W[ 0].x) + W[ 2].w + Wr2(W[ 0].w);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[17]);
+
+	W[ 0].w += Wr1(W[ 0].y) + W[ 3].x + Wr2(W[ 1].x);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[18]);
+
+	W[ 1].x += Wr1(W[ 0].z) + W[ 3].y + Wr2(W[ 1].y);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[19]);
+
+	W[ 1].y += Wr1(W[ 0].w) + W[ 3].z + Wr2(W[ 1].z);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[20]);
+
+	W[ 1].z += Wr1(W[ 1].x) + W[ 3].w + Wr2(W[ 1].w);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[21]);
+
+	W[ 1].w += Wr1(W[ 1].y) + W[ 0].x + Wr2(W[ 2].x);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[22]);
+
+	W[ 2].x += Wr1(W[ 1].z) + W[ 0].y + Wr2(W[ 2].y);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[23]);
+
+	W[ 2].y += Wr1(W[ 1].w) + W[ 0].z + Wr2(W[ 2].z);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[24]);
+
+	W[ 2].z += Wr1(W[ 2].x) + W[ 0].w + Wr2(W[ 2].w);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[25]);
+
+	W[ 2].w += Wr1(W[ 2].y) + W[ 1].x + Wr2(W[ 3].x);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[26]);
+
+	W[ 3].x += Wr1(W[ 2].z) + W[ 1].y + Wr2(W[ 3].y);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[27]);
+
+	W[ 3].y += Wr1(W[ 2].w) + W[ 1].z + Wr2(W[ 3].z);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[28]);
+
+	W[ 3].z += Wr1(W[ 3].x) + W[ 1].w + Wr2(W[ 3].w);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[29]);
+
+	W[ 3].w += Wr1(W[ 3].y) + W[ 2].x + Wr2(W[ 0].x);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[30]);
+
+	W[ 0].x += Wr1(W[ 3].z) + W[ 2].y + Wr2(W[ 0].y);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[31]);
+
+	W[ 0].y += Wr1(W[ 3].w) + W[ 2].z + Wr2(W[ 0].z);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[32]);
+
+	W[ 0].z += Wr1(W[ 0].x) + W[ 2].w + Wr2(W[ 0].w);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[33]);
+
+	W[ 0].w += Wr1(W[ 0].y) + W[ 3].x + Wr2(W[ 1].x);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[34]);
+
+	W[ 1].x += Wr1(W[ 0].z) + W[ 3].y + Wr2(W[ 1].y);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[35]);
+
+	W[ 1].y += Wr1(W[ 0].w) + W[ 3].z + Wr2(W[ 1].z);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[36]);
+
+	W[ 1].z += Wr1(W[ 1].x) + W[ 3].w + Wr2(W[ 1].w);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[37]);
+
+	W[ 1].w += Wr1(W[ 1].y) + W[ 0].x + Wr2(W[ 2].x);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[38]);
+
+	W[ 2].x += Wr1(W[ 1].z) + W[ 0].y + Wr2(W[ 2].y);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[39]);
+
+	W[ 2].y += Wr1(W[ 1].w) + W[ 0].z + Wr2(W[ 2].z);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[40]);
+
+	W[ 2].z += Wr1(W[ 2].x) + W[ 0].w + Wr2(W[ 2].w);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[41]);
+
+	W[ 2].w += Wr1(W[ 2].y) + W[ 1].x + Wr2(W[ 3].x);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[42]);
+
+	W[ 3].x += Wr1(W[ 2].z) + W[ 1].y + Wr2(W[ 3].y);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[43]);
+
+	W[ 3].y += Wr1(W[ 2].w) + W[ 1].z + Wr2(W[ 3].z);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[44]);
+
+	W[ 3].z += Wr1(W[ 3].x) + W[ 1].w + Wr2(W[ 3].w);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[45]);
+
+	W[ 3].w += Wr1(W[ 3].y) + W[ 2].x + Wr2(W[ 0].x);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[46]);
+
+	W[ 0].x += Wr1(W[ 3].z) + W[ 2].y + Wr2(W[ 0].y);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[47]);
+
+	W[ 0].y += Wr1(W[ 3].w) + W[ 2].z + Wr2(W[ 0].z);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[48]);
+
+	W[ 0].z += Wr1(W[ 0].x) + W[ 2].w + Wr2(W[ 0].w);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[49]);
+
+	W[ 0].w += Wr1(W[ 0].y) + W[ 3].x + Wr2(W[ 1].x);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[50]);
+
+	W[ 1].x += Wr1(W[ 0].z) + W[ 3].y + Wr2(W[ 1].y);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[51]);
+
+	W[ 1].y += Wr1(W[ 0].w) + W[ 3].z + Wr2(W[ 1].z);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[52]);
+
+	W[ 1].z += Wr1(W[ 1].x) + W[ 3].w + Wr2(W[ 1].w);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[53]);
+
+	W[ 1].w += Wr1(W[ 1].y) + W[ 0].x + Wr2(W[ 2].x);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[54]);
+
+	W[ 2].x += Wr1(W[ 1].z) + W[ 0].y + Wr2(W[ 2].y);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[55]);
+
+	W[ 2].y += Wr1(W[ 1].w) + W[ 0].z + Wr2(W[ 2].z);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[56]);
+
+	W[ 2].z += Wr1(W[ 2].x) + W[ 0].w + Wr2(W[ 2].w);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[57]);
+
+	W[ 2].w += Wr1(W[ 2].y) + W[ 1].x + Wr2(W[ 3].x);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[58]);
+
+	W[ 3].x += Wr1(W[ 2].z) + W[ 1].y + Wr2(W[ 3].y);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[59]);
+
+	W[ 3].y += Wr1(W[ 2].w) + W[ 1].z + Wr2(W[ 3].z);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[60]);
+
+	W[ 3].z += Wr1(W[ 3].x) + W[ 1].w + Wr2(W[ 3].w);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[61]);
+
+	W[ 3].w += Wr1(W[ 3].y) + W[ 2].x + Wr2(W[ 0].x);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[62]);
+	
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef G
+#undef H
+
+	*state0 += S0;
+	*state1 += S1;
+}
+
+void SHA256_fresh(uint4*restrict state0,uint4*restrict state1, const uint4 block0, const uint4 block1, const uint4 block2, const uint4 block3)
+{
+#define A (*state0).x
+#define B (*state0).y
+#define C (*state0).z
+#define D (*state0).w
+#define E (*state1).x
+#define F (*state1).y
+#define G (*state1).z
+#define H (*state1).w
+
+	uint4 W[4];
+
+	W[0].x = block0.x;
+	D= K[63] +W[0].x;
+	H= K[64] +W[0].x;
+
+	W[0].y = block0.y;
+	C= K[65] +Tr1(D)+Ch(D, K[66], K[67])+W[0].y;
+	G= K[68] +C+Tr2(H)+Ch(H, K[69] ,K[70]);
+
+	W[0].z = block0.z;
+	B= K[71] +Tr1(C)+Ch(C,D,K[66])+W[0].z;
+	F= K[72] +B+Tr2(G)+Maj(G,H, K[73]);
+
+	W[0].w = block0.w;
+	A= K[74] +Tr1(B)+Ch(B,C,D)+W[0].w;
+	E= K[75] +A+Tr2(F)+Maj(F,G,H);
+
+	W[1].x = block1.x;
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[4]);
+	W[1].y = block1.y;
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[5]);
+	W[1].z = block1.z;
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[6]);
+	W[1].w = block1.w;
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[7]);
+	
+	W[2].x = block2.x;
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[8]);
+	W[2].y = block2.y;
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[9]);
+	W[2].z = block2.z;
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[10]);
+	W[2].w = block2.w;
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[11]);
+	
+	W[3].x = block3.x;
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[12]);
+	W[3].y = block3.y;
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[13]);
+	W[3].z = block3.z;
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[14]);
+	W[3].w = block3.w;
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[76]);
+
+	W[0].x += Wr1(W[3].z) + W[2].y + Wr2(W[0].y);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[15]);
+
+	W[0].y += Wr1(W[3].w) + W[2].z + Wr2(W[0].z);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[16]);
+
+	W[0].z += Wr1(W[0].x) + W[2].w + Wr2(W[0].w);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[17]);
+
+	W[0].w += Wr1(W[0].y) + W[3].x + Wr2(W[1].x);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[18]);
+
+	W[1].x += Wr1(W[0].z) + W[3].y + Wr2(W[1].y);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[19]);
+
+	W[1].y += Wr1(W[0].w) + W[3].z + Wr2(W[1].z);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[20]);
+
+	W[1].z += Wr1(W[1].x) + W[3].w + Wr2(W[1].w);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[21]);
+
+	W[1].w += Wr1(W[1].y) + W[0].x + Wr2(W[2].x);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[22]);
+
+	W[2].x += Wr1(W[1].z) + W[0].y + Wr2(W[2].y);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[23]);
+
+	W[2].y += Wr1(W[1].w) + W[0].z + Wr2(W[2].z);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[24]);
+
+	W[2].z += Wr1(W[2].x) + W[0].w + Wr2(W[2].w);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[25]);
+
+	W[2].w += Wr1(W[2].y) + W[1].x + Wr2(W[3].x);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[26]);
+
+	W[3].x += Wr1(W[2].z) + W[1].y + Wr2(W[3].y);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[27]);
+
+	W[3].y += Wr1(W[2].w) + W[1].z + Wr2(W[3].z);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[28]);
+
+	W[3].z += Wr1(W[3].x) + W[1].w + Wr2(W[3].w);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[29]);
+
+	W[3].w += Wr1(W[3].y) + W[2].x + Wr2(W[0].x);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[30]);
+
+	W[0].x += Wr1(W[3].z) + W[2].y + Wr2(W[0].y);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[31]);
+
+	W[0].y += Wr1(W[3].w) + W[2].z + Wr2(W[0].z);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[32]);
+
+	W[0].z += Wr1(W[0].x) + W[2].w + Wr2(W[0].w);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[33]);
+
+	W[0].w += Wr1(W[0].y) + W[3].x + Wr2(W[1].x);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[34]);
+
+	W[1].x += Wr1(W[0].z) + W[3].y + Wr2(W[1].y);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[35]);
+
+	W[1].y += Wr1(W[0].w) + W[3].z + Wr2(W[1].z);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[36]);
+
+	W[1].z += Wr1(W[1].x) + W[3].w + Wr2(W[1].w);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[37]);
+
+	W[1].w += Wr1(W[1].y) + W[0].x + Wr2(W[2].x);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[38]);
+
+	W[2].x += Wr1(W[1].z) + W[0].y + Wr2(W[2].y);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[39]);
+
+	W[2].y += Wr1(W[1].w) + W[0].z + Wr2(W[2].z);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[40]);
+
+	W[2].z += Wr1(W[2].x) + W[0].w + Wr2(W[2].w);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[41]);
+
+	W[2].w += Wr1(W[2].y) + W[1].x + Wr2(W[3].x);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[42]);
+
+	W[3].x += Wr1(W[2].z) + W[1].y + Wr2(W[3].y);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[43]);
+
+	W[3].y += Wr1(W[2].w) + W[1].z + Wr2(W[3].z);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[44]);
+
+	W[3].z += Wr1(W[3].x) + W[1].w + Wr2(W[3].w);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[45]);
+
+	W[3].w += Wr1(W[3].y) + W[2].x + Wr2(W[0].x);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[46]);
+
+	W[0].x += Wr1(W[3].z) + W[2].y + Wr2(W[0].y);
+	RND(A,B,C,D,E,F,G,H, W[0].x+ K[47]);
+
+	W[0].y += Wr1(W[3].w) + W[2].z + Wr2(W[0].z);
+	RND(H,A,B,C,D,E,F,G, W[0].y+ K[48]);
+
+	W[0].z += Wr1(W[0].x) + W[2].w + Wr2(W[0].w);
+	RND(G,H,A,B,C,D,E,F, W[0].z+ K[49]);
+
+	W[0].w += Wr1(W[0].y) + W[3].x + Wr2(W[1].x);
+	RND(F,G,H,A,B,C,D,E, W[0].w+ K[50]);
+
+	W[1].x += Wr1(W[0].z) + W[3].y + Wr2(W[1].y);
+	RND(E,F,G,H,A,B,C,D, W[1].x+ K[51]);
+
+	W[1].y += Wr1(W[0].w) + W[3].z + Wr2(W[1].z);
+	RND(D,E,F,G,H,A,B,C, W[1].y+ K[52]);
+
+	W[1].z += Wr1(W[1].x) + W[3].w + Wr2(W[1].w);
+	RND(C,D,E,F,G,H,A,B, W[1].z+ K[53]);
+
+	W[1].w += Wr1(W[1].y) + W[0].x + Wr2(W[2].x);
+	RND(B,C,D,E,F,G,H,A, W[1].w+ K[54]);
+
+	W[2].x += Wr1(W[1].z) + W[0].y + Wr2(W[2].y);
+	RND(A,B,C,D,E,F,G,H, W[2].x+ K[55]);
+
+	W[2].y += Wr1(W[1].w) + W[0].z + Wr2(W[2].z);
+	RND(H,A,B,C,D,E,F,G, W[2].y+ K[56]);
+
+	W[2].z += Wr1(W[2].x) + W[0].w + Wr2(W[2].w);
+	RND(G,H,A,B,C,D,E,F, W[2].z+ K[57]);
+
+	W[2].w += Wr1(W[2].y) + W[1].x + Wr2(W[3].x);
+	RND(F,G,H,A,B,C,D,E, W[2].w+ K[58]);
+
+	W[3].x += Wr1(W[2].z) + W[1].y + Wr2(W[3].y);
+	RND(E,F,G,H,A,B,C,D, W[3].x+ K[59]);
+
+	W[3].y += Wr1(W[2].w) + W[1].z + Wr2(W[3].z);
+	RND(D,E,F,G,H,A,B,C, W[3].y+ K[60]);
+
+	W[3].z += Wr1(W[3].x) + W[1].w + Wr2(W[3].w);
+	RND(C,D,E,F,G,H,A,B, W[3].z+ K[61]);
+
+	W[3].w += Wr1(W[3].y) + W[2].x + Wr2(W[0].x);
+	RND(B,C,D,E,F,G,H,A, W[3].w+ K[62]);
+	
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef G
+#undef H
+
+	*state0 += (uint4)(K[73], K[77], K[78], K[79]);
+	*state1 += (uint4)(K[66], K[67], K[80], K[81]);
+}
+
+__constant uint fixedW[64] =
+{
+	0x428a2f99,0xf1374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
+	0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf794,
+	0xf59b89c2,0x73924787,0x23c6886e,0xa42ca65c,0x15ed3627,0x4d6edcbf,0xe28217fc,0xef02488f,
+	0xb707775c,0x0468c23f,0xe7e72b4c,0x49e1f1a2,0x4b99c816,0x926d1570,0xaa0fc072,0xadb36e2c,
+	0xad87a3ea,0xbcb1d3a3,0x7b993186,0x562b9420,0xbff3ca0c,0xda4b0c23,0x6cd8711a,0x8f337caa,
+	0xc91b1417,0xc359dce1,0xa83253a7,0x3b13c12d,0x9d3d725d,0xd9031a84,0xb1a03340,0x16f58012,
+	0xe64fb6a2,0xe84d923a,0xe93a5730,0x09837686,0x078ff753,0x29833341,0xd5de0b7e,0x6948ccf4,
+	0xe0a1adbe,0x7c728e11,0x511c78e4,0x315b45bd,0xfca71413,0xea28f96a,0x79703128,0x4e1ef848,
+};
+
+void SHA256_fixed(uint4*restrict state0,uint4*restrict state1)
+{
+	uint4 S0 = *state0;
+	uint4 S1 = *state1;
+
+#define A S0.x
+#define B S0.y
+#define C S0.z
+#define D S0.w
+#define E S1.x
+#define F S1.y
+#define G S1.z
+#define H S1.w
+
+	RND(A,B,C,D,E,F,G,H, fixedW[0]);
+	RND(H,A,B,C,D,E,F,G, fixedW[1]);
+	RND(G,H,A,B,C,D,E,F, fixedW[2]);
+	RND(F,G,H,A,B,C,D,E, fixedW[3]);
+	RND(E,F,G,H,A,B,C,D, fixedW[4]);
+	RND(D,E,F,G,H,A,B,C, fixedW[5]);
+	RND(C,D,E,F,G,H,A,B, fixedW[6]);
+	RND(B,C,D,E,F,G,H,A, fixedW[7]);
+	RND(A,B,C,D,E,F,G,H, fixedW[8]);
+	RND(H,A,B,C,D,E,F,G, fixedW[9]);
+	RND(G,H,A,B,C,D,E,F, fixedW[10]);
+	RND(F,G,H,A,B,C,D,E, fixedW[11]);
+	RND(E,F,G,H,A,B,C,D, fixedW[12]);
+	RND(D,E,F,G,H,A,B,C, fixedW[13]);
+	RND(C,D,E,F,G,H,A,B, fixedW[14]);
+	RND(B,C,D,E,F,G,H,A, fixedW[15]);
+	RND(A,B,C,D,E,F,G,H, fixedW[16]);
+	RND(H,A,B,C,D,E,F,G, fixedW[17]);
+	RND(G,H,A,B,C,D,E,F, fixedW[18]);
+	RND(F,G,H,A,B,C,D,E, fixedW[19]);
+	RND(E,F,G,H,A,B,C,D, fixedW[20]);
+	RND(D,E,F,G,H,A,B,C, fixedW[21]);
+	RND(C,D,E,F,G,H,A,B, fixedW[22]);
+	RND(B,C,D,E,F,G,H,A, fixedW[23]);
+	RND(A,B,C,D,E,F,G,H, fixedW[24]);
+	RND(H,A,B,C,D,E,F,G, fixedW[25]);
+	RND(G,H,A,B,C,D,E,F, fixedW[26]);
+	RND(F,G,H,A,B,C,D,E, fixedW[27]);
+	RND(E,F,G,H,A,B,C,D, fixedW[28]);
+	RND(D,E,F,G,H,A,B,C, fixedW[29]);
+	RND(C,D,E,F,G,H,A,B, fixedW[30]);
+	RND(B,C,D,E,F,G,H,A, fixedW[31]);
+	RND(A,B,C,D,E,F,G,H, fixedW[32]);
+	RND(H,A,B,C,D,E,F,G, fixedW[33]);
+	RND(G,H,A,B,C,D,E,F, fixedW[34]);
+	RND(F,G,H,A,B,C,D,E, fixedW[35]);
+	RND(E,F,G,H,A,B,C,D, fixedW[36]);
+	RND(D,E,F,G,H,A,B,C, fixedW[37]);
+	RND(C,D,E,F,G,H,A,B, fixedW[38]);
+	RND(B,C,D,E,F,G,H,A, fixedW[39]);
+	RND(A,B,C,D,E,F,G,H, fixedW[40]);
+	RND(H,A,B,C,D,E,F,G, fixedW[41]);
+	RND(G,H,A,B,C,D,E,F, fixedW[42]);
+	RND(F,G,H,A,B,C,D,E, fixedW[43]);
+	RND(E,F,G,H,A,B,C,D, fixedW[44]);
+	RND(D,E,F,G,H,A,B,C, fixedW[45]);
+	RND(C,D,E,F,G,H,A,B, fixedW[46]);
+	RND(B,C,D,E,F,G,H,A, fixedW[47]);
+	RND(A,B,C,D,E,F,G,H, fixedW[48]);
+	RND(H,A,B,C,D,E,F,G, fixedW[49]);
+	RND(G,H,A,B,C,D,E,F, fixedW[50]);
+	RND(F,G,H,A,B,C,D,E, fixedW[51]);
+	RND(E,F,G,H,A,B,C,D, fixedW[52]);
+	RND(D,E,F,G,H,A,B,C, fixedW[53]);
+	RND(C,D,E,F,G,H,A,B, fixedW[54]);
+	RND(B,C,D,E,F,G,H,A, fixedW[55]);
+	RND(A,B,C,D,E,F,G,H, fixedW[56]);
+	RND(H,A,B,C,D,E,F,G, fixedW[57]);
+	RND(G,H,A,B,C,D,E,F, fixedW[58]);
+	RND(F,G,H,A,B,C,D,E, fixedW[59]);
+	RND(E,F,G,H,A,B,C,D, fixedW[60]);
+	RND(D,E,F,G,H,A,B,C, fixedW[61]);
+	RND(C,D,E,F,G,H,A,B, fixedW[62]);
+	RND(B,C,D,E,F,G,H,A, fixedW[63]);
+	
+#undef A
+#undef B
+#undef C
+#undef D
+#undef E
+#undef F
+#undef G
+#undef H
+	*state0 += S0;
+	*state1 += S1;
+}
+
+void shittify(uint4 B[8])
+{
+	uint4 tmp[4];
+	tmp[0] = (uint4)(B[1].x,B[2].y,B[3].z,B[0].w);
+	tmp[1] = (uint4)(B[2].x,B[3].y,B[0].z,B[1].w);
+	tmp[2] = (uint4)(B[3].x,B[0].y,B[1].z,B[2].w);
+	tmp[3] = (uint4)(B[0].x,B[1].y,B[2].z,B[3].w);
+	
+	for(uint i=0; i<4; ++i)
+		B[i] = EndianSwap(tmp[i]);
+
+	tmp[0] = (uint4)(B[5].x,B[6].y,B[7].z,B[4].w);
+	tmp[1] = (uint4)(B[6].x,B[7].y,B[4].z,B[5].w);
+	tmp[2] = (uint4)(B[7].x,B[4].y,B[5].z,B[6].w);
+	tmp[3] = (uint4)(B[4].x,B[5].y,B[6].z,B[7].w);
+	
+	for(uint i=0; i<4; ++i)
+		B[i+4] = EndianSwap(tmp[i]);
+}
+
+void unshittify(uint4 B[8])
+{
+	uint4 tmp[4];
+	tmp[0] = (uint4)(B[3].x,B[2].y,B[1].z,B[0].w);
+	tmp[1] = (uint4)(B[0].x,B[3].y,B[2].z,B[1].w);
+	tmp[2] = (uint4)(B[1].x,B[0].y,B[3].z,B[2].w);
+	tmp[3] = (uint4)(B[2].x,B[1].y,B[0].z,B[3].w);
+	
+	for(uint i=0; i<4; ++i)
+		B[i] = EndianSwap(tmp[i]);
+
+	tmp[0] = (uint4)(B[7].x,B[6].y,B[5].z,B[4].w);
+	tmp[1] = (uint4)(B[4].x,B[7].y,B[6].z,B[5].w);
+	tmp[2] = (uint4)(B[5].x,B[4].y,B[7].z,B[6].w);
+	tmp[3] = (uint4)(B[6].x,B[5].y,B[4].z,B[7].w);
+	
+	for(uint i=0; i<4; ++i)
+		B[i+4] = EndianSwap(tmp[i]);
+}
+
+void salsa(uint4 B[8])
+{
+	uint4 w[4];
+
+	for(uint i=0; i<4; ++i)
+		w[i] = (B[i]^=B[i+4]);
+
+	for(uint i=0; i<4; ++i)
+	{
+		w[0] ^= rotl(w[3]     +w[2]     , 7U);
+		w[1] ^= rotl(w[0]     +w[3]     , 9U);
+		w[2] ^= rotl(w[1]     +w[0]     ,13U);
+		w[3] ^= rotl(w[2]     +w[1]     ,18U);
+		w[2] ^= rotl(w[3].wxyz+w[0].zwxy, 7U);
+		w[1] ^= rotl(w[2].wxyz+w[3].zwxy, 9U);
+		w[0] ^= rotl(w[1].wxyz+w[2].zwxy,13U);
+		w[3] ^= rotl(w[0].wxyz+w[1].zwxy,18U);
+	}
+
+	for(uint i=0; i<4; ++i)
+		w[i] = (B[i+4]^=(B[i]+=w[i]));
+
+	for(uint i=0; i<4; ++i)
+	{
+		w[0] ^= rotl(w[3]     +w[2]     , 7U);
+		w[1] ^= rotl(w[0]     +w[3]     , 9U);
+		w[2] ^= rotl(w[1]     +w[0]     ,13U);
+		w[3] ^= rotl(w[2]     +w[1]     ,18U);
+		w[2] ^= rotl(w[3].wxyz+w[0].zwxy, 7U);
+		w[1] ^= rotl(w[2].wxyz+w[3].zwxy, 9U);
+		w[0] ^= rotl(w[1].wxyz+w[2].zwxy,13U);
+		w[3] ^= rotl(w[0].wxyz+w[1].zwxy,18U);
+	}
+
+	for(uint i=0; i<4; ++i)
+		B[i+4] += w[i];
+}
+
+#define Coord(x,y,z) x+y*(x ## SIZE)+z*(y ## SIZE)*(x ## SIZE)
+#define CO Coord(z,x,y)
+
+void scrypt_core(uint4 X[8], __global uint4*restrict lookup)
+{
+	shittify(X);
+	const uint zSIZE = 8;
+	const uint ySIZE = (1024/LOOKUP_GAP+(1024%LOOKUP_GAP>0));
+	const uint xSIZE = CONCURRENT_THREADS;
+	uint x = get_global_id(0)%xSIZE;
+
+	for(uint y=0; y<1024/LOOKUP_GAP; ++y)
+	{
+		for(uint z=0; z<zSIZE; ++z)
+			lookup[CO] = X[z];
+		for(uint i=0; i<LOOKUP_GAP; ++i)
+			salsa(X);
+	}
+	for (uint i=0; i<1024; ++i)
+	{
+		uint j = X[7].x & K[85];
+		uint y = (j/LOOKUP_GAP);
+
+		if (j&1)
+		{
+			uint4 V[8];
+			for(uint z=0; z<zSIZE; ++z)
+				V[z] = lookup[CO];
+
+			salsa(V);
+
+			for(uint z=0; z<zSIZE; ++z)
+				X[z] ^= V[z];
+		} else {
+			for(uint z=0; z<zSIZE; ++z)
+				X[z] ^= lookup[CO];
+		}
+
+		salsa(X);
+	}
+	unshittify(X);
+}
+
+#define SCRYPT_FOUND (0xFF)
+#define SETFOUND(Xnonce) output[output[SCRYPT_FOUND]++] = Xnonce
+
+__attribute__((reqd_work_group_size(WORKSIZE, 1, 1)))
+__kernel void search(__global const uint4 * restrict input,
+volatile __global uint*restrict output, __global uint4*restrict padcache,
+const uint4 midstate0, const uint4 midstate16, const uint target)
+{
+	uint gid = get_global_id(0);
+	uint4 X[8];
+	uint4 tstate0, tstate1, ostate0, ostate1, tmp0, tmp1;
+	uint4 data = (uint4)(input[4].x,input[4].y,input[4].z,gid);
+	uint4 pad0 = midstate0, pad1 = midstate16;
+
+	SHA256(&pad0,&pad1, data, (uint4)(K[84],0,0,0), (uint4)(0,0,0,0), (uint4)(0,0,0, K[86]));
+	SHA256_fresh(&ostate0,&ostate1, pad0^ K[82], pad1^ K[82], K[82], K[82]);
+	SHA256_fresh(&tstate0,&tstate1, pad0^ K[83], pad1^ K[83], K[83], K[83]);
+
+	tmp0 = tstate0;
+	tmp1 = tstate1;
+	SHA256(&tstate0, &tstate1, input[0],input[1],input[2],input[3]);
+
+	for (uint i=0; i<4; i++)
+	{
+		pad0 = tstate0;
+		pad1 = tstate1;
+		X[i*2 ] = ostate0;
+		X[i*2+1] = ostate1;
+
+		SHA256(&pad0,&pad1, data, (uint4)(i+1,K[84],0,0), (uint4)(0,0,0,0), (uint4)(0,0,0, K[87]));
+		SHA256(X+i*2,X+i*2+1, pad0, pad1, (uint4)(K[84], 0U, 0U, 0U), (uint4)(0U, 0U, 0U, K[88]));
+	}
+	scrypt_core(X,padcache);
+	SHA256(&tmp0,&tmp1, X[0], X[1], X[2], X[3]);
+	SHA256(&tmp0,&tmp1, X[4], X[5], X[6], X[7]);
+	SHA256_fixed(&tmp0,&tmp1);
+	SHA256(&ostate0,&ostate1, tmp0, tmp1, (uint4)(K[84], 0U, 0U, 0U), (uint4)(0U, 0U, 0U, K[88]));
+
+	bool result = (EndianSwap(ostate1.w) <= target);
+	if (result)
+		SETFOUND(gid);
+}

+ 14 - 22
openwrt/bfgminer/Makefile

@@ -1,5 +1,5 @@
 #
 #
-# Copyright 2013 Luke Dashjr
+# Copyright 2013-2014 Luke Dashjr
 #
 #
 # This program is free software; you can redistribute it and/or modify it
 # 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
 # under the terms of the GNU General Public License as published by the Free
@@ -11,10 +11,10 @@ include $(TOPDIR)/rules.mk
 
 
 PKG_NAME:=bfgminer
 PKG_NAME:=bfgminer
 PKG_TITLE:=BFGMiner
 PKG_TITLE:=BFGMiner
-PKG_VERSION:=3.10.0
+PKG_VERSION:=4.7.0
 PKG_RELEASE:=1
 PKG_RELEASE:=1
 
 
-PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tbz2
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).txz
 PKG_SOURCE_URL:=http://luke.dashjr.org/programs/bitcoin/files/$(PKG_NAME)/$(PKG_VERSION)/
 PKG_SOURCE_URL:=http://luke.dashjr.org/programs/bitcoin/files/$(PKG_NAME)/$(PKG_VERSION)/
 
 
 PKG_INSTALL:=1
 PKG_INSTALL:=1
@@ -62,6 +62,10 @@ config PACKAGE_$(PKG_NAME)_libusb
 	bool "Build with libusb support (X6500 & ZTEX)"
 	bool "Build with libusb support (X6500 & ZTEX)"
 	depends on PACKAGE_$(PKG_NAME)
 	depends on PACKAGE_$(PKG_NAME)
 	default y
 	default y
+config PACKAGE_$(PKG_NAME)_scrypt
+	bool "Build with scrypt algorithm support"
+	depends on PACKAGE_$(PKG_NAME)
+	default y
 endef
 endef
 
 
 ifndef CONFIG_PACKAGE_$(PKG_NAME)_curses
 ifndef CONFIG_PACKAGE_$(PKG_NAME)_curses
@@ -83,7 +87,11 @@ CONFIGURE_ARGS += --with-libmicrohttpd
 endif
 endif
 
 
 ifndef CONFIG_PACKAGE_$(PKG_NAME)_libusb
 ifndef CONFIG_PACKAGE_$(PKG_NAME)_libusb
-CONFIGURE_ARGS += --disable-x6500 --disable-ztex
+CONFIGURE_ARGS += --without-libusb
+endif
+
+ifdef CONFIG_PACKAGE_$(PKG_NAME)_scrypt
+CONFIGURE_ARGS += --enable-scrypt
 endif
 endif
 
 
 TARGET_CFLAGS += -std=gnu99
 TARGET_CFLAGS += -std=gnu99
@@ -91,6 +99,7 @@ TARGET_CFLAGS += -Iuthash-1.9.8/src
 
 
 CONFIGURE_ARGS += --without-libudev
 CONFIGURE_ARGS += --without-libudev
 CONFIGURE_ARGS += --without-sensors
 CONFIGURE_ARGS += --without-sensors
+CONFIGURE_ARGS += --without-system-libbase58
 
 
 define Build/Prepare
 define Build/Prepare
 	$(call Build/Prepare/Default)
 	$(call Build/Prepare/Default)
@@ -109,27 +118,10 @@ define Package/$(PKG_NAME)/install
 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(PKG_NAME) $(1)/usr/bin
 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(PKG_NAME) $(1)/usr/bin
 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(PKG_NAME)-rpc $(1)/usr/bin
 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/$(PKG_NAME)-rpc $(1)/usr/bin
 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/libblkmaker*.so* $(1)/usr/lib
 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/libblkmaker*.so* $(1)/usr/lib
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/libbase58*.so* $(1)/usr/lib
 endef
 endef
 
 
 ALL_$(PKG_NAME)_PACKAGES += $(PKG_NAME)
 ALL_$(PKG_NAME)_PACKAGES += $(PKG_NAME)
 
 
-#### BitForce firmware flash ####
-
-define Package/bitforce-firmware-flash
-$(call Package/$(PKG_NAME)/Default)
-	TITLE:=BitForce firmware flash tool
-endef
-
-define Package/bitforce-firmware-flash/description
-BitForce firmware flash tool
-endef
-
-define Package/bitforce-firmware-flash/install
-	$(INSTALL_DIR) $(1)/usr/bin
-	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/bitforce-firmware-flash $(1)/usr/bin
-endef
-
-ALL_$(PKG_NAME)_PACKAGES += bitforce-firmware-flash
-
 
 
 $(foreach bitstream,$(ALL_$(PKG_NAME)_PACKAGES),$(eval $(call BuildPackage,$(bitstream))))
 $(foreach bitstream,$(ALL_$(PKG_NAME)_PACKAGES),$(eval $(call BuildPackage,$(bitstream))))

+ 1 - 1
openwrt/multibuild.sh

@@ -52,7 +52,7 @@ for cfn in $vcfglist; do
 	yes '' | make oldconfig
 	yes '' | make oldconfig
 	make {tools,toolchain}/install package/bfgminer/{clean,compile}
 	make {tools,toolchain}/install package/bfgminer/{clean,compile}
 	mkdir "$reporoot/$plat" -pv
 	mkdir "$reporoot/$plat" -pv
-	cp -v "bin/$plat/packages/"b{fgminer,itforce}*_${plat}.ipk "$reporoot/$plat/"
+	cp -v "bin/$plat/packages/"bfgminer*_${plat}.ipk "$reporoot/$plat/"
 	if [ -d "$reporoot/${BITSTREAM_PKG_PATH}" ]; then
 	if [ -d "$reporoot/${BITSTREAM_PKG_PATH}" ]; then
 	(
 	(
 		cd "$reporoot/$plat"
 		cd "$reporoot/$plat"

+ 0 - 11
packaging/suse/Makefile.am.patch

@@ -1,11 +0,0 @@
---- a/Makefile.am       2013-04-06 14:46:37.955969119 +0200
-+++ b/Makefile.am       2013-04-06 14:46:51.394965657 +0200
-@@ -38,7 +38,7 @@
- if NEED_LIBBLKMAKER
- SUBDIRS           += libblkmaker
- bfgminer_CPPFLAGS += -Ilibblkmaker
--bfgminer_LDFLAGS  += -Llibblkmaker/.libs -Wl,-rpath,libblkmaker/.libs
-+bfgminer_LDFLAGS  += -Llibblkmaker/.libs
- bfgminer_LDADD    += -lblkmaker_jansson-0.1 -lblkmaker-0.1
-
- if HAVE_CYGWIN

+ 0 - 11
packaging/suse/Makefile.in.patch

@@ -1,11 +0,0 @@
---- a/Makefile.in	2013-04-04 18:03:11.198185097 +0200
-+++ b/Makefile.in	2013-04-04 18:03:39.020202287 +0200
-@@ -57,7 +57,7 @@
- bin_PROGRAMS = bfgminer$(EXEEXT) $(am__EXEEXT_1) bfgminer-rpc$(EXEEXT)
- @NEED_LIBBLKMAKER_TRUE@am__append_1 = libblkmaker
- @NEED_LIBBLKMAKER_TRUE@am__append_2 = -Ilibblkmaker
--@NEED_LIBBLKMAKER_TRUE@am__append_3 = -Llibblkmaker/.libs -Wl,-rpath,libblkmaker/.libs
-+@NEED_LIBBLKMAKER_TRUE@am__append_3 = -Llibblkmaker/.libs
- @NEED_LIBBLKMAKER_TRUE@am__append_4 = -lblkmaker-0.1 -lblkmaker_jansson-0.1
- @HAVE_CYGWIN_TRUE@@NEED_LIBBLKMAKER_TRUE@am__append_5 = cygblkmaker-0.1-0.dll cygblkmaker_jansson-0.1-0.dll
- @HAS_SCRYPT_TRUE@am__append_6 = scrypt.c scrypt.h

+ 0 - 9
packaging/suse/bfgminer.changes

@@ -1,9 +0,0 @@
--------------------------------------------------------------------
-Sat Apr  6 14:43:43 CEST 2013 - berendt@b1-systems.de
-
-- updated to version 3.0.0
-
--------------------------------------------------------------------
-Thu Apr  4 17:06:56 CEST 2013 - berendt@b1-systems.de
-
-- initial package for bfgminer version 2.99.1

+ 0 - 6
packaging/suse/bfgminer.rpmlintrc

@@ -1,6 +0,0 @@
-addFilter("devel-file-in-non-devel-package")
-addFilter("no-manual-page-for-binary")
-addFilter("wrong-script-end-of-line-encoding")
-addFilter("standard-dir-owned-by-package")
-addFilter("script-without-shebang")
-addFilter("binary-or-shlib-calls-gethostbyname")

+ 0 - 90
packaging/suse/bfgminer.spec

@@ -1,90 +0,0 @@
-#
-# Copyright (c) 2013 Christian Berendt.
-#
-# All modifications and additions to the file contributed by third parties
-# remain the property of their copyright owners, unless otherwise agreed
-# upon. The license for this file, and modifications and additions to the
-# file, is the same license as for the pristine package itself (unless the
-# license for the pristine package is not an Open Source License, in which
-# case the license is the MIT License). An "Open Source License" is a
-# license that conforms to the Open Source Definition (Version 1.9)
-# published by the Open Source Initiative.
-#
-# Please submit bugfixes or comments via http://bugs.opensuse.org/
-#
-
-Name:           bfgminer
-Version:        3.0.0
-Release:        0
-Summary:        A BitCoin miner
-License:        GPL-3.0
-Group:          Productivity/Other
-Url:            https://github.com/luke-jr/bfgminer
-BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-Source:         http://luke.dashjr.org/programs/bitcoin/files/bfgminer/%{version}/%{name}-%{version}.tbz2
-Patch0:         Makefile.in.patch
-Patch1:         Makefile.am.patch
-
-BuildRequires:  automake
-BuildRequires:  libtool
-BuildRequires:  pkg-config
-BuildRequires:  make
-BuildRequires:  gcc
-BuildRequires:  yasm
-BuildRequires:  libjansson-devel
-BuildRequires:  libcurl-devel
-BuildRequires:  libusb-devel
-BuildRequires:  libudev-devel
-BuildRequires:  ncurses-devel
-
-%description
-This is a multi-threaded multi-pool FPGA, GPU and CPU miner with ATI GPU
-monitoring, (over)clocking and fanspeed support for bitcoin and derivative
-coins.
-
-%package devel
-Summary:        A BitCoin miner
-Group:          Development/Libraries/C and C++
-Requires:       %{name} = %{version}-%{release}
-
-%description devel
-This is a multi-threaded multi-pool FPGA, GPU and CPU miner with ATI GPU
-monitoring, (over)clocking and fanspeed support for bitcoin and derivative
-coins.
-
-%prep
-%setup -q
-%patch0 -p1
-%patch1 -p1
-%configure \
-  --enable-cpumining \
-  --enable-scrypt
-
-%build
-make %{?_smp_mflags}
-
-%install
-%make_install
-
-install -d -m 755 %{buildroot}/%{_datadir}/%{name}
-mv %{buildroot}%{_bindir}/*.cl %{buildroot}/%{_datadir}/%{name}
-mv %{buildroot}%{_bindir}/bitstreams %{buildroot}/%{_datadir}/%{name}
-
-%clean
-rm -rf %{buildroot}
-
-%post -p /sbin/ldconfig
-%postun -p /sbin/ldconfig
-
-%files
-%defattr(-,root,root,-)
-%{_bindir}/*
-%{_libdir}/*
-%dir %{_datadir}/%{name}
-%{_datadir}/%{name}/*
-
-%files devel
-%defattr(-,root,root,-)
-%{_includedir}/*
-
-%changelog

Some files were not shown because too many files changed in this diff