Browse Source

Merge tag 'bfgminer-3.1.2' into bigpic

BFGMiner version 3.1.2

Conflicts:
	miner.c
Luke Dashjr 12 years ago
parent
commit
e009320657
39 changed files with 1878 additions and 1130 deletions
  1. 5 0
      Makefile.am
  2. 128 0
      NEWS
  3. 36 37
      README
  4. 11 0
      README.RPC
  5. 7 9
      adl.c
  6. 33 76
      api.c
  7. 3 6
      compat.h
  8. 15 3
      configure.ac
  9. 13 0
      debian/changelog
  10. 1 1
      debian/control
  11. 19 11
      deviceapi.c
  12. 8 33
      driver-avalon.c
  13. 4 27
      driver-bf1.c
  14. 114 71
      driver-bitforce.c
  15. 0 2
      driver-cairnsmore.c
  16. 20 5
      driver-cpu.c
  17. 84 0
      driver-erupter.c
  18. 12 21
      driver-icarus.c
  19. 14 69
      driver-modminer.c
  20. 148 217
      driver-opencl.c
  21. 14 54
      driver-x6500.c
  22. 7 16
      driver-ztex.c
  23. 1 2
      findnonce.c
  24. 289 125
      fpgautils.c
  25. 25 1
      fpgautils.h
  26. 15 5
      ft232r.c
  27. 2 0
      icarus-common.h
  28. 37 0
      iospeeds.h
  29. 2 2
      jtag.c
  30. 35 11
      libztex.c
  31. 2 0
      libztex.h
  32. 6 3
      logging.h
  33. 373 154
      miner.c
  34. 32 23
      miner.h
  35. 9 1
      ocl.c
  36. 1 1
      openwrt/bfgminer/Makefile
  37. 15 15
      usbtest.py
  38. 242 126
      util.c
  39. 96 3
      util.h

+ 5 - 0
Makefile.am

@@ -156,6 +156,10 @@ endif # HAS_CPUMINE
 
 
 if NEED_FPGAUTILS
 if NEED_FPGAUTILS
 bfgminer_SOURCES += fpgautils.c fpgautils.h
 bfgminer_SOURCES += fpgautils.c fpgautils.h
+if HAVE_WINDOWS
+else
+bfgminer_SOURCES += iospeeds.h
+endif
 endif
 endif
 
 
 if NEED_DYNCLOCK
 if NEED_DYNCLOCK
@@ -183,6 +187,7 @@ endif
 if HAS_ICARUS
 if HAS_ICARUS
 bfgminer_SOURCES += driver-icarus.c icarus-common.h
 bfgminer_SOURCES += driver-icarus.c icarus-common.h
 bfgminer_SOURCES += driver-cairnsmore.c
 bfgminer_SOURCES += driver-cairnsmore.c
+bfgminer_SOURCES += driver-erupter.c
 endif
 endif
 
 
 if HAS_AVALON
 if HAS_AVALON

+ 128 - 0
NEWS

@@ -1,3 +1,131 @@
+BFGMiner Version 3.1.2 - July 8, 2013
+- When not compiling with optimizations, initialize unused nonce2 space to avoid
+warnings from memory checking tools
+- TUI Manage devices: Support PgUp/PgDn keys to skip over processors within the
+same device
+- Bugfix: bitforce: Prefer 2nd temperature if higher than 1st
+- When displaying device summary statlines, use the highest temperature reported
+by any processor
+- Stratum: Fix nonce2 sizes greater than 4 and (on big-endian) smaller than 4
+- bitforce: Manage TUI: Display both temperatures (if two), and enable changing
+fan speed
+- opencl: Add fan speed to Manage device TUI now that it's been removed from
+statline
+- DevAPI: Remove old statline APIs entirely, and add new override_statline_temp
+(used by modminer/x6500 for upload %)
+- README: Update statlines
+- TUI: Replace DevAPI statline_before with a predefined temperature column to
+free up statline space
+- Refactor and simplify bin2hex to speed up and avoid unnecessary heap use
+- stratum: Refactor work generation to do hex2bin conversions once, rather than
+every single header generated
+- Implement bytes_t for generic binary data storage (including smart realloc-
+based resize)
+- Bugfix: fpgautils: Only try to change baud rate when requested
+- x6500: Provide manuf/product/serial to cgpu interface
+- ztex: Provide manuf/product/serial to cgpu interface
+- erupter: Use baud 115200 by default
+- List valid baud rates once in iospeeds.h and standardize conversions
+- TUI: Display device manufacturer/product/serial in Manage device screen, when
+available
+- DevAPI: Store manufacturer/product/serial for each device
+- fpgautils: detectone_meta_info to provide metainformation (manufacturer,
+product, serial) on devices to detectone functions
+- Bugfix: fpgautils: Close product string file from sysfs (autodetect)
+- erupter: New icarus-based driver to handle autodetection of Block Erupter
+devices
+- Add --log-file option which redirects stderr to a file, but valid anywhere in
+the commandline or config file
+- Detect staged work underruns and increase queue to avoid them
+- Rewrite hex2bin to perform much faster (reduces minirig CPU usage by more than
+half!)
+- README: Add condensed list of dependencies
+- Enable "maintainer mode" by default
+- Bugfix: opencl: TUI manage: "Change settings" must not be compiled in with
+no-ADL builds
+- Bugfix: Detect whether the linker accepts -zorigin before attempting to use it
+- opencl: ADL: ADL_Adapter_ID_Get fails with newer drivers, so tolerate its
+failure best we can
+- opencl: Don't try to use BFI_INT patching with APP-SDK newer than 1084
+(Catalyst 13.1), since it doesn't work
+- fpgautils: Elaborate that bitstream open failures are probably due to missing
+bitstream package
+- fpgautils: s/firmware/bitstream/
+- Bugfix: Cleanup handling of complete device/driver failure
+- Deprecate -C (enable CPU) and -G (disable GPU) options, now that -S
+drv:[no]auto can be used for the same purposes
+- Bugfix: Since at least one of unix (or __APPLE__) or WIN32 is required by
+util.h, make sure unix is defined if WIN32 is not
+- Bugfix: Set ELF rpath for bundled libblkmaker to use $ORIGIN so it can be run
+from other directories
+- Bugfix: Cleanup needs to happen before printing the final quit message, or it
+gets lost in TUI mode
+- Bugfix: fpgautils: Initialize my_dev_t instances with null bytes, to ensure
+random unused data cannot influence hash keys
+- opencl: ManageTUI: Clear log cleanly for changing settings
+- Remove "GPU management" TUI entirely
+- opencl: Use new "Manage device" interface to do everything "GPU management"
+used to be used for
+- DevAPI: Add interface for drivers to define custom "Manage device" options
+- DevAPI: New function called to display additional processor information for
+"Manage devices"
+- TUI: Add enable/disable commands to device management
+- TUI: Implement beginnings of generic device management interface
+- Bugfix: avalon: Fix LIFE_INIT2 setting
+- Add LIFE_INIT2 status (safe to call functions, but not mining yet) for devices
+that want to report initialization status in their statline
+- Bugfix: modminer: Only program once for --force-dev-init
+- Bugfix: x6500: Only program once for --force-dev-init
+- fpgautils: Workaround and document Xcode clang bug
+- Bugfix: avalon: Correctly claim serial port
+- Bugfix: -S all: Mac OS X needs to probe /dev/cu.*, not just /dev/cu.usb*
+- cpu & opencl: Refuse to detect more than once
+- cpu & opencl: Respect scan-serial auto/noauto instructions
+- ft232r & libztex: Skip probe of claimed devices
+- fpgautils: Check for devices being claimed before calling detectone from autodetectors
+- x6500 & ztex: Claim USB devices
+- fpgautils: Implement bfg_claim_usb for claiming devices by USB bus number and
+address
+- fpgautils: Replace serial_claim with bfg_claim_serial using a more cleanly
+extensible interface and implementation
+- fpgautils: serial_claim: Include a bus enum in hash key
+- Add serial port claiming logic to avalon, bitforce, and modminer drivers
+- RPC: "devscan" command to probe for new devices
+- New (internal) scan_serial function to probe for new devices at runtime
+- Split out per-cgpu temperature configuration code to load_temp_config_cgpu
+- DevAPI: Modify add_cgpu to use temporary devices_new array, so detection can
+be done without touching live variables
+- Move more cgpu initialization to allocate_cgpu
+- Move devtype default assignment to allocate_cgpu
+- Move cgpu startup routine to new start_cgpu function
+- Move cgpu_info allocation to new allocate_cgpu function
+- Move *.drv_detect calls to a new drv_detect_all function
+- DevAPI: add_cgpu: There is no need to hold mutexes while creating devices
+- Bugfix: cpu: Update device "kernel name" with auto-selected algorithm
+- usbtest: Improve portability to at least 2.7 and 3.2
+- usbtest: Avoid messing up the display by escaping weird bytes via repr()
+- usbtest: Skip last 2 optional parameters, since we use the defaults and they
+are not in older versions of pyserial
+- Bugfix: bitforce: ZOX limits results to 16 results per call, so repeat ZOX
+until there are fewer
+- Bugfix: Initialization for bfgtls needs to be done in each thread
+- Bugfix: stratum: Be patient with stratum lines that come in slower than we can
+process them
+- Use bfg_strerror in locations previously just logging raw error numbers
+- Bugfix: stratum: Log WSAGetLastError() for error number on recv failures on
+Windows
+- Use bfg_strerror where it is already needed (for thread-safety)
+- New thread-safe bfg_strerror function to portably stringify error codes
+- Bugfix: bitforce_queue: Initialize buf2 so errors don't cause the work queue
+to flush
+- TUI: Display percentage invalid of found nonces with hw errors
+- Bugfix: modminer & x6500: Increment *->diff1 for all bad nonces
+- percentf2 that takes t as precalculated total
+- Keep track of bad nonces independently from generic hw errors
+- inc_hw_errors: Resolve cgpu outside of mutex
+- Use inc_hw_errors function at every site which increases hw_errors
+
+
 BFGMiner Version 3.1.1 - June 22, 2013
 BFGMiner Version 3.1.1 - June 22, 2013
 - stratum: Deliver exact socket-error within the debug error message
 - stratum: Deliver exact socket-error within the debug error message
 - Don't install docs for (compile-time) disabled functionality
 - Don't install docs for (compile-time) disabled functionality

+ 36 - 37
README

@@ -78,6 +78,10 @@ all pools that don't specify their own proxy setting like above
 ---
 ---
 BUILDING BFGMINER
 BUILDING BFGMINER
 
 
+Everything you probably want, condensed:
+	build-essential autoconf automake libtool pkg-config libcurl4-gnutls-dev
+	libjansson-dev uthash-dev libncursesw5-dev libudev-dev libusb-1.0-0-dev
+
 Dependencies:
 Dependencies:
 	autoconf             http://www.gnu.org/software/autoconf/
 	autoconf             http://www.gnu.org/software/autoconf/
 	automake             http://www.gnu.org/software/automake/
 	automake             http://www.gnu.org/software/automake/
@@ -178,6 +182,7 @@ Options for both config file and command line:
 --kernel-path|-K <arg> Specify a path to where bitstream and kernel files are (default: "/usr/local/bin")
 --kernel-path|-K <arg> Specify a path to where bitstream and kernel files are (default: "/usr/local/bin")
 --load-balance      Change multipool strategy from failover to efficiency based balance
 --load-balance      Change multipool strategy from failover to efficiency based balance
 --log|-l <arg>      Interval in seconds between log output (default: 5)
 --log|-l <arg>      Interval in seconds between log output (default: 5)
+--log-file|-L <arg> Append log file for output messages
 --log-microseconds  Include microseconds in log output
 --log-microseconds  Include microseconds in log output
 --monitor|-m <arg>  Use custom pipe cmd for output messages
 --monitor|-m <arg>  Use custom pipe cmd for output messages
 --net-delay         Impose small delays in networking to not overload slow routers
 --net-delay         Impose small delays in networking to not overload slow routers
@@ -230,7 +235,6 @@ GPU only options:
 
 
 --auto-fan          Automatically adjust all GPU fan speeds to maintain a target temperature
 --auto-fan          Automatically adjust all GPU fan speeds to maintain a target temperature
 --auto-gpu          Automatically adjust all GPU engine clock speeds to maintain a target temperature
 --auto-gpu          Automatically adjust all GPU engine clock speeds to maintain a target temperature
---disable-gpu|-G    Disable GPU mining even if suitable devices exist
 --gpu-threads|-g <arg> Number of threads per GPU (1 - 10) (default: 2)
 --gpu-threads|-g <arg> Number of threads per GPU (1 - 10) (default: 2)
 --gpu-dyninterval <arg> Set the refresh interval in ms for GPUs using dynamic intensity (default: 7)
 --gpu-dyninterval <arg> Set the refresh interval in ms for GPUs using dynamic intensity (default: 7)
 --gpu-engine <arg>  GPU engine (over)clock range in MHz - one value, range and/or comma separated list (e.g. 850-900,900,750-850)
 --gpu-engine <arg>  GPU engine (over)clock range in MHz - one value, range and/or comma separated list (e.g. 850-900,900,750-850)
@@ -250,6 +254,8 @@ GPU only options:
 --vectors|-v <arg>  Override detected optimal vector (1, 2 or 4) - one value or comma separated list
 --vectors|-v <arg>  Override detected optimal vector (1, 2 or 4) - one value or comma separated list
 --worksize|-w <arg> Override detected optimal worksize - one value or comma separated list
 --worksize|-w <arg> Override detected optimal worksize - one value or comma separated list
 
 
+GPU mining can be disabled by specifying the -S opencl:noauto option.
+
 See README.GPU for more information regarding GPU mining.
 See README.GPU for more information regarding GPU mining.
 
 
 scrypt only options:
 scrypt only options:
@@ -313,7 +319,6 @@ CPU only options (not included in binaries):
         sse4_64         SSE4.1 64 bit implementation for x86_64 machines
         sse4_64         SSE4.1 64 bit implementation for x86_64 machines
         altivec_4way    Altivec implementation for PowerPC G4 and G5 machines
         altivec_4way    Altivec implementation for PowerPC G4 and G5 machines
 --cpu-threads|-t <arg> Number of miner CPU threads (default: 4)
 --cpu-threads|-t <arg> Number of miner CPU threads (default: 4)
---enable-cpu|-C     Enable CPU mining with other mining (default: no CPU mining if other devices exist)
 
 
 
 
 ---
 ---
@@ -322,7 +327,18 @@ WHILE RUNNING:
 
 
 The following options are available while running with a single keypress:
 The following options are available while running with a single keypress:
 
 
-[P]ool management [G]PU management [S]ettings [D]isplay options [Q]uit
+[M]anage devices [P]ool management [S]ettings [D]isplay options [Q]uit
+
+M gives you something like:
+
+Select processor to manage using up/down arrow keys
+ BFL 0a: 78.0C |  3.64/ 3.70/ 2.91Gh/s | A:46 R:0+0(none) HW:  2/none
+  BitFORCE SHA256 SC from Butterfly Labs
+Serial: FTWN6T67
+
+[D]isable
+Or press Enter when done
+
 
 
 P gives you:
 P gives you:
 
 
@@ -359,24 +375,6 @@ co[M]pact: off
 Q quits the application.
 Q quits the application.
 
 
 
 
-G gives you something like:
-
-GPU 0: [124.2 / 191.3 Mh/s] [A:77  R:33+0( 42%)  HW:0]
-Temp: 67.0 C
-Fan Speed: 35% (2500 RPM)
-Engine Clock: 960 MHz
-Memory Clock: 480 MHz
-Vddc: 1.200 V
-Activity: 93%
-Powertune: 0%
-Last initialised: [2011-09-06 12:03:56]
-Thread 0: 62.4 Mh/s Enabled ALIVE
-Thread 1: 60.2 Mh/s Enabled ALIVE
-
-[E]nable [D]isable [R]estart GPU [C]hange settings
-Or press any other key to continue
-
-
 The running log shows output like this:
 The running log shows output like this:
 
 
  [2013-02-13 00:26:30] Accepted 1758e8df BFL 0  pool 0 Diff 10/1
  [2013-02-13 00:26:30] Accepted 1758e8df BFL 0  pool 0 Diff 10/1
@@ -395,7 +393,7 @@ dedicated to this program,
 	https://bitcointalk.org/?topic=168174
 	https://bitcointalk.org/?topic=168174
 
 
 The output line shows the following:
 The output line shows the following:
- 5s:1713.6 avg:1707.8 u:1710.2 Mh/s | A:729 R:8+0(.01%) HW:0
+ 5s:1713.6 avg:1707.8 u:1710.2 Mh/s | A:729 R:8+0(.01%) HW:0/.81%
 
 
 Each column is as follows:
 Each column is as follows:
 5s:  A 5 second exponentially decaying average hash rate
 5s:  A 5 second exponentially decaying average hash rate
@@ -404,20 +402,7 @@ u:   An all time average hash rate based on actual accepted shares
 A:   The number of Accepted shares
 A:   The number of Accepted shares
 R:   The number of Rejected shares, stale shares discarded (never submitted),
 R:   The number of Rejected shares, stale shares discarded (never submitted),
      and the percentage these are of total found.
      and the percentage these are of total found.
-HW:  The number of HardWare errors
-
- GPU 1: 73.5C 2551RPM | 427.3/443.0/442.1Mh/s | A:8 R:0+0(none) HW:0 U:4.39/m
-
-Each column is as follows:
-Temperature (if supported)
-Fanspeed (if supported)
-A 5 second exponentially decaying average hash rate
-An all time average hash rate
-An all time average hash rate based on actual accepted shares
-The number of accepted shares
-The number of rejected shares (and percentage of total submitted)
-The number of hardware erorrs
-The utility defines as the number of shares / minute
+HW:  The number of HardWare errors, and percentage invalid of nonces returned
 
 
 The BFGMiner status line shows:
 The BFGMiner status line shows:
  ST: 1  GF: 1  NB: 1  AS: 0  RF: 1  E: 2.42  U:22.53/m  BS:2.71k
  ST: 1  GF: 1  NB: 1  AS: 0  RF: 1  E: 2.42  U:22.53/m  BS:2.71k
@@ -439,6 +424,18 @@ This shows a short stretch of the current block, the next block's height and
 difficulty (including the network hashrate that difficulty represents), and when
 difficulty (including the network hashrate that difficulty represents), and when
 the search for the new block started.
 the search for the new block started.
 
 
+Each device shows:
+ BFL 2: 74.0C | 51.97/58.90/57.17Gh/s | A:847 R:15+0(.54%) HW:496/.91%
+
+Column are as follows:
+Temperature (if supported)
+5 second exponentially decaying average hash rate
+An all time average hash rate
+An all time average hash rate based on actual accepted shares
+The number of accepted shares
+The number of rejected plus discarded shares (and percentage of total submitted)
+The number of hardware errors and percentage of nonces invalid
+
 
 
 ---
 ---
 MULTIPOOL
 MULTIPOOL
@@ -641,7 +638,9 @@ Q: What happened to CPU mining?
 A: Being increasingly irrelevant for most users, and a maintenance issue, it is
 A: Being increasingly irrelevant for most users, and a maintenance issue, it is
 no longer under active development and will not be supported unless someone
 no longer under active development and will not be supported unless someone
 steps up to help maintain it. No binary builds supporting CPU mining will be
 steps up to help maintain it. No binary builds supporting CPU mining will be
-released but CPU mining can be built into BFGMiner when it is compiled.
+released for Windows but CPU mining can be built into BFGMiner when it is
+compiled. For builds which do support CPU mining, it is still disabled by
+default, and must be enabled using the -S cpu:auto option.
 
 
 Q: GUI version?
 Q: GUI version?
 A: No. The RPC interface makes it possible for someone else to write one
 A: No. The RPC interface makes it possible for someone else to write one

+ 11 - 0
README.RPC

@@ -145,6 +145,10 @@ The list of requests - a (*) means it requires privileged access - and replies a
                               Will not report PGAs if PGA mining is disabled
                               Will not report PGAs if PGA mining is disabled
                               Will not report CPUs if CPU mining is disabled
                               Will not report CPUs if CPU mining is disabled
 
 
+ devscan|info  DEVS           Probes for a device specified by info, which is
+                              the same format as the --scan-serial command line
+                              option
+
  devdetail     DEVS           Each available device with their fixed details
  devdetail     DEVS           Each available device with their fixed details
                               e.g. GPU=0,Driver=opencl,Kernel=diablo,Model=...|
                               e.g. GPU=0,Driver=opencl,Kernel=diablo,Model=...|
 
 
@@ -410,6 +414,13 @@ api-example.py - a Python script to access the API
 Feature Changelog for external applications using the API:
 Feature Changelog for external applications using the API:
 
 
 
 
+API V1.25.1 (BFGMiner v3.1.2)
+
+Added API commands:
+ 'devscan'
+
+----------
+
 API V1.25 (BFGMiner v3.0.1)
 API V1.25 (BFGMiner v3.0.1)
 
 
 Modified API commands:
 Modified API commands:

+ 7 - 9
adl.c

@@ -251,12 +251,16 @@ void init_adl(int nDevs)
 			applog(LOG_INFO, "Failed to ADL_Adapter_ID_Get. Error %d", result);
 			applog(LOG_INFO, "Failed to ADL_Adapter_ID_Get. Error %d", result);
 			if (result == -10)
 			if (result == -10)
 				applog(LOG_INFO, "This error says the device is not enabled");
 				applog(LOG_INFO, "This error says the device is not enabled");
-			continue;
 		}
 		}
-
+		else
 		/* Each adapter may have multiple entries */
 		/* Each adapter may have multiple entries */
 		if (lpAdapterID == last_adapter)
 		if (lpAdapterID == last_adapter)
 			continue;
 			continue;
+		else
+		if (!lpAdapterID)
+			applog(LOG_INFO, "Adapter returns ID 0 meaning not AMD. Card order might be confused");
+		else
+			last_adapter = lpAdapterID;
 
 
 		applog(LOG_DEBUG, "GPU %d "
 		applog(LOG_DEBUG, "GPU %d "
 		       "iAdapterIndex %d "
 		       "iAdapterIndex %d "
@@ -289,12 +293,6 @@ void init_adl(int nDevs)
 			applog(LOG_ERR, "Use the gpu map feature to reliably map OpenCL to ADL");
 			applog(LOG_ERR, "Use the gpu map feature to reliably map OpenCL to ADL");
 			devs_match = false;
 			devs_match = false;
 		}
 		}
-		last_adapter = lpAdapterID;
-
-		if (!lpAdapterID) {
-			applog(LOG_INFO, "Adapter returns ID 0 meaning not AMD. Card order might be confused");
-			continue;
-		}
 	}
 	}
 
 
 	if (devices < nDevs) {
 	if (devices < nDevs) {
@@ -367,7 +365,7 @@ void init_adl(int nDevs)
 		result = ADL_Adapter_ID_Get(iAdapterIndex, &lpAdapterID);
 		result = ADL_Adapter_ID_Get(iAdapterIndex, &lpAdapterID);
 		if (result != ADL_OK) {
 		if (result != ADL_OK) {
 			applog(LOG_INFO, "Failed to ADL_Adapter_ID_Get. Error %d", result);
 			applog(LOG_INFO, "Failed to ADL_Adapter_ID_Get. Error %d", result);
-			continue;
+			lpAdapterID = -1;
 		}
 		}
 
 
 		if (gpus[gpu].deven == DEV_DISABLED) {
 		if (gpus[gpu].deven == DEV_DISABLED) {

+ 33 - 76
api.c

@@ -48,81 +48,6 @@
 // However lots of PGA's may mean more
 // However lots of PGA's may mean more
 #define QUEUE	100
 #define QUEUE	100
 
 
-#if defined WIN32
-static char WSAbuf[1024];
-
-struct WSAERRORS {
-	int id;
-	char *code;
-} WSAErrors[] = {
-	{ 0,			"No error" },
-	{ WSAEINTR,		"Interrupted system call" },
-	{ WSAEBADF,		"Bad file number" },
-	{ WSAEACCES,		"Permission denied" },
-	{ WSAEFAULT,		"Bad address" },
-	{ WSAEINVAL,		"Invalid argument" },
-	{ WSAEMFILE,		"Too many open sockets" },
-	{ WSAEWOULDBLOCK,	"Operation would block" },
-	{ WSAEINPROGRESS,	"Operation now in progress" },
-	{ WSAEALREADY,		"Operation already in progress" },
-	{ WSAENOTSOCK,		"Socket operation on non-socket" },
-	{ WSAEDESTADDRREQ,	"Destination address required" },
-	{ WSAEMSGSIZE,		"Message too long" },
-	{ WSAEPROTOTYPE,	"Protocol wrong type for socket" },
-	{ WSAENOPROTOOPT,	"Bad protocol option" },
-	{ WSAEPROTONOSUPPORT,	"Protocol not supported" },
-	{ WSAESOCKTNOSUPPORT,	"Socket type not supported" },
-	{ WSAEOPNOTSUPP,	"Operation not supported on socket" },
-	{ WSAEPFNOSUPPORT,	"Protocol family not supported" },
-	{ WSAEAFNOSUPPORT,	"Address family not supported" },
-	{ WSAEADDRINUSE,	"Address already in use" },
-	{ WSAEADDRNOTAVAIL,	"Can't assign requested address" },
-	{ WSAENETDOWN,		"Network is down" },
-	{ WSAENETUNREACH,	"Network is unreachable" },
-	{ WSAENETRESET,		"Net connection reset" },
-	{ WSAECONNABORTED,	"Software caused connection abort" },
-	{ WSAECONNRESET,	"Connection reset by peer" },
-	{ WSAENOBUFS,		"No buffer space available" },
-	{ WSAEISCONN,		"Socket is already connected" },
-	{ WSAENOTCONN,		"Socket is not connected" },
-	{ WSAESHUTDOWN,		"Can't send after socket shutdown" },
-	{ WSAETOOMANYREFS,	"Too many references, can't splice" },
-	{ WSAETIMEDOUT,		"Connection timed out" },
-	{ WSAECONNREFUSED,	"Connection refused" },
-	{ WSAELOOP,		"Too many levels of symbolic links" },
-	{ WSAENAMETOOLONG,	"File name too long" },
-	{ WSAEHOSTDOWN,		"Host is down" },
-	{ WSAEHOSTUNREACH,	"No route to host" },
-	{ WSAENOTEMPTY,		"Directory not empty" },
-	{ WSAEPROCLIM,		"Too many processes" },
-	{ WSAEUSERS,		"Too many users" },
-	{ WSAEDQUOT,		"Disc quota exceeded" },
-	{ WSAESTALE,		"Stale NFS file handle" },
-	{ WSAEREMOTE,		"Too many levels of remote in path" },
-	{ WSASYSNOTREADY,	"Network system is unavailable" },
-	{ WSAVERNOTSUPPORTED,	"Winsock version out of range" },
-	{ WSANOTINITIALISED,	"WSAStartup not yet called" },
-	{ WSAEDISCON,		"Graceful shutdown in progress" },
-	{ WSAHOST_NOT_FOUND,	"Host not found" },
-	{ WSANO_DATA,		"No host data of that type was found" },
-	{ -1,			"Unknown error code" }
-};
-
-char *WSAErrorMsg(void) {
-	int i;
-	int id = WSAGetLastError();
-
-	/* Assume none of them are actually -1 */
-	for (i = 0; WSAErrors[i].id != -1; i++)
-		if (WSAErrors[i].id == id)
-			break;
-
-	sprintf(WSAbuf, "Socket Error: (%d) %s", id, WSAErrors[i].code);
-
-	return &(WSAbuf[0]);
-}
-#endif
-
 static const char *UNAVAILABLE = " - API will not be available";
 static const char *UNAVAILABLE = " - API will not be available";
 
 
 static const char *BLANK = "";
 static const char *BLANK = "";
@@ -398,6 +323,8 @@ static const char *JSON_PARAMETER = "parameter";
 #define MSG_ZERSUM 96
 #define MSG_ZERSUM 96
 #define MSG_ZERNOSUM 97
 #define MSG_ZERNOSUM 97
 
 
+#define MSG_DEVSCAN 0x100
+
 enum code_severity {
 enum code_severity {
 	SEVERITY_ERR,
 	SEVERITY_ERR,
 	SEVERITY_WARN,
 	SEVERITY_WARN,
@@ -407,6 +334,7 @@ enum code_severity {
 };
 };
 
 
 enum code_parameters {
 enum code_parameters {
+	PARAM_COUNT,
 	PARAM_GPU,
 	PARAM_GPU,
 	PARAM_PGA,
 	PARAM_PGA,
 	PARAM_CPU,
 	PARAM_CPU,
@@ -572,6 +500,7 @@ struct CODES {
  { SEVERITY_ERR,   MSG_ZERINV,	PARAM_STR,	"Invalid zero parameter '%s'" },
  { SEVERITY_ERR,   MSG_ZERINV,	PARAM_STR,	"Invalid zero parameter '%s'" },
  { SEVERITY_SUCC,  MSG_ZERSUM,	PARAM_STR,	"Zeroed %s stats with summary" },
  { SEVERITY_SUCC,  MSG_ZERSUM,	PARAM_STR,	"Zeroed %s stats with summary" },
  { SEVERITY_SUCC,  MSG_ZERNOSUM, PARAM_STR,	"Zeroed %s stats without summary" },
  { SEVERITY_SUCC,  MSG_ZERNOSUM, PARAM_STR,	"Zeroed %s stats without summary" },
+ { SEVERITY_SUCC,  MSG_DEVSCAN, PARAM_COUNT,	"Added %d new device(s)" },
  { SEVERITY_FAIL, 0, 0, NULL }
  { SEVERITY_FAIL, 0, 0, NULL }
 };
 };
 
 
@@ -1262,6 +1191,7 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p
 			severity[1] = '\0';
 			severity[1] = '\0';
 
 
 			switch(codes[i].params) {
 			switch(codes[i].params) {
+				case PARAM_COUNT:
 				case PARAM_GPU:
 				case PARAM_GPU:
 				case PARAM_PGA:
 				case PARAM_PGA:
 				case PARAM_CPU:
 				case PARAM_CPU:
@@ -1464,6 +1394,7 @@ static const char *status2str(enum alive status)
 		case LIFE_NOSTART:
 		case LIFE_NOSTART:
 			return NOSTART;
 			return NOSTART;
 		case LIFE_INIT:
 		case LIFE_INIT:
+		case LIFE_INIT2:
 			return INIT;
 			return INIT;
 		case LIFE_WAIT:
 		case LIFE_WAIT:
 			return WAIT;
 			return WAIT;
@@ -1661,6 +1592,31 @@ static void gpudev(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *p
 }
 }
 #endif
 #endif
 
 
+static void devscan(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
+{
+	int n;
+	bool io_open = false;
+	
+	applog(LOG_DEBUG, "RPC: request to scan %s for devices",
+	       param);
+	
+	if (param && !param[0])
+		param = NULL;
+	
+	n = scan_serial(param);
+	
+	message(io_data, MSG_DEVSCAN, n, NULL, isjson);
+	
+	io_open = io_add(io_data, isjson ? COMSTR JSON_DEVS : _DEVS COMSTR);
+
+	n = total_devices - n;
+	for (int i = n; i < total_devices; ++i)
+		devdetail_an(io_data, get_devices(i), isjson, i > n);
+	
+	if (isjson && io_open)
+		io_close(io_data);
+}
+
 #ifdef HAVE_AN_FPGA
 #ifdef HAVE_AN_FPGA
 static void pgadev(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
 static void pgadev(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
 {
 {
@@ -3150,6 +3106,7 @@ struct CMDS {
 } cmds[] = {
 } cmds[] = {
 	{ "version",		apiversion,	false },
 	{ "version",		apiversion,	false },
 	{ "config",		minerconfig,	false },
 	{ "config",		minerconfig,	false },
+	{ "devscan",		devscan,	false },
 	{ "devs",		devstatus,	false },
 	{ "devs",		devstatus,	false },
 	{ "devdetail",	devdetail,	false },
 	{ "devdetail",	devdetail,	false },
 	{ "pools",		poolstatus,	false },
 	{ "pools",		poolstatus,	false },
@@ -3610,7 +3567,7 @@ void api(int api_thr_id)
 	SOCKETTYPE c;
 	SOCKETTYPE c;
 	int n, bound;
 	int n, bound;
 	char *connectaddr;
 	char *connectaddr;
-	char *binderror;
+	const char *binderror;
 	time_t bindstart;
 	time_t bindstart;
 	short int port = opt_api_port;
 	short int port = opt_api_port;
 	struct sockaddr_in serv;
 	struct sockaddr_in serv;

+ 3 - 6
compat.h

@@ -18,16 +18,13 @@
 
 
 #include <stdbool.h>
 #include <stdbool.h>
 
 
-// NOTE: Nested preprocessor checks since the latter isn't defined at all without the former
-#ifdef HAVE_LIBUSB
-#	if ! HAVE_DECL_LIBUSB_ERROR_NAME
-		static char my_libusb_error_name_buf[0x10];
-#		define libusb_error_name(x) (sprintf(my_libusb_error_name_buf, "%d", x), my_libusb_error_name_buf)
-#	endif
+#if !(defined(WIN32) || defined(unix))
+#define unix
 #endif
 #endif
 
 
 #ifdef WIN32
 #ifdef WIN32
 #include <errno.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <time.h>
 #include <time.h>
 #include <pthread.h>
 #include <pthread.h>
 #include <sys/time.h>
 #include <sys/time.h>

+ 15 - 3
configure.ac

@@ -14,7 +14,7 @@ dnl * any later version.  See COPYING for more details.
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [3])
 m4_define([v_maj], [3])
 m4_define([v_min], [1])
 m4_define([v_min], [1])
-m4_define([v_mic], [1])
+m4_define([v_mic], [2])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([lt_rev], m4_eval(v_maj + v_min))
 m4_define([lt_rev], m4_eval(v_maj + v_min))
@@ -55,7 +55,7 @@ AC_CANONICAL_BUILD
 AC_CANONICAL_HOST
 AC_CANONICAL_HOST
 
 
 dnl Make sure anyone changing configure.ac/Makefile.am has a clue
 dnl Make sure anyone changing configure.ac/Makefile.am has a clue
-AM_MAINTAINER_MODE
+AM_MAINTAINER_MODE([enable])
 
 
 dnl Checks for programs
 dnl Checks for programs
 AC_PROG_CC_C99
 AC_PROG_CC_C99
@@ -524,8 +524,20 @@ if test "x$with_system_libblkmaker" = "xyes"; then
 		AC_MSG_ERROR([Could not find system libblkmaker])
 		AC_MSG_ERROR([Could not find system libblkmaker])
 	])
 	])
 else
 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_CFLAGS='-Ilibblkmaker'
-	libblkmaker_LDFLAGS='-Llibblkmaker/.libs -Wl,-rpath,libblkmaker/.libs'
+	libblkmaker_LDFLAGS='-Llibblkmaker/.libs -Wl,-rpath,\$$ORIGIN/libblkmaker/.libs'"$origin_LDFLAGS"
 	libblkmaker_LIBS='-lblkmaker_jansson-0.1 -lblkmaker-0.1'
 	libblkmaker_LIBS='-lblkmaker_jansson-0.1 -lblkmaker-0.1'
 	AC_CONFIG_SUBDIRS([libblkmaker])
 	AC_CONFIG_SUBDIRS([libblkmaker])
 fi
 fi

+ 13 - 0
debian/changelog

@@ -1,3 +1,16 @@
+bfgminer (3.1.2-0precise1) precise; urgency=low
+
+  * TUI: The "GPU management" interface has been replaced with a new generic "Manage devices" interface, allowing easy enable and disable of non-GPU devices.
+  * Major CPU usage reduction for faster mining rigs (on my minirig host system, from 35% down to 13%!).
+  * erupter: New icarus-based driver to handle autodetection of (branded) Block Erupter devices.
+  * opencl: Add support for AMD Catalyst 13.2+ drivers.
+  * The device statlines have been condensed by reducing the device-specific space down to a single temperature reading. More detailed information (such as GPU fan speeds) is still available via RPC and the new "Manage devices" interface.
+  * RPC: New "devscan" command to probe for new devices on demand. The effect is the same as starting BFGMiner with -S noauto -S <parameter>.
+  * TUI: Display percentage invalid of found nonces with hw errors.
+  * cpu & opencl: These legacy drivers now respect the --scan-serial auto/noauto directives, and the old -C (enable CPU) and -G (disable GPU) options are now deprecated.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Mon, 08 Jul 2013 18:46:53 -0000
+
 bfgminer (3.1.1-0precise1) precise; urgency=low
 bfgminer (3.1.1-0precise1) precise; urgency=low
 
 
   * bitforce: Support for Little Single boards, and Jalapenos with 1.2 firmware.
   * bitforce: Support for Little Single boards, and Jalapenos with 1.2 firmware.

+ 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.1.1
+Standards-Version: 3.1.2
 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

+ 19 - 11
deviceapi.c

@@ -26,6 +26,7 @@
 
 
 #include "compat.h"
 #include "compat.h"
 #include "deviceapi.h"
 #include "deviceapi.h"
+#include "fpgautils.h"
 #include "logging.h"
 #include "logging.h"
 #include "miner.h"
 #include "miner.h"
 #include "util.h"
 #include "util.h"
@@ -580,12 +581,21 @@ void *miner_thread(void *userdata)
 		minerloop_scanhash(mythr);
 		minerloop_scanhash(mythr);
 	__thr_being_msg(LOG_NOTICE, mythr, "shutting down");
 	__thr_being_msg(LOG_NOTICE, mythr, "shutting down");
 
 
-out:
-	cgpu->deven = DEV_DISABLED;
+out: ;
+	struct cgpu_info *proc = cgpu;
+	do
+	{
+		proc->deven = DEV_DISABLED;
+		proc->status = LIFE_DEAD2;
+	}
+	while ( (proc = proc->next_proc) && !proc->threads);
+	mythr->getwork = 0;
+	mythr->has_pth = false;
+	nmsleep(1000);
+	
 	if (drv->thread_shutdown)
 	if (drv->thread_shutdown)
 		drv->thread_shutdown(mythr);
 		drv->thread_shutdown(mythr);
 
 
-	thread_reportin(mythr);
 	notifier_destroy(mythr->notifier);
 	notifier_destroy(mythr->notifier);
 
 
 	return NULL;
 	return NULL;
@@ -608,10 +618,12 @@ bool add_cgpu(struct cgpu_info *cgpu)
 	strcpy(cgpu->proc_repr, cgpu->dev_repr);
 	strcpy(cgpu->proc_repr, cgpu->dev_repr);
 	sprintf(cgpu->proc_repr_ns, "%s%u", cgpu->drv->name, cgpu->device_id);
 	sprintf(cgpu->proc_repr_ns, "%s%u", cgpu->drv->name, cgpu->device_id);
 	
 	
-	wr_lock(&devices_lock);
+	maybe_strdup_if_null(&cgpu->dev_manufacturer, detectone_meta_info.manufacturer);
+	maybe_strdup_if_null(&cgpu->dev_product,      detectone_meta_info.product);
+	maybe_strdup_if_null(&cgpu->dev_serial,       detectone_meta_info.serial);
 	
 	
-	devices = realloc(devices, sizeof(struct cgpu_info *) * (total_devices + lpcount + 1));
-	devices[total_devices++] = cgpu;
+	devices_new = realloc(devices_new, sizeof(struct cgpu_info *) * (total_devices_new + lpcount + 1));
+	devices_new[total_devices_new++] = cgpu;
 	
 	
 	if (lpcount > 1)
 	if (lpcount > 1)
 	{
 	{
@@ -645,7 +657,7 @@ bool add_cgpu(struct cgpu_info *cgpu)
 				slave->proc_repr_ns[ns] += i;
 				slave->proc_repr_ns[ns] += i;
 			}
 			}
 			slave->threads = tpp;
 			slave->threads = tpp;
-			devices[total_devices++] = slave;
+			devices_new[total_devices_new++] = slave;
 			*nlp_p = slave;
 			*nlp_p = slave;
 			nlp_p = &slave->next_proc;
 			nlp_p = &slave->next_proc;
 		}
 		}
@@ -653,12 +665,8 @@ bool add_cgpu(struct cgpu_info *cgpu)
 		cgpu->proc_id = 0;
 		cgpu->proc_id = 0;
 		cgpu->threads -= (tpp * (lpcount - 1));
 		cgpu->threads -= (tpp * (lpcount - 1));
 	}
 	}
-	
-	wr_unlock(&devices_lock);
 
 
-	mutex_lock(&stats_lock);
 	cgpu->last_device_valid_work = time(NULL);
 	cgpu->last_device_valid_work = time(NULL);
-	mutex_unlock(&stats_lock);
 	
 	
 	return true;
 	return true;
 }
 }

+ 8 - 33
driver-avalon.c

@@ -233,7 +233,7 @@ static inline int avalon_gets(int fd, uint8_t *buf, int read_count,
 		ret = read(fd, buf, 1);
 		ret = read(fd, buf, 1);
 		if (ret < 0)
 		if (ret < 0)
 		{
 		{
-			applog(LOG_ERR, "Avalon: Error %d on read in avalon_gets", errno);
+			applog(LOG_ERR, "Avalon: Error on read in avalon_gets: %s", bfg_strerror(errno, BST_ERRNO));
 			return AVA_GETS_ERROR;
 			return AVA_GETS_ERROR;
 		}
 		}
 
 
@@ -458,23 +458,8 @@ static void get_options(int this_option_offset, int *baud, int *miner_count,
 		*(colon++) = '\0';
 		*(colon++) = '\0';
 
 
 	tmp = atoi(buf);
 	tmp = atoi(buf);
-	switch (tmp) {
-	case 115200:
-		*baud = 115200;
-		break;
-	case 57600:
-		*baud = 57600;
-		break;
-	case 38400:
-		*baud = 38400;
-		break;
-	case 19200:
-		*baud = 19200;
-		break;
-	default:
-		quit(1, "Invalid avalon-options for baud (%s) "
-			"must be 115200, 57600, 38400 or 19200", buf);
-	}
+	if (!valid_baud(*baud = tmp))
+		quit(1, "Invalid avalon-options for baud (%s)", buf);
 
 
 	if (colon && *colon) {
 	if (colon && *colon) {
 		colon2 = strchr(colon, ':');
 		colon2 = strchr(colon, ':');
@@ -571,6 +556,9 @@ static bool avalon_detect_one(const char *devpath)
 	int baud, miner_count, asic_count, timeout, frequency = 0;
 	int baud, miner_count, asic_count, timeout, frequency = 0;
 	struct cgpu_info *avalon;
 	struct cgpu_info *avalon;
 
 
+	if (serial_claim(devpath, &avalon_drv))
+		return false;
+	
 	int this_option_offset = ++option_offset;
 	int this_option_offset = ++option_offset;
 	get_options(this_option_offset, &baud, &miner_count, &asic_count,
 	get_options(this_option_offset, &baud, &miner_count, &asic_count,
 		    &timeout, &frequency);
 		    &timeout, &frequency);
@@ -688,6 +676,7 @@ static bool avalon_prepare(struct thr_info *thr)
 
 
 	cgtime(&now);
 	cgtime(&now);
 	get_datestamp(avalon->init, &now);
 	get_datestamp(avalon->init, &now);
+	avalon->status = LIFE_INIT2;
 	return true;
 	return true;
 }
 }
 
 
@@ -779,20 +768,6 @@ static inline void adjust_fan(struct avalon_info *info)
 	}
 	}
 }
 }
 
 
-static void get_avalon_statline_before(char *buf, struct cgpu_info *avalon)
-{
-	struct avalon_info *info = avalon->device_data;
-	int lowfan = 10000;
-
-	/* Find the lowest fan speed of the ASIC cooling fans. */
-	if (info->fan1 >= 0 && info->fan1 < lowfan)
-		lowfan = info->fan1;
-	if (info->fan2 >= 0 && info->fan2 < lowfan)
-		lowfan = info->fan2;
-
-	tailsprintf(buf, "%2d/%3dC %04dR | ", info->temp0, info->temp2, lowfan);
-}
-
 /* We use a replacement algorithm to only remove references to work done from
 /* We use a replacement algorithm to only remove references to work done from
  * the buffer when we need the extra space for new work. */
  * the buffer when we need the extra space for new work. */
 static bool avalon_fill(struct cgpu_info *avalon)
 static bool avalon_fill(struct cgpu_info *avalon)
@@ -976,6 +951,7 @@ static int64_t avalon_scanhash(struct thr_info *thr)
 
 
 	if (hash_count) {
 	if (hash_count) {
 		record_temp_fan(info, &ar, &(avalon->temp));
 		record_temp_fan(info, &ar, &(avalon->temp));
+		avalon->temp = info->temp_max;
 		applog(LOG_INFO,
 		applog(LOG_INFO,
 		       "Avalon: Fan1: %d/m, Fan2: %d/m, Fan3: %d/m\t"
 		       "Avalon: Fan1: %d/m, Fan2: %d/m, Fan3: %d/m\t"
 		       "Temp1: %dC, Temp2: %dC, Temp3: %dC, TempMAX: %dC",
 		       "Temp1: %dC, Temp2: %dC, Temp3: %dC, TempMAX: %dC",
@@ -1043,7 +1019,6 @@ struct device_drv avalon_drv = {
 	.queue_full = avalon_fill,
 	.queue_full = avalon_fill,
 	.scanwork = avalon_scanhash,
 	.scanwork = avalon_scanhash,
 	.get_api_stats = avalon_api_stats,
 	.get_api_stats = avalon_api_stats,
-	.get_statline_before = get_avalon_statline_before,
 	.reinit_device = avalon_init,
 	.reinit_device = avalon_init,
 	.thread_shutdown = avalon_shutdown,
 	.thread_shutdown = avalon_shutdown,
 };
 };

+ 4 - 27
driver-bf1.c

@@ -53,7 +53,7 @@ int bf1_rehash(unsigned char *midstate, unsigned m7, unsigned ntime, unsigned nb
 {
 {
 	uint8_t   in[16];
 	uint8_t   in[16];
 	uint32_t *in32 = (uint32_t *)in;
 	uint32_t *in32 = (uint32_t *)in;
-	char     *hex;
+	char      hex[65];
 	uint32_t *mid32 = (uint32_t *)midstate;
 	uint32_t *mid32 = (uint32_t *)midstate;
 	uint32_t  out32[8];
 	uint32_t  out32[8];
 	uint8_t  *out = (uint8_t *) out32;
 	uint8_t  *out = (uint8_t *) out32;
@@ -76,7 +76,7 @@ int bf1_rehash(unsigned char *midstate, unsigned m7, unsigned ntime, unsigned nb
 
 
 	if (out32[7] == 0)
 	if (out32[7] == 0)
 	{
 	{
-		hex = bin2hex(out, 32);
+		bin2hex(hex, out, 32);
 		applog(LOG_INFO, "! MS0: %08x, m7: %08x, ntime: %08x, nbits: %08x, nnonce: %08x\n\t\t\t out: %s\n", mid32[0], m7, ntime, nbits, nnonce, hex);
 		applog(LOG_INFO, "! MS0: %08x, m7: %08x, ntime: %08x, nbits: %08x, nnonce: %08x\n\t\t\t out: %s\n", mid32[0], m7, ntime, nbits, nnonce, hex);
 		return 1;
 		return 1;
 	}
 	}
@@ -132,12 +132,8 @@ static bool bf1_detect_custom(const char *devpath, struct device_drv *api, struc
 		return false;
 		return false;
 	}
 	}
 
 
-	if(serial_claim(devpath, api))
-	{
-		const char *claimedby = serial_claim(devpath, api)->dname;
-		applog(LOG_DEBUG, "Bitfury BF1 device %s already claimed by other driver: %s", devpath, claimedby);
+	if (serial_claim_v(devpath, api))
 		return false;
 		return false;
-	}
 
 
 	/* We have a real MiniMiner ONE! */
 	/* We have a real MiniMiner ONE! */
 	struct cgpu_info *bf1;
 	struct cgpu_info *bf1;
@@ -303,10 +299,8 @@ static void bf1_process_results(struct thr_info *thr, struct work *work)
 			nonces--;
 			nonces--;
 			continue;
 			continue;
 		}
 		}
+		inc_hw_errors(thr, work, nonce);
 	}
 	}
-
-	for(int i=0; i<nonces; i++)
-		inc_hw_errors(thr);
 }
 }
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -391,22 +385,6 @@ static void bf1_poll(struct thr_info *thr)
 	timer_set_delay(&thr->tv_poll, &tv_now, 1000000);
 	timer_set_delay(&thr->tv_poll, &tv_now, 1000000);
 }
 }
 
 
-//------------------------------------------------------------------------------
-static void bf1_statline_before(char *buf, struct cgpu_info *cgpu)
-{
-	char before[] = "                    ";
-	if(cgpu->device_data)
-	{
-		struct BF1Info *info = (struct BF1Info *)cgpu->device_data;
-
-		int len = strlen(info->id.product);
-		memcpy(before, info->id.product, len);
-
-		sprintf(before + len + 1, "%08X", info->id.serial);
-	}
-	tailsprintf(buf, "%s | ", &before[0]);
-}
-
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 static void bf1_shutdown(struct thr_info *thr)
 static void bf1_shutdown(struct thr_info *thr)
 {
 {
@@ -431,7 +409,6 @@ struct device_drv bf1_drv = {
 	.minerloop = hash_queued_work,
 	.minerloop = hash_queued_work,
 
 
 	.drv_detect = bf1_detect,
 	.drv_detect = bf1_detect,
-	.get_statline_before = bf1_statline_before,
 
 
 	.identify_device = bf1_identify,
 	.identify_device = bf1_identify,
 
 

+ 114 - 71
driver-bitforce.c

@@ -37,7 +37,7 @@
 #define BITFORCE_QRESULT_LINE_LEN 165
 #define BITFORCE_QRESULT_LINE_LEN 165
 #define BITFORCE_MAX_QUEUED_MAX 40
 #define BITFORCE_MAX_QUEUED_MAX 40
 #define BITFORCE_MIN_QUEUED_MAX 10
 #define BITFORCE_MIN_QUEUED_MAX 10
-#define BITFORCE_MAX_QRESULTS 40
+#define BITFORCE_MAX_QRESULTS 16
 #define BITFORCE_GOAL_QRESULTS 5
 #define BITFORCE_GOAL_QRESULTS 5
 #define BITFORCE_MIN_QRESULT_WAIT BITFORCE_CHECK_INTERVAL_MS
 #define BITFORCE_MIN_QRESULT_WAIT BITFORCE_CHECK_INTERVAL_MS
 #define BITFORCE_MAX_QRESULT_WAIT 1000
 #define BITFORCE_MAX_QRESULT_WAIT 1000
@@ -131,9 +131,9 @@ void bitforce_cmd2(int fd, int procid, void *buf, size_t bufsz, const char *cmd,
 	
 	
 	if (unlikely(opt_dev_protocol))
 	if (unlikely(opt_dev_protocol))
 	{
 	{
-		char *hex = bin2hex(data, datasz);
+		char hex[(datasz * 2) + 1];
+		bin2hex(hex, data, datasz);
 		applog(LOG_DEBUG, "DEVPROTO: CMD2 (fd=%d xlink=%d): %s", fd, procid, hex);
 		applog(LOG_DEBUG, "DEVPROTO: CMD2 (fd=%d xlink=%d): %s", fd, procid, hex);
-		free(hex);
 	}
 	}
 	
 	
 	bitforce_send(fd, procid, data, datasz);
 	bitforce_send(fd, procid, data, datasz);
@@ -190,6 +190,9 @@ static bool bitforce_detect_one(const char *devpath)
 		return false;
 		return false;
 	}
 	}
 
 
+	if (serial_claim_v(devpath, &bitforce_drv))
+		return false;
+	
 	applog(LOG_DEBUG, "Found BitForce device on %s", devpath);
 	applog(LOG_DEBUG, "Found BitForce device on %s", devpath);
 	initdata = malloc(sizeof(*initdata));
 	initdata = malloc(sizeof(*initdata));
 	*initdata = (struct bitforce_init_data){
 	*initdata = (struct bitforce_init_data){
@@ -337,8 +340,7 @@ void bitforce_comm_error(struct thr_info *thr)
 	data->noncebuf[0] = '\0';
 	data->noncebuf[0] = '\0';
 	applog(LOG_ERR, "%"PRIpreprv": Comms error", bitforce->proc_repr);
 	applog(LOG_ERR, "%"PRIpreprv": Comms error", bitforce->proc_repr);
 	dev_error(bitforce, REASON_DEV_COMMS_ERROR);
 	dev_error(bitforce, REASON_DEV_COMMS_ERROR);
-	++bitforce->hw_errors;
-	++hw_errors;
+	inc_hw_errors_only(thr);
 	BFclose(*p_fdDev);
 	BFclose(*p_fdDev);
 	int fd = *p_fdDev = BFopen(bitforce->device_path);
 	int fd = *p_fdDev = BFopen(bitforce->device_path);
 	if (fd == -1)
 	if (fd == -1)
@@ -350,24 +352,6 @@ void bitforce_comm_error(struct thr_info *thr)
 	bitforce_clear_buffer(bitforce);
 	bitforce_clear_buffer(bitforce);
 }
 }
 
 
-static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
-{
-	struct bitforce_data *data = bitforce->device_data;
-	struct bitforce_proc_data *procdata = bitforce->thr[0]->cgpu_data;
-	
-	if (!procdata->handles_board)
-		goto nostats;
-
-	if (data->temp[0] > 0 && data->temp[1] > 0)
-		tailsprintf(buf, "%5.1fC/%4.1fC   | ", data->temp[0], data->temp[1]);
-	else
-	if (bitforce->temp > 0)
-		tailsprintf(buf, "%5.1fC         | ", bitforce->temp);
-	else
-nostats:
-		tailsprintf(buf, "               | ");
-}
-
 static bool bitforce_thread_prepare(struct thr_info *thr)
 static bool bitforce_thread_prepare(struct thr_info *thr)
 {
 {
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct cgpu_info *bitforce = thr->cgpu;
@@ -589,9 +573,9 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
 	mutex_unlock(mutexp);
 	mutex_unlock(mutexp);
 	
 	
 	if (unlikely(!pdevbuf[0])) {
 	if (unlikely(!pdevbuf[0])) {
+		struct thr_info *thr = bitforce->thr[0];
 		applog(LOG_ERR, "%"PRIpreprv": Error: Get temp returned empty string/timed out", bitforce->proc_repr);
 		applog(LOG_ERR, "%"PRIpreprv": Error: Get temp returned empty string/timed out", bitforce->proc_repr);
-		bitforce->hw_errors++;
-		++hw_errors;
+		inc_hw_errors_only(thr);
 		return false;
 		return false;
 	}
 	}
 
 
@@ -606,7 +590,7 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
 				float temp2 = my_strtof(s + 1, &s);
 				float temp2 = my_strtof(s + 1, &s);
 				set_float_if_gt_zero(&data->temp[1], temp2);
 				set_float_if_gt_zero(&data->temp[1], temp2);
 				if (temp2 > temp)
 				if (temp2 > temp)
-					temp = temp;
+					temp = temp2;
 			}
 			}
 		}
 		}
 
 
@@ -617,14 +601,14 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
 				chip_cgpu->temp = temp;
 				chip_cgpu->temp = temp;
 		}
 		}
 	} else {
 	} else {
+		struct thr_info *thr = bitforce->thr[0];
 		/* Use the temperature monitor as a kind of watchdog for when
 		/* Use the temperature monitor as a kind of watchdog for when
 		 * our responses are out of sync and flush the buffer to
 		 * our responses are out of sync and flush the buffer to
 		 * hopefully recover */
 		 * hopefully recover */
 		applog(LOG_WARNING, "%"PRIpreprv": Garbled response probably throttling, clearing buffer", bitforce->proc_repr);
 		applog(LOG_WARNING, "%"PRIpreprv": Garbled response probably throttling, clearing buffer", bitforce->proc_repr);
 		dev_error(bitforce, REASON_DEV_THROTTLE);
 		dev_error(bitforce, REASON_DEV_THROTTLE);
 		/* Count throttling episodes as hardware errors */
 		/* Count throttling episodes as hardware errors */
-		bitforce->hw_errors++;
-		++hw_errors;
+		inc_hw_errors_only(thr);
 		bitforce_clear_buffer(bitforce);
 		bitforce_clear_buffer(bitforce);
 		return false;
 		return false;
 	}
 	}
@@ -639,10 +623,9 @@ void dbg_block_data(struct cgpu_info *bitforce)
 		return;
 		return;
 	
 	
 	struct bitforce_data *data = bitforce->device_data;
 	struct bitforce_data *data = bitforce->device_data;
-	char *s;
-	s = bin2hex(&data->next_work_ob[8], 44);
+	char s[89];
+	bin2hex(s, &data->next_work_ob[8], 44);
 	applog(LOG_DEBUG, "%"PRIpreprv": block data: %s", bitforce->proc_repr, s);
 	applog(LOG_DEBUG, "%"PRIpreprv": block data: %s", bitforce->proc_repr, s);
-	free(s);
 }
 }
 
 
 static void bitforce_change_mode(struct cgpu_info *, enum bitforce_proto);
 static void bitforce_change_mode(struct cgpu_info *, enum bitforce_proto);
@@ -981,14 +964,14 @@ void bitforce_job_get_results(struct thr_info *thr, struct work *work)
 			{
 			{
 				// Didn't find the one we're waiting on
 				// Didn't find the one we're waiting on
 				// Must be extra stuff in the queue results
 				// Must be extra stuff in the queue results
-				char *xmid = bin2hex(work->midstate, 32);
-				char *xdt = bin2hex(&work->data[64], 12);
+				char xmid[65];
+				char xdt[25];
+				bin2hex(xmid, work->midstate, 32);
+				bin2hex(xdt, &work->data[64], 12);
 				applog(LOG_WARNING, "%"PRIpreprv": Found extra garbage in queue results: %s",
 				applog(LOG_WARNING, "%"PRIpreprv": Found extra garbage in queue results: %s",
 				       bitforce->proc_repr, pdevbuf);
 				       bitforce->proc_repr, pdevbuf);
 				applog(LOG_WARNING, "%"PRIpreprv": ...while waiting on: %s,%s",
 				applog(LOG_WARNING, "%"PRIpreprv": ...while waiting on: %s,%s",
 				       bitforce->proc_repr, xmid, xdt);
 				       bitforce->proc_repr, xmid, xdt);
-				free(xmid);
-				free(xdt);
 				count = 0;
 				count = 0;
 			}
 			}
 			else
 			else
@@ -1035,8 +1018,7 @@ noqr:
 		applog(LOG_ERR, "%"PRIpreprv": took %lums - longer than %lums", bitforce->proc_repr,
 		applog(LOG_ERR, "%"PRIpreprv": took %lums - longer than %lums", bitforce->proc_repr,
 			tv_to_ms(elapsed), (unsigned long)BITFORCE_TIMEOUT_MS);
 			tv_to_ms(elapsed), (unsigned long)BITFORCE_TIMEOUT_MS);
 		dev_error(bitforce, REASON_DEV_OVER_HEAT);
 		dev_error(bitforce, REASON_DEV_OVER_HEAT);
-		++bitforce->hw_errors;
-		++hw_errors;
+		inc_hw_errors_only(thr);
 
 
 		/* If the device truly throttled, it didn't process the job and there
 		/* If the device truly throttled, it didn't process the job and there
 		 * are no results. But check first, just in case we're wrong about it
 		 * are no results. But check first, just in case we're wrong about it
@@ -1092,8 +1074,7 @@ noqr:
 
 
 	applog(LOG_DEBUG, "%"PRIpreprv": waited %dms until %s", bitforce->proc_repr, bitforce->wait_ms, pdevbuf);
 	applog(LOG_DEBUG, "%"PRIpreprv": waited %dms until %s", bitforce->proc_repr, bitforce->wait_ms, pdevbuf);
 	if (count < 0 && strncasecmp(pdevbuf, "I", 1)) {
 	if (count < 0 && strncasecmp(pdevbuf, "I", 1)) {
-		bitforce->hw_errors++;
-		++hw_errors;
+		inc_hw_errors_only(thr);
 		applog(LOG_WARNING, "%"PRIpreprv": Error: Get result reports: %s", bitforce->proc_repr, pdevbuf);
 		applog(LOG_WARNING, "%"PRIpreprv": Error: Get result reports: %s", bitforce->proc_repr, pdevbuf);
 		bitforce_clear_buffer(bitforce);
 		bitforce_clear_buffer(bitforce);
 	}
 	}
@@ -1163,8 +1144,7 @@ void bitforce_process_qresult_line(struct thr_info *thr, char *buf, struct work
 	    || bitforce_process_qresult_line_i(thr, midstate, datatail, buf, thr->next_work) ))
 	    || bitforce_process_qresult_line_i(thr, midstate, datatail, buf, thr->next_work) ))
 	{
 	{
 		applog(LOG_ERR, "%"PRIpreprv": Failed to find work for queued results", bitforce->proc_repr);
 		applog(LOG_ERR, "%"PRIpreprv": Failed to find work for queued results", bitforce->proc_repr);
-		++bitforce->hw_errors;
-		++hw_errors;
+		inc_hw_errors_only(thr);
 	}
 	}
 }
 }
 
 
@@ -1312,6 +1292,7 @@ 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);
 		}
 		}
+		bitforce->status = LIFE_INIT2;
 		
 		
 		first_on_this_board = procdata;
 		first_on_this_board = procdata;
 		for (int proc = 1; proc < data->parallel; ++proc)
 		for (int proc = 1; proc < data->parallel; ++proc)
@@ -1326,6 +1307,7 @@ static bool bitforce_thread_init(struct thr_info *thr)
 			procdata->handles_board = false;
 			procdata->handles_board = false;
 			procdata->cgpu = bitforce;
 			procdata->cgpu = bitforce;
 			bitforce->device_data = data;
 			bitforce->device_data = data;
+			bitforce->status = LIFE_INIT2;
 		}
 		}
 		applog(LOG_DEBUG, "%s: Board %d: %"PRIpreprv"-%"PRIpreprv, bitforce->dev_repr, boardno, first_on_this_board->cgpu->proc_repr, bitforce->proc_repr);
 		applog(LOG_DEBUG, "%s: Board %d: %"PRIpreprv"-%"PRIpreprv, bitforce->dev_repr, boardno, first_on_this_board->cgpu->proc_repr, bitforce->proc_repr);
 		
 		
@@ -1348,6 +1330,62 @@ static bool bitforce_thread_init(struct thr_info *thr)
 	return true;
 	return true;
 }
 }
 
 
+#ifdef HAVE_CURSES
+static
+void bitforce_tui_wlogprint_choices(struct cgpu_info *cgpu)
+{
+	struct bitforce_data *data = cgpu->device_data;
+	if (data->sc)
+		wlogprint("[F]an control ");
+}
+
+static
+const char *bitforce_tui_handle_choice(struct cgpu_info *cgpu, int input)
+{
+	struct bitforce_data *data = cgpu->device_data;
+	pthread_mutex_t *mutexp;
+	int fd;
+	static char replybuf[0x100];
+	
+	if (!data->sc)
+		return NULL;
+	switch (input)
+	{
+		case 'f': case 'F':
+		{
+			int fanspeed;
+			char *intvar;
+
+			intvar = curses_input("Set fan speed (range 0-4 for low to fast or 5 for auto)");
+			if (!intvar)
+				return "Invalid fan speed\n";
+			fanspeed = atoi(intvar);
+			free(intvar);
+			if (fanspeed < 0 || fanspeed > 5)
+				return "Invalid fan speed\n";
+			
+			char cmd[4] = "Z0X";
+			cmd[1] += fanspeed;
+			mutexp = &cgpu->device->device_mutex;
+			mutex_lock(mutexp);
+			fd = cgpu->device->device_fd;
+			bitforce_cmd1(fd, data->xlink_id, replybuf, sizeof(replybuf), cmd);
+			mutex_unlock(mutexp);
+			return replybuf;
+		}
+	}
+	return NULL;
+}
+
+static
+void bitforce_wlogprint_status(struct cgpu_info *cgpu)
+{
+	struct bitforce_data *data = cgpu->device_data;
+	if (data->temp[0] > 0 && data->temp[1] > 0)
+		wlogprint("Temperatures: %4.1fC %4.1fC\n", data->temp[0], data->temp[1]);
+}
+#endif
+
 static struct api_data *bitforce_drv_stats(struct cgpu_info *cgpu)
 static struct api_data *bitforce_drv_stats(struct cgpu_info *cgpu)
 {
 {
 	struct bitforce_data *data = cgpu->device_data;
 	struct bitforce_data *data = cgpu->device_data;
@@ -1432,10 +1470,14 @@ struct device_drv bitforce_drv = {
 	.dname = "bitforce",
 	.dname = "bitforce",
 	.name = "BFL",
 	.name = "BFL",
 	.drv_detect = bitforce_detect,
 	.drv_detect = bitforce_detect,
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = bitforce_wlogprint_status,
+	.proc_tui_wlogprint_choices = bitforce_tui_wlogprint_choices,
+	.proc_tui_handle_choice = bitforce_tui_handle_choice,
+#endif
 	.get_api_stats = bitforce_drv_stats,
 	.get_api_stats = bitforce_drv_stats,
 	.minerloop = minerloop_async,
 	.minerloop = minerloop_async,
 	.reinit_device = bitforce_reinit,
 	.reinit_device = bitforce_reinit,
-	.get_statline_before = get_bitforce_statline_before,
 	.get_stats = bitforce_get_stats,
 	.get_stats = bitforce_get_stats,
 	.set_device = bitforce_set_device,
 	.set_device = bitforce_set_device,
 	.identify_device = bitforce_identify,
 	.identify_device = bitforce_identify,
@@ -1543,7 +1585,8 @@ bool bitforce_queue_do_results(struct thr_info *thr)
 	struct bitforce_data *data = bitforce->device_data;
 	struct bitforce_data *data = bitforce->device_data;
 	int fd = bitforce->device->device_fd;
 	int fd = bitforce->device->device_fd;
 	int count;
 	int count;
-	char *noncebuf = &data->noncebuf[0], *buf, *end;
+	int fcount;
+	char *noncebuf, *buf, *end;
 	unsigned char midstate[32], datatail[12];
 	unsigned char midstate[32], datatail[12];
 	struct work *work, *tmpwork, *thiswork;
 	struct work *work, *tmpwork, *thiswork;
 	struct timeval tv_now, tv_elapsed;
 	struct timeval tv_now, tv_elapsed;
@@ -1555,23 +1598,22 @@ bool bitforce_queue_do_results(struct thr_info *thr)
 	if (unlikely(!fd))
 	if (unlikely(!fd))
 		return false;
 		return false;
 	
 	
+again:
+	noncebuf = &data->noncebuf[0];
 	count = bitforce_zox(thr, "ZOX");
 	count = bitforce_zox(thr, "ZOX");
 	
 	
-	if (!count)
-	{
-		applog(LOG_DEBUG, "%"PRIpreprv": Received 0 queued results on poll", bitforce->proc_repr);
-		return true;
-	}
-	
 	if (unlikely(count < 0))
 	if (unlikely(count < 0))
 	{
 	{
 		applog(LOG_ERR, "%"PRIpreprv": Received unexpected queue result response: %s", bitforce->proc_repr, noncebuf);
 		applog(LOG_ERR, "%"PRIpreprv": Received unexpected queue result response: %s", bitforce->proc_repr, noncebuf);
-		++bitforce->hw_errors;
-		++hw_errors;
+		inc_hw_errors_only(thr);
 		return false;
 		return false;
 	}
 	}
 	
 	
-	count = 0;
+	applog(LOG_DEBUG, "%"PRIpreprv": Received %d queue results on poll (max=%d)", bitforce->proc_repr, count, (int)BITFORCE_MAX_QRESULTS);
+	if (!count)
+		return true;
+	
+	fcount = 0;
 	for (int i = 0; i < data->parallel; ++i)
 	for (int i = 0; i < data->parallel; ++i)
 		counts[i] = 0;
 		counts[i] = 0;
 	noncebuf = next_line(noncebuf);
 	noncebuf = next_line(noncebuf);
@@ -1620,8 +1662,7 @@ bool bitforce_queue_do_results(struct thr_info *thr)
 		if (unlikely(!thiswork))
 		if (unlikely(!thiswork))
 		{
 		{
 			applog(LOG_ERR, "%"PRIpreprv": Failed to find work for queue results: %s", chip_cgpu->proc_repr, buf);
 			applog(LOG_ERR, "%"PRIpreprv": Failed to find work for queue results: %s", chip_cgpu->proc_repr, buf);
-			++chip_cgpu->hw_errors;
-			++hw_errors;
+			inc_hw_errors_only(chip_thr);
 			goto next_qline;
 			goto next_qline;
 		}
 		}
 		
 		
@@ -1639,7 +1680,7 @@ bool bitforce_queue_do_results(struct thr_info *thr)
 			}
 			}
 			bitforce_process_result_nonces(chip_thr, work, &end[1]);
 			bitforce_process_result_nonces(chip_thr, work, &end[1]);
 		}
 		}
-		++count;
+		++fcount;
 		++counts[chipno];
 		++counts[chipno];
 		
 		
 finishresult:
 finishresult:
@@ -1669,22 +1710,25 @@ next_qline: (void)0;
 	
 	
 	bitforce_set_queue_full(thr);
 	bitforce_set_queue_full(thr);
 	
 	
+	if (count >= BITFORCE_MAX_QRESULTS)
+		goto again;
+	
 	if (data->parallel == 1 && (
 	if (data->parallel == 1 && (
-	        (count < BITFORCE_GOAL_QRESULTS && bitforce->sleep_ms < BITFORCE_MAX_QRESULT_WAIT && data->queued > 1)
-	     || (count > BITFORCE_GOAL_QRESULTS && bitforce->sleep_ms > BITFORCE_MIN_QRESULT_WAIT)  ))
+	        (fcount < BITFORCE_GOAL_QRESULTS && bitforce->sleep_ms < BITFORCE_MAX_QRESULT_WAIT && data->queued > 1)
+	     || (fcount > BITFORCE_GOAL_QRESULTS && bitforce->sleep_ms > BITFORCE_MIN_QRESULT_WAIT)  ))
 	{
 	{
 		unsigned int old_sleep_ms = bitforce->sleep_ms;
 		unsigned int old_sleep_ms = bitforce->sleep_ms;
-		bitforce->sleep_ms = (uint32_t)bitforce->sleep_ms * BITFORCE_GOAL_QRESULTS / (count ?: 1);
+		bitforce->sleep_ms = (uint32_t)bitforce->sleep_ms * BITFORCE_GOAL_QRESULTS / (fcount ?: 1);
 		if (bitforce->sleep_ms > BITFORCE_MAX_QRESULT_WAIT)
 		if (bitforce->sleep_ms > BITFORCE_MAX_QRESULT_WAIT)
 			bitforce->sleep_ms = BITFORCE_MAX_QRESULT_WAIT;
 			bitforce->sleep_ms = BITFORCE_MAX_QRESULT_WAIT;
 		if (bitforce->sleep_ms < BITFORCE_MIN_QRESULT_WAIT)
 		if (bitforce->sleep_ms < BITFORCE_MIN_QRESULT_WAIT)
 			bitforce->sleep_ms = BITFORCE_MIN_QRESULT_WAIT;
 			bitforce->sleep_ms = BITFORCE_MIN_QRESULT_WAIT;
 		applog(LOG_DEBUG, "%"PRIpreprv": Received %d queue results after %ums; Wait time changed to: %ums (queued<=%d)",
 		applog(LOG_DEBUG, "%"PRIpreprv": Received %d queue results after %ums; Wait time changed to: %ums (queued<=%d)",
-		       bitforce->proc_repr, count, old_sleep_ms, bitforce->sleep_ms, data->queued);
+		       bitforce->proc_repr, fcount, old_sleep_ms, bitforce->sleep_ms, data->queued);
 	}
 	}
 	else
 	else
 		applog(LOG_DEBUG, "%"PRIpreprv": Received %d queue results after %ums; Wait time unchanged (queued<=%d)",
 		applog(LOG_DEBUG, "%"PRIpreprv": Received %d queue results after %ums; Wait time unchanged (queued<=%d)",
-		       bitforce->proc_repr, count, bitforce->sleep_ms, data->queued);
+		       bitforce->proc_repr, fcount, bitforce->sleep_ms, data->queued);
 	
 	
 	cgtime(&tv_now);
 	cgtime(&tv_now);
 	timersub(&tv_now, &data->tv_hashmeter_start, &tv_elapsed);
 	timersub(&tv_now, &data->tv_hashmeter_start, &tv_elapsed);
@@ -1732,8 +1776,7 @@ bool bitforce_queue_append(struct thr_info *thr, struct work *work)
 		{
 		{
 			// Problem sending queue, retry again in a few seconds
 			// Problem sending queue, retry again in a few seconds
 			applog(LOG_ERR, "%"PRIpreprv": Failed to send queue", bitforce->proc_repr);
 			applog(LOG_ERR, "%"PRIpreprv": Failed to send queue", bitforce->proc_repr);
-			++bitforce->hw_errors;
-			++hw_errors;
+			inc_hw_errors_only(thr);
 			data->want_to_send_queue = true;
 			data->want_to_send_queue = true;
 		}
 		}
 	}
 	}
@@ -1756,7 +1799,7 @@ void bitforce_queue_flush(struct thr_info *thr)
 	
 	
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct bitforce_data *data = bitforce->device_data;
 	struct bitforce_data *data = bitforce->device_data;
-	char *buf = &data->noncebuf[0], *buf2;
+	char *buf = &data->noncebuf[0], *buf2 = NULL;
 	const char *cmd = "ZqX";
 	const char *cmd = "ZqX";
 	unsigned flushed;
 	unsigned flushed;
 	struct _jobinfo *processing = NULL, *item, *this;
 	struct _jobinfo *processing = NULL, *item, *this;
@@ -1767,10 +1810,7 @@ void bitforce_queue_flush(struct thr_info *thr)
 	// TODO: Call "ZQX" most of the time: don't need to do sanity checks so often
 	// TODO: Call "ZQX" most of the time: don't need to do sanity checks so often
 	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]);
-		buf2 = NULL;
-	}
 	else
 	else
 	if ((!strncasecmp(buf, "COUNT:", 6)) && (buf2 = strstr(buf, "FLUSHED:")) )
 	if ((!strncasecmp(buf, "COUNT:", 6)) && (buf2 = strstr(buf, "FLUSHED:")) )
 	{
 	{
@@ -1837,9 +1877,9 @@ void bitforce_queue_flush(struct thr_info *thr)
 			HASH_FIND(hh, processing, &key[0], sizeof(key), item);
 			HASH_FIND(hh, processing, &key[0], sizeof(key), item);
 			if (unlikely(!item))
 			if (unlikely(!item))
 			{
 			{
-				char *hex = bin2hex(key, 32+12);
+				char hex[89];
+				bin2hex(hex, key, 32+12);
 				applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device is missing queued job! %s", bitforce->proc_repr, hex);
 				applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device is missing queued job! %s", bitforce->proc_repr, hex);
-				free(hex);
 				work_list_del(&thr->work_list, work);
 				work_list_del(&thr->work_list, work);
 				continue;
 				continue;
 			}
 			}
@@ -1879,8 +1919,7 @@ void bitforce_queue_poll(struct thr_info *thr)
 			if (!data->queued)
 			if (!data->queued)
 			{
 			{
 				applog(LOG_ERR, "%"PRIpreprv": Failed to send queue, and queue empty; retrying after 1 second", bitforce->proc_repr);
 				applog(LOG_ERR, "%"PRIpreprv": Failed to send queue, and queue empty; retrying after 1 second", bitforce->proc_repr);
-				++bitforce->hw_errors;
-				++hw_errors;
+				inc_hw_errors_only(thr);
 				sleep_us = 1000000;
 				sleep_us = 1000000;
 			}
 			}
 	
 	
@@ -1921,7 +1960,11 @@ struct device_drv bitforce_queue_api = {
 	.name = "BFL",
 	.name = "BFL",
 	.minerloop = minerloop_queue,
 	.minerloop = minerloop_queue,
 	.reinit_device = bitforce_reinit,
 	.reinit_device = bitforce_reinit,
-	.get_statline_before = get_bitforce_statline_before,
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = bitforce_wlogprint_status,
+	.proc_tui_wlogprint_choices = bitforce_tui_wlogprint_choices,
+	.proc_tui_handle_choice = bitforce_tui_handle_choice,
+#endif
 	.get_api_stats = bitforce_drv_stats,
 	.get_api_stats = bitforce_drv_stats,
 	.get_stats = bitforce_get_stats,
 	.get_stats = bitforce_get_stats,
 	.set_device = bitforce_set_device,
 	.set_device = bitforce_set_device,

+ 0 - 2
driver-cairnsmore.c

@@ -196,8 +196,6 @@ static bool cairnsmore_identify(struct cgpu_info *cm1)
 	return true;
 	return true;
 }
 }
 
 
-extern struct device_drv icarus_drv;
-
 static void cairnsmore_drv_init()
 static void cairnsmore_drv_init()
 {
 {
 	cairnsmore_drv = icarus_drv;
 	cairnsmore_drv = icarus_drv;

+ 20 - 5
driver-cpu.c

@@ -30,8 +30,10 @@
 #include <libgen.h>
 #include <libgen.h>
 
 
 #include "compat.h"
 #include "compat.h"
+#include "fpgautils.h"
 #include "miner.h"
 #include "miner.h"
 #include "bench_block.h"
 #include "bench_block.h"
+#include "util.h"
 #include "driver-cpu.h"
 #include "driver-cpu.h"
 
 
 #if defined(unix)
 #if defined(unix)
@@ -709,7 +711,7 @@ char *force_nthreads_int(const char *arg, int *i)
 #endif
 #endif
 
 
 #ifdef WANT_CPUMINE
 #ifdef WANT_CPUMINE
-static void cpu_detect()
+static int cpu_autodetect()
 {
 {
 	int i;
 	int i;
 
 
@@ -745,13 +747,10 @@ static void cpu_detect()
 	#endif /* !WIN32 */
 	#endif /* !WIN32 */
 
 
 	if (opt_n_threads < 0 || !forced_n_threads) {
 	if (opt_n_threads < 0 || !forced_n_threads) {
-		if (total_devices && !opt_usecpu)
-			opt_n_threads = 0;
-		else
 			opt_n_threads = num_processors;
 			opt_n_threads = num_processors;
 	}
 	}
 	if (num_processors < 1)
 	if (num_processors < 1)
-		return;
+		return 0;
 
 
 	cpus = calloc(opt_n_threads, sizeof(struct cgpu_info));
 	cpus = calloc(opt_n_threads, sizeof(struct cgpu_info));
 	if (unlikely(!cpus))
 	if (unlikely(!cpus))
@@ -767,6 +766,19 @@ static void cpu_detect()
 		cgpu->kname = algo_names[opt_algo];
 		cgpu->kname = algo_names[opt_algo];
 		add_cgpu(cgpu);
 		add_cgpu(cgpu);
 	}
 	}
+	return opt_n_threads;
+}
+
+static void cpu_detect()
+{
+	RUNONCE();
+	
+	if ((opt_n_threads < 0 || !forced_n_threads)
+	 && ((total_devices || total_devices_new) && !opt_usecpu))
+		// If there are any other devices, only act if the user has explicitly enabled it
+		noserial_detect_manual(&cpu_drv, cpu_autodetect);
+	else
+		noserial_detect(&cpu_drv, cpu_autodetect);
 }
 }
 
 
 static pthread_mutex_t cpualgo_lock;
 static pthread_mutex_t cpualgo_lock;
@@ -791,6 +803,7 @@ static uint64_t cpu_can_limit_work(struct thr_info __maybe_unused *thr)
 static bool cpu_thread_init(struct thr_info *thr)
 static bool cpu_thread_init(struct thr_info *thr)
 {
 {
 	const int thr_id = thr->id;
 	const int thr_id = thr->id;
+	struct cgpu_info *cgpu = thr->cgpu;
 
 
 	mutex_lock(&cpualgo_lock);
 	mutex_lock(&cpualgo_lock);
 	switch (opt_algo)
 	switch (opt_algo)
@@ -803,6 +816,8 @@ static bool cpu_thread_init(struct thr_info *thr)
 	}
 	}
 	mutex_unlock(&cpualgo_lock);
 	mutex_unlock(&cpualgo_lock);
 
 
+	cgpu->kname = algo_names[opt_algo];
+	
 	/* Set worker threads to nice 19 and then preferentially to SCHED_IDLE
 	/* Set worker threads to nice 19 and then preferentially to SCHED_IDLE
 	 * and if that fails, then SCHED_BATCH. No need for this to be an
 	 * and if that fails, then SCHED_BATCH. No need for this to be an
 	 * error if it fails */
 	 * error if it fails */

+ 84 - 0
driver-erupter.c

@@ -0,0 +1,84 @@
+/*
+ * Copyright 2013 Luke Dashjr
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "fpgautils.h"
+#include "icarus-common.h"
+
+#define ERUPTER_IO_SPEED 115200
+#define ERUPTER_HASH_TIME 0.0000000029761
+
+extern struct device_drv erupter_drv;
+extern struct device_drv erupter_drv_emerald;
+
+static bool _erupter_detect_one(const char *devpath, struct device_drv *drv)
+{
+	struct ICARUS_INFO *info = calloc(1, sizeof(struct ICARUS_INFO));
+	if (unlikely(!info))
+		quit(1, "Failed to malloc ICARUS_INFO");
+
+	*info = (struct ICARUS_INFO){
+		.baud = ERUPTER_IO_SPEED,
+		.Hs = ERUPTER_HASH_TIME,
+		.timing_mode = MODE_DEFAULT,
+	};
+
+	if (!icarus_detect_custom(devpath, drv, info)) {
+		free(info);
+		return false;
+	}
+	return true;
+}
+
+static bool erupter_emerald_detect_one(const char *devpath)
+{
+	return _erupter_detect_one(devpath, &erupter_drv_emerald);
+}
+
+static bool erupter_detect_one(const char *devpath)
+{
+	return _erupter_detect_one(devpath, &erupter_drv);
+}
+
+static int erupter_emerald_detect_auto(void)
+{
+	return serial_autodetect(erupter_emerald_detect_one, "Block", "Erupter", "Emerald");
+}
+
+static int erupter_detect_auto(void)
+{
+	return serial_autodetect(erupter_detect_one, "Block", "Erupter");
+}
+
+static void erupter_drv_init();
+
+static void erupter_detect()
+{
+	erupter_drv_init();
+	// Actual serial detection is handled by Icarus driver
+	serial_detect_auto_byname(&erupter_drv_emerald, erupter_emerald_detect_one, erupter_emerald_detect_auto);
+	serial_detect_auto_byname(&erupter_drv, erupter_detect_one, erupter_detect_auto);
+}
+
+static void erupter_drv_init()
+{
+	erupter_drv = icarus_drv;
+	erupter_drv.dname = "erupter";
+	erupter_drv.name = "BES";
+	erupter_drv.drv_detect = erupter_detect;
+	
+	erupter_drv_emerald = erupter_drv;
+	erupter_drv_emerald.name = "BEE";
+}
+
+struct device_drv erupter_drv = {
+	// Needed to get to erupter_drv_init at all
+	.drv_detect = erupter_detect,
+};
+
+struct device_drv erupter_drv_emerald;

+ 12 - 21
driver-icarus.c

@@ -472,16 +472,8 @@ static void get_options(int this_option_offset, struct ICARUS_INFO *info)
 
 
 		if (*buf) {
 		if (*buf) {
 			tmp = atoi(buf);
 			tmp = atoi(buf);
-			switch (tmp) {
-			case 115200:
-				*baud = 115200;
-				break;
-			case 57600:
-				*baud = 57600;
-				break;
-			default:
-				quit(1, "Invalid icarus-options for baud (%s) must be 115200 or 57600", buf);
-			}
+			if (!valid_baud(*baud = tmp))
+				quit(1, "Invalid icarus-options for baud (%s)", buf);
 		}
 		}
 
 
 		if (colon && *colon) {
 		if (colon && *colon) {
@@ -555,7 +547,7 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 	const char golden_nonce[] = "000187a2";
 	const char golden_nonce[] = "000187a2";
 
 
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
-	char *nonce_hex;
+	char nonce_hex[(sizeof(nonce_bin) * 2) + 1];
 
 
 	get_options(this_option_offset, info);
 	get_options(this_option_offset, info);
 
 
@@ -580,26 +572,21 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 
 
 	icarus_close(fd);
 	icarus_close(fd);
 
 
-	nonce_hex = bin2hex(nonce_bin, sizeof(nonce_bin));
+	bin2hex(nonce_hex, nonce_bin, sizeof(nonce_bin));
 	if (strncmp(nonce_hex, golden_nonce, 8)) {
 	if (strncmp(nonce_hex, golden_nonce, 8)) {
 		applog(LOG_DEBUG,
 		applog(LOG_DEBUG,
 			"Icarus Detect: "
 			"Icarus Detect: "
 			"Test failed at %s: get %s, should: %s",
 			"Test failed at %s: get %s, should: %s",
 			devpath, nonce_hex, golden_nonce);
 			devpath, nonce_hex, golden_nonce);
-		free(nonce_hex);
 		return false;
 		return false;
 	}
 	}
 	applog(LOG_DEBUG,
 	applog(LOG_DEBUG,
 		"Icarus Detect: "
 		"Icarus Detect: "
 		"Test succeeded at %s: got %s",
 		"Test succeeded at %s: got %s",
 			devpath, nonce_hex);
 			devpath, nonce_hex);
-	free(nonce_hex);
 
 
-	if (serial_claim(devpath, api)) {
-		const char *claimedby = serial_claim(devpath, api)->dname;
-		applog(LOG_DEBUG, "Icarus device %s already claimed by other driver: %s", devpath, claimedby);
+	if (serial_claim_v(devpath, api))
 		return false;
 		return false;
-	}
 
 
 	/* We have a real Icarus! */
 	/* We have a real Icarus! */
 	struct cgpu_info *icarus;
 	struct cgpu_info *icarus;
@@ -633,6 +620,9 @@ static bool icarus_detect_one(const char *devpath)
 	if (unlikely(!info))
 	if (unlikely(!info))
 		quit(1, "Failed to malloc ICARUS_INFO");
 		quit(1, "Failed to malloc ICARUS_INFO");
 
 
+	// TODO: try some higher speeds with the Icarus and BFL to see
+	// if they support them and if setting them makes any difference
+	// N.B. B3000000 doesn't work on Icarus
 	info->baud = ICARUS_IO_SPEED;
 	info->baud = ICARUS_IO_SPEED;
 	info->quirk_reopen = 1;
 	info->quirk_reopen = 1;
 	info->Hs = ICARUS_REV3_HASH_TIME;
 	info->Hs = ICARUS_REV3_HASH_TIME;
@@ -685,6 +675,8 @@ static bool icarus_prepare(struct thr_info *thr)
 	}
 	}
 #endif
 #endif
 
 
+	icarus->status = LIFE_INIT2;
+	
 	return true;
 	return true;
 }
 }
 
 
@@ -764,7 +756,6 @@ static bool icarus_start_work(struct thr_info *thr, const unsigned char *ob_bin)
 	struct icarus_state *state = thr->cgpu_data;
 	struct icarus_state *state = thr->cgpu_data;
 	int fd = icarus->device_fd;
 	int fd = icarus->device_fd;
 	int ret;
 	int ret;
-	char *ob_hex;
 
 
 	cgtime(&state->tv_workstart);
 	cgtime(&state->tv_workstart);
 
 
@@ -777,11 +768,11 @@ static bool icarus_start_work(struct thr_info *thr, const unsigned char *ob_bin)
 	}
 	}
 
 
 	if (opt_debug) {
 	if (opt_debug) {
-		ob_hex = bin2hex(ob_bin, 64);
+		char ob_hex[129];
+		bin2hex(ob_hex, ob_bin, 64);
 		applog(LOG_DEBUG, "%"PRIpreprv" sent: %s",
 		applog(LOG_DEBUG, "%"PRIpreprv" sent: %s",
 			icarus->proc_repr,
 			icarus->proc_repr,
 			ob_hex);
 			ob_hex);
-		free(ob_hex);
 	}
 	}
 
 
 	return true;
 	return true;

+ 14 - 69
driver-modminer.c

@@ -123,6 +123,9 @@ modminer_detect_one(const char *devpath)
 	char*devname = strdup(buf);
 	char*devname = strdup(buf);
 	applog(LOG_DEBUG, "ModMiner identified as: %s", devname);
 	applog(LOG_DEBUG, "ModMiner identified as: %s", devname);
 
 
+	if (serial_claim_v(devpath, &modminer_drv))
+		return false;
+	
 	if (1 != write(fd, MODMINER_FPGA_COUNT, 1))
 	if (1 != write(fd, MODMINER_FPGA_COUNT, 1))
 		bailout(LOG_DEBUG, "ModMiner detect: write failed on %s (get FPGA count)", devpath);
 		bailout(LOG_DEBUG, "ModMiner detect: write failed on %s (get FPGA count)", devpath);
 	len = read(fd, buf, 1);
 	len = read(fd, buf, 1);
@@ -297,6 +300,8 @@ modminer_fpga_prepare(struct thr_info *thr)
 	dclk_prepare(&state->dclk);
 	dclk_prepare(&state->dclk);
 	state->next_work_cmd[0] = MODMINER_SEND_WORK;
 	state->next_work_cmd[0] = MODMINER_SEND_WORK;
 	state->next_work_cmd[1] = proc->proc_id;  // FPGA id
 	state->next_work_cmd[1] = proc->proc_id;  // FPGA id
+	
+	proc->status = LIFE_INIT2;
 
 
 	return true;
 	return true;
 }
 }
@@ -409,7 +414,7 @@ modminer_fpga_init(struct thr_info *thr)
 		applog(LOG_ERR, "%s: FPGA not programmed", modminer->proc_repr);
 		applog(LOG_ERR, "%s: FPGA not programmed", modminer->proc_repr);
 		if (!modminer_fpga_upload_bitstream(modminer))
 		if (!modminer_fpga_upload_bitstream(modminer))
 			return false;
 			return false;
-	} else if (opt_force_dev_init && modminer->status == LIFE_INIT) {
+	} else if (opt_force_dev_init && !((struct modminer_fpga_state *)modminer->device->thr[0]->cgpu_data)->pdone) {
 		applog(LOG_DEBUG, "%s: FPGA is already programmed, but --force-dev-init is set",
 		applog(LOG_DEBUG, "%s: FPGA is already programmed, but --force-dev-init is set",
 		       modminer->proc_repr);
 		       modminer->proc_repr);
 		if (!modminer_fpga_upload_bitstream(modminer))
 		if (!modminer_fpga_upload_bitstream(modminer))
@@ -451,73 +456,16 @@ modminer_fpga_init(struct thr_info *thr)
 }
 }
 
 
 static
 static
-bool get_modminer_upload_percent(char *buf, struct cgpu_info *modminer)
+bool get_modminer_upload_percent(char *buf, struct cgpu_info *modminer, __maybe_unused bool per_processor)
 {
 {
-	char info[18] = "               | ";
-
 	char pdone = ((struct modminer_fpga_state*)(modminer->device->thr[0]->cgpu_data))->pdone;
 	char pdone = ((struct modminer_fpga_state*)(modminer->device->thr[0]->cgpu_data))->pdone;
 	if (pdone != 101) {
 	if (pdone != 101) {
-		sprintf(&info[1], "%3d%%", pdone);
-		info[5] = ' ';
-		strcat(buf, info);
+		tailsprintf(buf, "%3d%% ", pdone);
 		return true;
 		return true;
 	}
 	}
 	return false;
 	return false;
 }
 }
 
 
-static
-void get_modminer_statline_before(char *buf, struct cgpu_info *modminer)
-{
-	if (get_modminer_upload_percent(buf, modminer))
-		return;
-
-	struct thr_info*thr = modminer->thr[0];
-	struct modminer_fpga_state *state = thr->cgpu_data;
-	float gt = state->temp;
-	
-	if (gt > 0)
-		tailsprintf(buf, "%5.1fC ", gt);
-	else
-		tailsprintf(buf, "       ");
-	tailsprintf(buf, "        | ");
-}
-
-static
-void get_modminer_dev_statline_before(char *buf, struct cgpu_info *modminer)
-{
-	if (get_modminer_upload_percent(buf, modminer))
-		return;
-
-	char info[18] = "               | ";
-	int tc = modminer->procs;
-	bool havetemp = false;
-	int i;
-
-	if (tc > 4)
-		tc = 4;
-
-	for (i = 0; i < tc; ++i, modminer = modminer->next_proc) {
-		struct thr_info*thr = modminer->thr[0];
-		struct modminer_fpga_state *state = thr->cgpu_data;
-		unsigned char temp = state->temp;
-
-		info[i*3+2] = '/';
-		if (temp) {
-			havetemp = true;
-			if (temp > 9)
-				info[i*3+0] = 0x30 + (temp / 10);
-			info[i*3+1] = 0x30 + (temp % 10);
-		}
-	}
-	if (havetemp) {
-		info[tc*3-1] = ' ';
-		info[tc*3] = 'C';
-		strcat(buf, info);
-	}
-	else
-		strcat(buf, "               | ");
-}
-
 static void modminer_get_temperature(struct cgpu_info *modminer, struct thr_info *thr)
 static void modminer_get_temperature(struct cgpu_info *modminer, struct thr_info *thr)
 {
 {
 	struct modminer_fpga_state *state = thr->cgpu_data;
 	struct modminer_fpga_state *state = thr->cgpu_data;
@@ -650,10 +598,10 @@ fd_set fds;
 	status_read("start work");
 	status_read("start work");
 	mutex_unlock(mutexp);
 	mutex_unlock(mutexp);
 	if (opt_debug) {
 	if (opt_debug) {
-		char *xdata = bin2hex(state->running_work.data, 80);
+		char xdata[161];
+		bin2hex(xdata, state->running_work.data, 80);
 		applog(LOG_DEBUG, "%s: Started work: %s",
 		applog(LOG_DEBUG, "%s: Started work: %s",
 		       modminer->proc_repr, xdata);
 		       modminer->proc_repr, xdata);
-		free(xdata);
 	}
 	}
 
 
 	return true;
 	return true;
@@ -712,11 +660,7 @@ modminer_process_results(struct thr_info*thr)
 				submit_nonce(thr, work, nonce);
 				submit_nonce(thr, work, nonce);
 			}
 			}
 			else {
 			else {
-				applog(LOG_DEBUG, "%s: Nonce with H not zero  : %02x%02x%02x%02x",
-				       modminer->proc_repr,
-				       NONCE_CHARS(nonce));
-				++hw_errors;
-				++modminer->hw_errors;
+				inc_hw_errors(thr, work, nonce);
 				++state->bad_share_counter;
 				++state->bad_share_counter;
 				++immediate_bad_nonces;
 				++immediate_bad_nonces;
 			}
 			}
@@ -794,6 +738,8 @@ modminer_scanhash(struct thr_info*thr, struct work*work, int64_t __maybe_unused
 static void
 static void
 modminer_fpga_shutdown(struct thr_info *thr)
 modminer_fpga_shutdown(struct thr_info *thr)
 {
 {
+	for (struct cgpu_info *proc = thr->cgpu->device; proc; proc = proc->next_proc)
+		proc->status = LIFE_DEAD2;
 	free(thr->cgpu_data);
 	free(thr->cgpu_data);
 	thr->cgpu_data = NULL;
 	thr->cgpu_data = NULL;
 }
 }
@@ -848,8 +794,7 @@ struct device_drv modminer_drv = {
 	.dname = "modminer",
 	.dname = "modminer",
 	.name = "MMQ",
 	.name = "MMQ",
 	.drv_detect = modminer_detect,
 	.drv_detect = modminer_detect,
-	.get_dev_statline_before = get_modminer_dev_statline_before,
-	.get_statline_before = get_modminer_statline_before,
+	.override_statline_temp = get_modminer_upload_percent,
 	.get_stats = modminer_get_stats,
 	.get_stats = modminer_get_stats,
 	.get_api_extra_device_status = get_modminer_drv_extra_device_status,
 	.get_api_extra_device_status = get_modminer_drv_extra_device_status,
 	.set_device = modminer_set_device,
 	.set_device = modminer_set_device,

+ 148 - 217
driver-opencl.c

@@ -39,6 +39,7 @@
 #define OMIT_OPENCL_API
 #define OMIT_OPENCL_API
 
 
 #include "compat.h"
 #include "compat.h"
+#include "fpgautils.h"
 #include "miner.h"
 #include "miner.h"
 #include "driver-opencl.h"
 #include "driver-opencl.h"
 #include "findnonce.h"
 #include "findnonce.h"
@@ -834,217 +835,145 @@ struct device_drv opencl_api;
 #endif /* HAVE_OPENCL */
 #endif /* HAVE_OPENCL */
 
 
 #if defined(HAVE_OPENCL) && defined(HAVE_CURSES)
 #if defined(HAVE_OPENCL) && defined(HAVE_CURSES)
-void manage_gpu(void)
+static
+void opencl_wlogprint_status(struct cgpu_info *cgpu)
 {
 {
 	struct thr_info *thr;
 	struct thr_info *thr;
-	int selected, gpu, i;
+	int i;
 	char checkin[40];
 	char checkin[40];
-	char input;
-
-	if (!opt_g_threads)
-		return;
-
-	opt_loginput = true;
-	immedok(logwin, true);
-	clear_logwin();
-retry:
-
-	for (gpu = 0; gpu < nDevs; gpu++) {
-		struct cgpu_info *cgpu = &gpus[gpu];
-		double displayed_rolling, displayed_total;
-		bool mhash_base = true;
-
-		displayed_rolling = cgpu->rolling;
-		displayed_total = cgpu->total_mhashes / cgpu_runtime(cgpu);
-		if (displayed_rolling < 1) {
-			displayed_rolling *= 1000;
-			displayed_total *= 1000;
-			mhash_base = false;
-		}
-
-		wlog("%"PRIpreprv": %.1f / %.1f %sh/s | A:%d  R:%d  HW:%d  U:%.2f/m  I:%d\n",
-			cgpu->proc_repr,
-			displayed_rolling, displayed_total, mhash_base ? "M" : "K",
-			cgpu->accepted, cgpu->rejected, cgpu->hw_errors,
-			cgpu->utility, cgpu->intensity);
+	double displayed_rolling;
+	bool mhash_base = !(cgpu->rolling < 1);
+	char logline[255];
+	strcpy(logline, ""); // In case it has no data
+	
+	tailsprintf(logline, "I:%s%d  ", (cgpu->dynamic ? "d" : ""), cgpu->intensity);
 #ifdef HAVE_ADL
 #ifdef HAVE_ADL
-		if (gpus[gpu].has_adl) {
-			int engineclock = 0, memclock = 0, activity = 0, fanspeed = 0, fanpercent = 0, powertune = 0;
-			float temp = 0, vddc = 0;
-
-			if (gpu_stats(gpu, &temp, &engineclock, &memclock, &vddc, &activity, &fanspeed, &fanpercent, &powertune)) {
-				char logline[255];
-
-				strcpy(logline, ""); // In case it has no data
-				if (temp != -1)
-					sprintf(logline, "%.1f C  ", temp);
-				if (fanspeed != -1 || fanpercent != -1) {
-					tailsprintf(logline, "F: ");
-					if (fanpercent != -1)
-						tailsprintf(logline, "%d%% ", fanpercent);
+	if (cgpu->has_adl) {
+		int engineclock = 0, memclock = 0, activity = 0, fanspeed = 0, fanpercent = 0, powertune = 0;
+		float temp = 0, vddc = 0;
+
+		if (gpu_stats(cgpu->device_id, &temp, &engineclock, &memclock, &vddc, &activity, &fanspeed, &fanpercent, &powertune)) {
+			if (fanspeed != -1 || fanpercent != -1) {
+				tailsprintf(logline, "F: ");
+				if (fanpercent != -1)
+				{
+					tailsprintf(logline, "%d%% ", fanpercent);
 					if (fanspeed != -1)
 					if (fanspeed != -1)
 						tailsprintf(logline, "(%d RPM) ", fanspeed);
 						tailsprintf(logline, "(%d RPM) ", fanspeed);
-					tailsprintf(logline, " ");
 				}
 				}
-				if (engineclock != -1)
-					tailsprintf(logline, "E: %d MHz  ", engineclock);
-				if (memclock != -1)
-					tailsprintf(logline, "M: %d MHz  ", memclock);
-				if (vddc != -1)
-					tailsprintf(logline, "V: %.3fV  ", vddc);
-				if (activity != -1)
-					tailsprintf(logline, "A: %d%%  ", activity);
-				if (powertune != -1)
-					tailsprintf(logline, "P: %d%%", powertune);
-				tailsprintf(logline, "\n");
-				_wlog(logline);
+				else
+					tailsprintf(logline, "%d RPM ", fanspeed);
+				tailsprintf(logline, " ");
 			}
 			}
+			if (engineclock != -1)
+				tailsprintf(logline, "E: %d MHz  ", engineclock);
+			if (memclock != -1)
+				tailsprintf(logline, "M: %d MHz  ", memclock);
+			if (vddc != -1)
+				tailsprintf(logline, "V: %.3fV  ", vddc);
+			if (activity != -1)
+				tailsprintf(logline, "A: %d%%  ", activity);
+			if (powertune != -1)
+				tailsprintf(logline, "P: %d%%", powertune);
 		}
 		}
+	}
 #endif
 #endif
-		wlog("Last initialised: %s\n", cgpu->init);
-		wlog("Intensity: ");
-		if (gpus[gpu].dynamic)
-			wlog("Dynamic (only one thread in use)\n");
-		else
-			wlog("%d\n", gpus[gpu].intensity);
-		for (i = 0; i < mining_threads; i++) {
-			thr = get_thread(i);
-			if (thr->cgpu != cgpu)
-				continue;
-			get_datestamp(checkin, &thr->last);
-			displayed_rolling = thr->rolling;
-			if (!mhash_base)
-				displayed_rolling *= 1000;
-			wlog("Thread %d: %.1f %sh/s %s ", i, displayed_rolling, mhash_base ? "M" : "K" , cgpu->deven != DEV_DISABLED ? "Enabled" : "Disabled");
-			switch (cgpu->status) {
-				default:
-				case LIFE_WELL:
-					wlog("ALIVE");
-					break;
-				case LIFE_SICK:
-					wlog("SICK reported in %s", checkin);
-					break;
-				case LIFE_DEAD:
-					wlog("DEAD reported in %s", checkin);
-					break;
-				case LIFE_INIT:
-				case LIFE_NOSTART:
-					wlog("Never started");
-					break;
-			}
-			if (thr->pause)
-				wlog(" paused");
-			wlog("\n");
+	
+	wlogprint("%s\n", logline);
+	
+	wlogprint("Last initialised: %s\n", cgpu->init);
+	
+	for (i = 0; i < mining_threads; i++) {
+		thr = get_thread(i);
+		if (thr->cgpu != cgpu)
+			continue;
+		
+		get_datestamp(checkin, &thr->last);
+		displayed_rolling = thr->rolling;
+		if (!mhash_base)
+			displayed_rolling *= 1000;
+		sprintf(logline, "Thread %d: %.1f %sh/s %s ", i, displayed_rolling, mhash_base ? "M" : "K" , cgpu->deven != DEV_DISABLED ? "Enabled" : "Disabled");
+		switch (cgpu->status) {
+			default:
+			case LIFE_WELL:
+				tailsprintf(logline, "ALIVE");
+				break;
+			case LIFE_SICK:
+				tailsprintf(logline, "SICK reported in %s", checkin);
+				break;
+			case LIFE_DEAD:
+				tailsprintf(logline, "DEAD reported in %s", checkin);
+				break;
+			case LIFE_INIT:
+			case LIFE_NOSTART:
+				tailsprintf(logline, "Never started");
+				break;
 		}
 		}
-		wlog("\n");
+		if (thr->pause)
+			tailsprintf(logline, " paused");
+		wlogprint("%s\n", logline);
 	}
 	}
+}
 
 
-	wlogprint("[E]nable [D]isable [I]ntensity [R]estart GPU %s\n",adl_active ? "[C]hange settings" : "");
-
-	wlogprint("Or press any other key to continue\n");
-	logwin_update();
-	input = getch();
-
-	if (nDevs == 1)
-		selected = 0;
-	else
-		selected = -1;
-	if (!strncasecmp(&input, "e", 1)) {
-		struct cgpu_info *cgpu;
+static
+void opencl_tui_wlogprint_choices(struct cgpu_info *cgpu)
+{
+	wlogprint("[I]ntensity [R]estart GPU ");
+#ifdef HAVE_ADL
+	if (cgpu->has_adl)
+		wlogprint("[C]hange settings ");
+#endif
+}
 
 
-		if (selected)
-			selected = curses_int("Select GPU to enable");
-		if (selected < 0 || selected >= nDevs) {
-			wlogprint("Invalid selection\n");
-			goto retry;
-		}
-		cgpu = &gpus[selected];
-		if (gpus[selected].deven != DEV_DISABLED) {
-			wlogprint("Device already enabled\n");
-			goto retry;
-		}
-		gpus[selected].deven = DEV_ENABLED;
-		if (cgpu->status != LIFE_WELL) {
-			wlogprint("Must restart device before enabling it");
-			goto retry;
-		}
-		proc_enable(cgpu);
-		goto retry;
-	} if (!strncasecmp(&input, "d", 1)) {
-		if (selected)
-			selected = curses_int("Select GPU to disable");
-		if (selected < 0 || selected >= nDevs) {
-			wlogprint("Invalid selection\n");
-			goto retry;
-		}
-		if (gpus[selected].deven == DEV_DISABLED) {
-			wlogprint("Device already disabled\n");
-			goto retry;
-		}
-		gpus[selected].deven = DEV_DISABLED;
-		goto retry;
-	} else if (!strncasecmp(&input, "i", 1)) {
-		int intensity;
-		char *intvar;
-
-		if (selected)
-			selected = curses_int("Select GPU to change intensity on");
-		if (selected < 0 || selected >= nDevs) {
-			wlogprint("Invalid selection\n");
-			goto retry;
-		}
-		intvar = curses_input("Set GPU scan intensity (d or " _MIN_INTENSITY_STR " -> " _MAX_INTENSITY_STR ")");
-		if (!intvar) {
-			wlogprint("Invalid input\n");
-			goto retry;
-		}
-		if (!strncasecmp(intvar, "d", 1)) {
-			wlogprint("Dynamic mode enabled on gpu %d\n", selected);
-			gpus[selected].dynamic = true;
-			pause_dynamic_threads(selected);
+static
+const char *opencl_tui_handle_choice(struct cgpu_info *cgpu, int input)
+{
+	switch (input)
+	{
+		case 'i': case 'I':
+		{
+			int intensity;
+			char *intvar;
+
+			intvar = curses_input("Set GPU scan intensity (d or " _MIN_INTENSITY_STR " -> " _MAX_INTENSITY_STR ")");
+			if (!intvar)
+				return "Invalid intensity\n";
+			if (!strncasecmp(intvar, "d", 1)) {
+				cgpu->dynamic = true;
+				pause_dynamic_threads(cgpu->device_id);
+				free(intvar);
+				return "Dynamic mode enabled\n";
+			}
+			intensity = atoi(intvar);
 			free(intvar);
 			free(intvar);
-			goto retry;
+			if (intensity < MIN_INTENSITY || intensity > MAX_INTENSITY)
+				return "Invalid intensity (out of range)\n";
+			cgpu->dynamic = false;
+			cgpu->intensity = intensity;
+			pause_dynamic_threads(cgpu->device_id);
+			return "Intensity changed\n";
 		}
 		}
-		intensity = atoi(intvar);
-		free(intvar);
-		if (intensity < MIN_INTENSITY || intensity > MAX_INTENSITY) {
-			wlogprint("Invalid selection\n");
-			goto retry;
-		}
-		gpus[selected].dynamic = false;
-		gpus[selected].intensity = intensity;
-		wlogprint("Intensity on gpu %d set to %d\n", selected, intensity);
-		pause_dynamic_threads(selected);
-		goto retry;
-	} else if (!strncasecmp(&input, "r", 1)) {
-		if (selected)
-			selected = curses_int("Select GPU to attempt to restart");
-		if (selected < 0 || selected >= nDevs) {
-			wlogprint("Invalid selection\n");
-			goto retry;
-		}
-		wlogprint("Attempting to restart threads of GPU %d\n", selected);
-		reinit_device(&gpus[selected]);
-		goto retry;
-	} else if (adl_active && (!strncasecmp(&input, "c", 1))) {
-		if (selected)
-			selected = curses_int("Select GPU to change settings on");
-		if (selected < 0 || selected >= nDevs) {
-			wlogprint("Invalid selection\n");
-			goto retry;
+		case 'r': case 'R':
+			reinit_device(cgpu);
+			return "Attempting to restart\n";
+		case 'c': case 'C':
+		{
+			char logline[256];
+			
+			clear_logwin();
+			get_statline3(logline, cgpu, true, true);
+			wattron(logwin, A_BOLD);
+			waddstr(logwin, logline);
+			wattroff(logwin, A_BOLD);
+			wlogprint("\n");
+			
+			change_gpusettings(cgpu->device_id);
+			return "";  // Force refresh
 		}
 		}
-		change_gpusettings(selected);
-		goto retry;
-	} else
-		clear_logwin();
-
-	immedok(logwin, false);
-	opt_loginput = false;
-}
-#else
-void manage_gpu(void)
-{
+	}
+	return NULL;
 }
 }
+
 #endif
 #endif
 
 
 
 
@@ -1408,7 +1337,7 @@ void *reinit_gpu(__maybe_unused void *userdata)
 #ifdef HAVE_OPENCL
 #ifdef HAVE_OPENCL
 struct device_drv opencl_api;
 struct device_drv opencl_api;
 
 
-static void opencl_detect()
+static int opencl_autodetect()
 {
 {
 #ifndef WIN32
 #ifndef WIN32
 	if (!getenv("DISPLAY")) {
 	if (!getenv("DISPLAY")) {
@@ -1419,7 +1348,7 @@ static void opencl_detect()
 
 
 	if (!load_opencl_symbols()) {
 	if (!load_opencl_symbols()) {
 		nDevs = 0;
 		nDevs = 0;
-		return;
+		return 0;
 	}
 	}
 
 
 
 
@@ -1432,7 +1361,7 @@ static void opencl_detect()
 	}
 	}
 
 
 	if (!nDevs)
 	if (!nDevs)
-		return;
+		return 0;
 
 
 	/* If opt_g_threads is not set, use default 1 thread on scrypt and
 	/* If opt_g_threads is not set, use default 1 thread on scrypt and
 	 * 2 for regular mining */
 	 * 2 for regular mining */
@@ -1478,6 +1407,16 @@ static void opencl_detect()
 
 
 	if (!opt_noadl)
 	if (!opt_noadl)
 		init_adl(nDevs);
 		init_adl(nDevs);
+	
+	return nDevs;
+}
+
+static void opencl_detect()
+{
+	RUNONCE();
+	
+	// This wrapper ensures users can specify -S opencl:noauto to disable it
+	noserial_detect(&opencl_api, opencl_autodetect);
 }
 }
 
 
 static void reinit_opencl_device(struct cgpu_info *gpu)
 static void reinit_opencl_device(struct cgpu_info *gpu)
@@ -1485,7 +1424,9 @@ static void reinit_opencl_device(struct cgpu_info *gpu)
 	tq_push(control_thr[gpur_thr_id].q, gpu);
 	tq_push(control_thr[gpur_thr_id].q, gpu);
 }
 }
 
 
-static void get_opencl_statline_before(char *buf, struct cgpu_info *gpu)
+// FIXME: Legacy (called by TUI) for side effects
+static
+bool override_opencl_statline_temp(char *buf, struct cgpu_info *gpu, __maybe_unused bool per_processor)
 {
 {
 #ifdef HAVE_SENSORS
 #ifdef HAVE_SENSORS
 	struct opencl_device_data *data = gpu->device_data;
 	struct opencl_device_data *data = gpu->device_data;
@@ -1506,33 +1447,18 @@ static void get_opencl_statline_before(char *buf, struct cgpu_info *gpu)
 				continue;
 				continue;
 			
 			
 			gpu->temp = val;
 			gpu->temp = val;
-			tailsprintf(buf, "%5.1fC         | ", val);
-			return;
+			return false;
 		}
 		}
 	}
 	}
 #endif
 #endif
 #ifdef HAVE_ADL
 #ifdef HAVE_ADL
 	if (gpu->has_adl) {
 	if (gpu->has_adl) {
 		int gpuid = gpu->device_id;
 		int gpuid = gpu->device_id;
-		float gt = gpu_temp(gpuid);
-		int gf = gpu_fanspeed(gpuid);
-		int gp;
-
-		if (gt != -1)
-			tailsprintf(buf, "%5.1fC ", gt);
-		else
-			tailsprintf(buf, "       ");
-		if (gf != -1)
-			tailsprintf(buf, "%4dRPM ", gf);
-		else if ((gp = gpu_fanpercent(gpuid)) != -1)
-			tailsprintf(buf, "%3d%%    ", gp);
-		else
-			tailsprintf(buf, "        ");
-		tailsprintf(buf, "| ");
+		gpu_temp(gpuid);
+		gpu_fanspeed(gpuid);
 	}
 	}
-	else
 #endif
 #endif
-		tailsprintf(buf, "               | ");
+	return false;
 }
 }
 
 
 static struct api_data*
 static struct api_data*
@@ -1835,7 +1761,12 @@ struct device_drv opencl_api = {
 	.name = "OCL",
 	.name = "OCL",
 	.drv_detect = opencl_detect,
 	.drv_detect = opencl_detect,
 	.reinit_device = reinit_opencl_device,
 	.reinit_device = reinit_opencl_device,
-	.get_statline_before = get_opencl_statline_before,
+	.override_statline_temp = override_opencl_statline_temp,
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = opencl_wlogprint_status,
+	.proc_tui_wlogprint_choices = opencl_tui_wlogprint_choices,
+	.proc_tui_handle_choice = opencl_tui_handle_choice,
+#endif
 	.get_api_extra_device_status = get_opencl_api_extra_device_status,
 	.get_api_extra_device_status = get_opencl_api_extra_device_status,
 	.thread_prepare = opencl_thread_prepare,
 	.thread_prepare = opencl_thread_prepare,
 	.thread_init = opencl_thread_init,
 	.thread_init = opencl_thread_init,

+ 14 - 54
driver-x6500.c

@@ -124,6 +124,9 @@ uint32_t x6500_get_register(struct jtag_port *jp, uint8_t addr)
 
 
 static bool x6500_foundusb(libusb_device *dev, const char *product, const char *serial)
 static bool x6500_foundusb(libusb_device *dev, const char *product, const char *serial)
 {
 {
+	if (bfg_claim_libusb(&x6500_api, true, dev))
+		return false;
+	
 	struct cgpu_info *x6500;
 	struct cgpu_info *x6500;
 	x6500 = calloc(1, sizeof(*x6500));
 	x6500 = calloc(1, sizeof(*x6500));
 	x6500->drv = &x6500_api;
 	x6500->drv = &x6500_api;
@@ -135,6 +138,7 @@ static bool x6500_foundusb(libusb_device *dev, const char *product, const char *
 	x6500->name = strdup(product);
 	x6500->name = strdup(product);
 	x6500->cutofftemp = 85;
 	x6500->cutofftemp = 85;
 	x6500->device_data = dev;
 	x6500->device_data = dev;
+	cgpu_copy_libusb_strings(x6500, dev);
 
 
 	return add_cgpu(x6500);
 	return add_cgpu(x6500);
 }
 }
@@ -224,7 +228,7 @@ x6500_fpga_upload_bitstream(struct cgpu_info *x6500, struct jtag_port *jp1)
 
 
 	applog(LOG_WARNING, "%s: Programming %s...",
 	applog(LOG_WARNING, "%s: Programming %s...",
 	       x6500->dev_repr, x6500->device_path);
 	       x6500->dev_repr, x6500->device_path);
-	x6500->status = LIFE_INIT;
+	x6500->status = LIFE_INIT2;
 	
 	
 	// "Magic" jtag_port configured to access both FPGAs concurrently
 	// "Magic" jtag_port configured to access both FPGAs concurrently
 	struct jtag_port jpt = {
 	struct jtag_port jpt = {
@@ -341,6 +345,7 @@ static bool x6500_thread_init(struct thr_info *thr)
 	notifier_init(thr->mutex_request);
 	notifier_init(thr->mutex_request);
 	pthread_cond_init(&x6500->device_cond, NULL);
 	pthread_cond_init(&x6500->device_cond, NULL);
 	
 	
+	// This works because x6500_thread_init is only called for the first processor now that they're all using the same thread
 	for ( ; x6500; x6500 = x6500->next_proc)
 	for ( ; x6500; x6500 = x6500->next_proc)
 	{
 	{
 		thr = x6500->thr[0];
 		thr = x6500->thr[0];
@@ -360,6 +365,7 @@ static bool x6500_thread_init(struct thr_info *thr)
 	jp->a = x6500->device_data;
 	jp->a = x6500->device_data;
 	x6500_jtag_set(jp, pinoffset);
 	x6500_jtag_set(jp, pinoffset);
 	thr->cgpu_data = fpga;
 	thr->cgpu_data = fpga;
+	x6500->status = LIFE_INIT2;
 	
 	
 	if (!jtag_reset(jp)) {
 	if (!jtag_reset(jp)) {
 		applog(LOG_ERR, "%s: JTAG reset failed",
 		applog(LOG_ERR, "%s: JTAG reset failed",
@@ -389,7 +395,7 @@ static bool x6500_thread_init(struct thr_info *thr)
 		       x6500->proc_repr);
 		       x6500->proc_repr);
 		if (!x6500_fpga_upload_bitstream(x6500, jp))
 		if (!x6500_fpga_upload_bitstream(x6500, jp))
 			return false;
 			return false;
-	} else if (opt_force_dev_init && x6500->status == LIFE_INIT) {
+	} else if (opt_force_dev_init && x6500 == x6500->device) {
 		applog(LOG_DEBUG, "%"PRIprepr": FPGA is already programmed, but --force-dev-init is set",
 		applog(LOG_DEBUG, "%"PRIprepr": FPGA is already programmed, but --force-dev-init is set",
 		       x6500->proc_repr);
 		       x6500->proc_repr);
 		if (!x6500_fpga_upload_bitstream(x6500, jp))
 		if (!x6500_fpga_upload_bitstream(x6500, jp))
@@ -557,57 +563,16 @@ static bool x6500_get_stats(struct cgpu_info *x6500)
 }
 }
 
 
 static
 static
-bool get_x6500_upload_percent(char *buf, struct cgpu_info *x6500)
+bool get_x6500_upload_percent(char *buf, struct cgpu_info *x6500, __maybe_unused bool per_processor)
 {
 {
-	char info[18] = "               | ";
-
 	unsigned char pdone = *((unsigned char*)x6500->device_data - 1);
 	unsigned char pdone = *((unsigned char*)x6500->device_data - 1);
 	if (pdone != 101) {
 	if (pdone != 101) {
-		sprintf(&info[1], "%3d%%", pdone);
-		info[5] = ' ';
-		strcat(buf, info);
+		tailsprintf(buf, "%3d%% ", pdone);
 		return true;
 		return true;
 	}
 	}
 	return false;
 	return false;
 }
 }
 
 
-static
-void get_x6500_statline_before(char *buf, struct cgpu_info *x6500)
-{
-	if (get_x6500_upload_percent(buf, x6500))
-		return;
-
-	char info[18] = "               | ";
-	struct x6500_fpga_data *fpga = x6500->thr[0]->cgpu_data;
-
-	if (fpga->temp) {
-		sprintf(&info[1], "%.1fC", fpga->temp);
-		info[strlen(info)] = ' ';
-		strcat(buf, info);
-		return;
-	}
-	strcat(buf, "               | ");
-}
-
-static
-void get_x6500_dev_statline_before(char *buf, struct cgpu_info *x6500)
-{
-	if (get_x6500_upload_percent(buf, x6500))
-		return;
-
-	char info[18] = "               | ";
-	struct x6500_fpga_data *fpga0 = x6500->thr[0]->cgpu_data;
-	struct x6500_fpga_data *fpga1 = x6500->next_proc->thr[0]->cgpu_data;
-
-	if (x6500->temp) {
-		sprintf(&info[1], "%.1fC/%.1fC", fpga0->temp, fpga1->temp);
-		info[strlen(info)] = ' ';
-		strcat(buf, info);
-		return;
-	}
-	strcat(buf, "               | ");
-}
-
 static struct api_data*
 static struct api_data*
 get_x6500_api_extra_device_status(struct cgpu_info *x6500)
 get_x6500_api_extra_device_status(struct cgpu_info *x6500)
 {
 {
@@ -682,10 +647,10 @@ void x6500_job_start(struct thr_info *thr)
 	mt_job_transition(thr);
 	mt_job_transition(thr);
 	
 	
 	if (opt_debug) {
 	if (opt_debug) {
-		char *xdata = bin2hex(thr->work->data, 80);
+		char xdata[161];
+		bin2hex(xdata, thr->work->data, 80);
 		applog(LOG_DEBUG, "%"PRIprepr": Started work: %s",
 		applog(LOG_DEBUG, "%"PRIprepr": Started work: %s",
 		       x6500->proc_repr, xdata);
 		       x6500->proc_repr, xdata);
-		free(xdata);
 	}
 	}
 
 
 	uint32_t usecs = 0x80000000 / fpga->dclk.freqM;
 	uint32_t usecs = 0x80000000 / fpga->dclk.freqM;
@@ -745,11 +710,7 @@ int64_t x6500_process_results(struct thr_info *thr, struct work *work)
 				       x6500->proc_repr,
 				       x6500->proc_repr,
 				       (unsigned long)nonce);
 				       (unsigned long)nonce);
 			} else {
 			} else {
-				applog(LOG_DEBUG, "%"PRIprepr": Nonce with H not zero  : %08lx",
-				       x6500->proc_repr,
-				       (unsigned long)nonce);
-				++hw_errors;
-				++x6500->hw_errors;
+				inc_hw_errors(thr, work, nonce);
 
 
 				dclk_gotNonces(&fpga->dclk);
 				dclk_gotNonces(&fpga->dclk);
 				dclk_errorCount(&fpga->dclk, 1.);
 				dclk_errorCount(&fpga->dclk, 1.);
@@ -786,11 +747,10 @@ struct device_drv x6500_api = {
 	.dname = "x6500",
 	.dname = "x6500",
 	.name = "XBS",
 	.name = "XBS",
 	.drv_detect = x6500_detect,
 	.drv_detect = x6500_detect,
-	.get_dev_statline_before = get_x6500_dev_statline_before,
 	.thread_prepare = x6500_prepare,
 	.thread_prepare = x6500_prepare,
 	.thread_init = x6500_thread_init,
 	.thread_init = x6500_thread_init,
 	.get_stats = x6500_get_stats,
 	.get_stats = x6500_get_stats,
-	.get_statline_before = get_x6500_statline_before,
+	.override_statline_temp = get_x6500_upload_percent,
 	.get_api_extra_device_status = get_x6500_api_extra_device_status,
 	.get_api_extra_device_status = get_x6500_api_extra_device_status,
 	.poll = x6500_fpga_poll,
 	.poll = x6500_fpga_poll,
 	.minerloop = minerloop_async,
 	.minerloop = minerloop_async,

+ 7 - 16
driver-ztex.c

@@ -61,6 +61,9 @@ static struct cgpu_info *ztex_setup(struct libztex_device *dev, int fpgacount)
 	ztex->device_ztex = dev;
 	ztex->device_ztex = dev;
 	ztex->procs = fpgacount;
 	ztex->procs = fpgacount;
 	ztex->threads = fpgacount;
 	ztex->threads = fpgacount;
+	ztex->dev_manufacturer = dev->dev_manufacturer;
+	ztex->dev_product = dev->dev_product;
+	ztex->dev_serial = (char*)&dev->snString[0];
 	add_cgpu(ztex);
 	add_cgpu(ztex);
 	strcpy(ztex->device_ztex->repr, ztex->dev_repr);
 	strcpy(ztex->device_ztex->repr, ztex->dev_repr);
 	ztex->name = fpganame;
 	ztex->name = fpganame;
@@ -85,6 +88,8 @@ static int ztex_autodetect(void)
 
 
 	for (i = 0; i < cnt; i++) {
 	for (i = 0; i < cnt; i++) {
 		ztex_master = ztex_devices[i]->dev;
 		ztex_master = ztex_devices[i]->dev;
+		if (bfg_claim_usb(&ztex_drv, true, ztex_master->usbbus, ztex_master->usbaddress))
+			return false;
 		ztex_master->root = ztex_master;
 		ztex_master->root = ztex_master;
 		fpgacount = libztex_numberOfFpgas(ztex_master);
 		fpgacount = libztex_numberOfFpgas(ztex_master);
 		ztex_master->handles = fpgacount;
 		ztex_master->handles = fpgacount;
@@ -266,8 +271,7 @@ static int64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 				if (count > 2)
 				if (count > 2)
 					dclk_errorCount(&ztex->dclk, 1.0 / ztex->numNonces);
 					dclk_errorCount(&ztex->dclk, 1.0 / ztex->numNonces);
 
 
-				thr->cgpu->hw_errors++;
-				++hw_errors;
+				inc_hw_errors_only(thr);
 			}
 			}
 
 
 			for (j=0; j<=ztex->extraSolutions; j++) {
 			for (j=0; j<=ztex->extraSolutions; j++) {
@@ -319,19 +323,6 @@ static int64_t ztex_scanhash(struct thr_info *thr, struct work *work,
 	return noncecnt;
 	return noncecnt;
 }
 }
 
 
-static void ztex_statline_before(char *buf, struct cgpu_info *cgpu)
-{
-	char before[] = "               ";
-	if (cgpu->device_ztex) {
-		const char *snString = (char*)cgpu->device_ztex->snString;
-		size_t snStringLen = strlen(snString);
-		if (snStringLen > 14)
-			snStringLen = 14;
-		memcpy(before, snString, snStringLen);
-	}
-	tailsprintf(buf, "%s| ", &before[0]);
-}
-
 static struct api_data*
 static struct api_data*
 get_ztex_drv_extra_device_status(struct cgpu_info *ztex)
 get_ztex_drv_extra_device_status(struct cgpu_info *ztex)
 {
 {
@@ -375,6 +366,7 @@ static bool ztex_prepare(struct thr_info *thr)
 	ztex_releaseFpga(ztex);
 	ztex_releaseFpga(ztex);
 	notifier_init(thr->work_restart_notifier);
 	notifier_init(thr->work_restart_notifier);
 	applog(LOG_DEBUG, "%"PRIpreprv": prepare", cgpu->proc_repr);
 	applog(LOG_DEBUG, "%"PRIpreprv": prepare", cgpu->proc_repr);
+	cgpu->status = LIFE_INIT2;
 	return true;
 	return true;
 }
 }
 
 
@@ -407,7 +399,6 @@ struct device_drv ztex_drv = {
 	.dname = "ztex",
 	.dname = "ztex",
 	.name = "ZTX",
 	.name = "ZTX",
 	.drv_detect = ztex_detect,
 	.drv_detect = ztex_detect,
-	.get_statline_before = ztex_statline_before,
 	.get_api_extra_device_status = get_ztex_drv_extra_device_status,
 	.get_api_extra_device_status = get_ztex_drv_extra_device_status,
 	.thread_init = ztex_prepare,
 	.thread_init = ztex_prepare,
 	.scanhash = ztex_scanhash,
 	.scanhash = ztex_scanhash,

+ 1 - 2
findnonce.c

@@ -156,8 +156,7 @@ static void *postcalc_hash(void *userdata)
 	if (unlikely(pcd->res[found] & ~found)) {
 	if (unlikely(pcd->res[found] & ~found)) {
 		applog(LOG_WARNING, "%"PRIpreprv": invalid nonce count - HW error",
 		applog(LOG_WARNING, "%"PRIpreprv": invalid nonce count - HW error",
 				thr->cgpu->proc_repr);
 				thr->cgpu->proc_repr);
-		hw_errors++;
-		thr->cgpu->hw_errors++;
+		inc_hw_errors_only(thr);
 		pcd->res[found] &= found;
 		pcd->res[found] &= found;
 	}
 	}
 
 

+ 289 - 125
fpgautils.c

@@ -16,6 +16,7 @@
 #include <winsock2.h>
 #include <winsock2.h>
 #endif
 #endif
 
 
+#include <ctype.h>
 #include <stdarg.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <stdlib.h>
@@ -23,6 +24,10 @@
 #include <dirent.h>
 #include <dirent.h>
 #include <string.h>
 #include <string.h>
 
 
+#ifdef HAVE_LIBUSB
+#include <libusb.h>
+#endif
+
 #include "miner.h"
 #include "miner.h"
 
 
 #ifndef WIN32
 #ifndef WIN32
@@ -100,7 +105,62 @@ bool search_needles(const char *haystack, va_list needles)
 
 
 #define SEARCH_NEEDLES(haystack)  search_needles(haystack, needles)
 #define SEARCH_NEEDLES(haystack)  search_needles(haystack, needles)
 
 
+static
+int _detectone_wrap(const detectone_func_t detectone, const char * const param, const char *fname)
+{
+	if (bfg_claim_serial(NULL, false, param))
+	{
+		applog(LOG_DEBUG, "%s: %s is already claimed, skipping probe", fname, param);
+		return 0;
+	}
+	return detectone(param);
+}
+#define detectone(param)  _detectone_wrap(detectone, param, __func__)
+
+struct detectone_meta_info_t detectone_meta_info;
+
+static
+void clear_detectone_meta_info(void)
+{
+	detectone_meta_info = (struct detectone_meta_info_t){
+		.manufacturer = NULL,
+	};
+}
+
 #ifdef HAVE_LIBUDEV
 #ifdef HAVE_LIBUDEV
+static
+void _decode_udev_enc(char *o, const char *s)
+{
+	while(s[0])
+	{
+		if (s[0] == '\\' && s[1] == 'x' && s[2] && s[3])
+		{
+			hex2bin((void*)(o++), &s[2], 1);
+			s += 4;
+		}
+		else
+			(o++)[0] = (s++)[0];
+	}
+	o[0] = '\0';
+}
+
+static
+char *_decode_udev_enc_dup(const char *s)
+{
+	if (!s)
+		return NULL;
+	
+	char *o = malloc(strlen(s));
+	if (!o)
+	{
+		applog(LOG_ERR, "Failed to malloc in _decode_udev_enc_dup");
+		return NULL;
+	}
+	
+	_decode_udev_enc(o, s);
+	return o;
+}
+
 static
 static
 int _serial_autodetect_udev(detectone_func_t detectone, va_list needles)
 int _serial_autodetect_udev(detectone_func_t detectone, va_list needles)
 {
 {
@@ -126,14 +186,24 @@ int _serial_autodetect_udev(detectone_func_t detectone, va_list needles)
 			continue;
 			continue;
 		}
 		}
 
 
+		detectone_meta_info = (struct detectone_meta_info_t){
+			.manufacturer = _decode_udev_enc_dup(udev_device_get_property_value(device, "ID_VENDOR_ENC")),
+			.product = _decode_udev_enc_dup(udev_device_get_property_value(device, "ID_MODEL_ENC")),
+			.serial = _decode_udev_enc_dup(udev_device_get_property_value(device, "ID_SERIAL_SHORT")),
+		};
+		
 		const char *devpath = udev_device_get_devnode(device);
 		const char *devpath = udev_device_get_devnode(device);
 		if (devpath && detectone(devpath))
 		if (devpath && detectone(devpath))
 			++found;
 			++found;
 
 
+		free((void*)detectone_meta_info.manufacturer);
+		free((void*)detectone_meta_info.product);
+		free((void*)detectone_meta_info.serial);
 		udev_device_unref(device);
 		udev_device_unref(device);
 	}
 	}
 	udev_enumerate_unref(enumerate);
 	udev_enumerate_unref(enumerate);
 	udev_unref(udev);
 	udev_unref(udev);
+	clear_detectone_meta_info();
 
 
 	return found;
 	return found;
 }
 }
@@ -152,6 +222,9 @@ int _serial_autodetect_devserial(detectone_func_t detectone, va_list needles)
 	char *devfile = devpath + sizeof(udevdir);
 	char *devfile = devpath + sizeof(udevdir);
 	char found = 0;
 	char found = 0;
 
 
+	// No way to split this out of the filename reliably
+	clear_detectone_meta_info();
+	
 	D = opendir(udevdir);
 	D = opendir(udevdir);
 	if (!D)
 	if (!D)
 		return 0;
 		return 0;
@@ -174,16 +247,40 @@ int _serial_autodetect_devserial(detectone_func_t detectone, va_list needles)
 #endif
 #endif
 
 
 #ifndef WIN32
 #ifndef WIN32
+static
+char *_sysfs_do_read(char *buf, size_t bufsz, const char *devpath, char *devfile, const char *append)
+{
+	FILE *F;
+	
+	strcpy(devfile, append);
+	F = fopen(devpath, "r");
+	if (F)
+	{
+		if (fgets(buf, bufsz, F))
+		{
+			size_t L = strlen(buf);
+			while (isspace(buf[--L]))
+				buf[L] = '\0';
+		}
+		else
+			buf[0] = '\0';
+		fclose(F);
+	}
+	else
+		buf[0] = '\0';
+	
+	return buf[0] ? buf : NULL;
+}
+
 static
 static
 int _serial_autodetect_sysfs(detectone_func_t detectone, va_list needles)
 int _serial_autodetect_sysfs(detectone_func_t detectone, va_list needles)
 {
 {
 	DIR *D, *DS, *DT;
 	DIR *D, *DS, *DT;
-	FILE *F;
 	struct dirent *de;
 	struct dirent *de;
 	const char devroot[] = "/sys/bus/usb/devices";
 	const char devroot[] = "/sys/bus/usb/devices";
 	const size_t devrootlen = sizeof(devroot) - 1;
 	const size_t devrootlen = sizeof(devroot) - 1;
 	char devpath[sizeof(devroot) + (NAME_MAX * 3)];
 	char devpath[sizeof(devroot) + (NAME_MAX * 3)];
-	char buf[0x100];
+	char ttybuf[0x10], manuf[0x40], prod[0x40], serial[0x40];
 	char *devfile, *upfile;
 	char *devfile, *upfile;
 	char found = 0;
 	char found = 0;
 	size_t len, len2;
 	size_t len, len2;
@@ -199,12 +296,11 @@ int _serial_autodetect_sysfs(detectone_func_t detectone, va_list needles)
 		upfile = &devpath[devrootlen + 1];
 		upfile = &devpath[devrootlen + 1];
 		memcpy(upfile, de->d_name, len);
 		memcpy(upfile, de->d_name, len);
 		devfile = upfile + len;
 		devfile = upfile + len;
-		strcpy(devfile, "/product");
-		F = fopen(devpath, "r");
-		if (!(F && fgets(buf, sizeof(buf), F)))
+		
+		if (!_sysfs_do_read(prod, sizeof(prod), devpath, devfile, "/product"))
 			continue;
 			continue;
 		
 		
-		if (!SEARCH_NEEDLES(buf))
+		if (!SEARCH_NEEDLES(prod))
 			continue;
 			continue;
 		
 		
 		devfile[0] = '\0';
 		devfile[0] = '\0';
@@ -214,7 +310,7 @@ int _serial_autodetect_sysfs(detectone_func_t detectone, va_list needles)
 		devfile[0] = '/';
 		devfile[0] = '/';
 		++devfile;
 		++devfile;
 		
 		
-		memcpy(buf, "/dev/", 5);
+		memcpy(ttybuf, "/dev/", 5);
 		
 		
 		while ( (de = readdir(DS)) )
 		while ( (de = readdir(DS)) )
 		{
 		{
@@ -235,8 +331,15 @@ int _serial_autodetect_sysfs(detectone_func_t detectone, va_list needles)
 				if (strncmp(&de->d_name[3], "USB", 3) && strncmp(&de->d_name[3], "ACM", 3))
 				if (strncmp(&de->d_name[3], "USB", 3) && strncmp(&de->d_name[3], "ACM", 3))
 					continue;
 					continue;
 				
 				
-				strcpy(&buf[5], de->d_name);
-				if (detectone(buf))
+				
+				detectone_meta_info = (struct detectone_meta_info_t){
+					.manufacturer = _sysfs_do_read(manuf, sizeof(manuf), devpath, devfile, "/manufacturer"),
+					.product = prod,
+					.serial = _sysfs_do_read(serial, sizeof(serial), devpath, devfile, "/serial"),
+				};
+				
+				strcpy(&ttybuf[5], de->d_name);
+				if (detectone(ttybuf))
 					++found;
 					++found;
 			}
 			}
 			closedir(DT);
 			closedir(DT);
@@ -244,6 +347,7 @@ int _serial_autodetect_sysfs(detectone_func_t detectone, va_list needles)
 		closedir(DS);
 		closedir(DS);
 	}
 	}
 	closedir(D);
 	closedir(D);
+	clear_detectone_meta_info();
 	
 	
 	return found;
 	return found;
 }
 }
@@ -259,6 +363,16 @@ int _serial_autodetect_sysfs(detectone_func_t detectone, va_list needles)
 	}  \
 	}  \
 } while(0)
 } while(0)
 
 
+#ifdef UNTESTED_FTDI_DETECTONE_META_INFO
+static
+char *_ftdi_get_string(char *buf, int i, DWORD flags)
+{
+	if (FT_OK != FT_ListDevices((PVOID)i, buf, FT_LIST_BY_INDEX | flags))
+		return NULL;
+	return buf[0] ? buf : NULL;
+}
+#endif
+
 static
 static
 int _serial_autodetect_ftdi(detectone_func_t detectone, va_list needles)
 int _serial_autodetect_ftdi(detectone_func_t detectone, va_list needles)
 {
 {
@@ -266,6 +380,9 @@ int _serial_autodetect_ftdi(detectone_func_t detectone, va_list needles)
 	char *devpathnum = &devpath[7];
 	char *devpathnum = &devpath[7];
 	char **bufptrs;
 	char **bufptrs;
 	char *buf;
 	char *buf;
+#ifdef UNTESTED_FTDI_DETECTONE_META_INFO
+	char manuf[64], serial[64];
+#endif
 	int found = 0;
 	int found = 0;
 	DWORD i;
 	DWORD i;
 
 
@@ -300,6 +417,7 @@ int _serial_autodetect_ftdi(detectone_func_t detectone, va_list needles)
 		goto out;
 		goto out;
 	}
 	}
 	
 	
+	clear_detectone_meta_info();
 	for (i = numDevs; i > 0; ) {
 	for (i = numDevs; i > 0; ) {
 		--i;
 		--i;
 		bufptrs[i][64] = '\0';
 		bufptrs[i][64] = '\0';
@@ -317,6 +435,13 @@ int _serial_autodetect_ftdi(detectone_func_t detectone, va_list needles)
 			continue;
 			continue;
 		
 		
 		applog(LOG_ERR, "FT_GetComPortNumber(%p (%ld), %ld)", ftHandle, (long)i, (long)lComPortNumber);
 		applog(LOG_ERR, "FT_GetComPortNumber(%p (%ld), %ld)", ftHandle, (long)i, (long)lComPortNumber);
+#ifdef UNTESTED_FTDI_DETECTONE_META_INFO
+		detectone_meta_info = (struct detectone_meta_info_t){
+			.product = bufptrs[i],
+			.serial = _ftdi_get_string(serial, i, FT_OPEN_BY_SERIAL_NUMBER),
+		};
+#endif
+		
 		sprintf(devpathnum, "%d", (int)lComPortNumber);
 		sprintf(devpathnum, "%d", (int)lComPortNumber);
 		
 		
 		if (detectone(devpath))
 		if (detectone(devpath))
@@ -324,6 +449,7 @@ int _serial_autodetect_ftdi(detectone_func_t detectone, va_list needles)
 	}
 	}
 
 
 out:
 out:
+	clear_detectone_meta_info();
 	dlclose(dll);
 	dlclose(dll);
 	return found;
 	return found;
 }
 }
@@ -331,6 +457,8 @@ out:
 #	define _serial_autodetect_ftdi(...)  (0)
 #	define _serial_autodetect_ftdi(...)  (0)
 #endif
 #endif
 
 
+#undef detectone
+
 int _serial_autodetect(detectone_func_t detectone, ...)
 int _serial_autodetect(detectone_func_t detectone, ...)
 {
 {
 	int rv;
 	int rv;
@@ -347,19 +475,18 @@ int _serial_autodetect(detectone_func_t detectone, ...)
 	return rv;
 	return rv;
 }
 }
 
 
-struct device_drv *serial_claim(const char *devpath, struct device_drv *api);
-
 int _serial_detect(struct device_drv *api, detectone_func_t detectone, autoscan_func_t autoscan, int flags)
 int _serial_detect(struct device_drv *api, detectone_func_t detectone, autoscan_func_t autoscan, int flags)
 {
 {
 	struct string_elist *iter, *tmp;
 	struct string_elist *iter, *tmp;
 	const char *dev, *colon;
 	const char *dev, *colon;
-	bool inhibitauto = false;
+	bool inhibitauto = flags & 4;
 	char found = 0;
 	char found = 0;
 	bool forceauto = flags & 1;
 	bool forceauto = flags & 1;
 	bool hasname;
 	bool hasname;
 	size_t namel = strlen(api->name);
 	size_t namel = strlen(api->name);
 	size_t dnamel = strlen(api->dname);
 	size_t dnamel = strlen(api->dname);
 
 
+	clear_detectone_meta_info();
 	DL_FOREACH_SAFE(scan_devices, iter, tmp) {
 	DL_FOREACH_SAFE(scan_devices, iter, tmp) {
 		dev = iter->string;
 		dev = iter->string;
 		if ((colon = strchr(dev, ':')) && colon[1] != '\0') {
 		if ((colon = strchr(dev, ':')) && colon[1] != '\0') {
@@ -404,11 +531,27 @@ int _serial_detect(struct device_drv *api, detectone_func_t detectone, autoscan_
 	return found;
 	return found;
 }
 }
 
 
+enum bfg_device_bus {
+	BDB_SERIAL,
+	BDB_USB,
+};
+
+// TODO: claim USB side of USB-Serial devices
+typedef
+struct my_dev_t {
+	enum bfg_device_bus bus;
+	union {
+		struct {
+			uint8_t usbbus;
+			uint8_t usbaddr;
+		};
 #ifndef WIN32
 #ifndef WIN32
-typedef dev_t my_dev_t;
+		dev_t dev;
 #else
 #else
-typedef int my_dev_t;
+		int com;
 #endif
 #endif
+	};
+} my_dev_t;
 
 
 struct _device_claim {
 struct _device_claim {
 	struct device_drv *drv;
 	struct device_drv *drv;
@@ -416,43 +559,100 @@ struct _device_claim {
 	UT_hash_handle hh;
 	UT_hash_handle hh;
 };
 };
 
 
-struct device_drv *serial_claim(const char *devpath, struct device_drv *api)
+static
+struct device_drv *bfg_claim_any(struct device_drv * const api, const char * const verbose, const my_dev_t * const dev)
 {
 {
 	static struct _device_claim *claims = NULL;
 	static struct _device_claim *claims = NULL;
 	struct _device_claim *c;
 	struct _device_claim *c;
-	my_dev_t dev;
+	
+	HASH_FIND(hh, claims, dev, sizeof(*dev), c);
+	if (c)
+	{
+		if (verbose)
+			applog(LOG_DEBUG, "%s device %s already claimed by other driver: %s",
+			       api->dname, verbose, c->drv->dname);
+		return c->drv;
+	}
+	
+	if (!api)
+		return NULL;
+	
+	c = malloc(sizeof(*c));
+	c->dev = *dev;
+	c->drv = api;
+	HASH_ADD(hh, claims, dev, sizeof(*dev), c);
+	return NULL;
+}
 
 
+struct device_drv *bfg_claim_serial(struct device_drv * const api, const bool verbose, const char * const devpath)
+{
+	my_dev_t dev;
+	
+	memset(&dev, 0, sizeof(dev));
+	dev.bus = BDB_SERIAL;
 #ifndef WIN32
 #ifndef WIN32
 	{
 	{
 		struct stat my_stat;
 		struct stat my_stat;
 		if (stat(devpath, &my_stat))
 		if (stat(devpath, &my_stat))
 			return NULL;
 			return NULL;
-		dev = my_stat.st_rdev;
+		dev.dev = my_stat.st_rdev;
 	}
 	}
 #else
 #else
 	{
 	{
 		char *p = strstr(devpath, "COM"), *p2;
 		char *p = strstr(devpath, "COM"), *p2;
 		if (!p)
 		if (!p)
 			return NULL;
 			return NULL;
-		dev = strtol(&p[3], &p2, 10);
+		dev.com = strtol(&p[3], &p2, 10);
 		if (p2 == p)
 		if (p2 == p)
 			return NULL;
 			return NULL;
 	}
 	}
 #endif
 #endif
+	
+	return bfg_claim_any(api, (verbose ? devpath : NULL), &dev);
+}
 
 
-	HASH_FIND(hh, claims, &dev, sizeof(dev), c);
-	if (c)
-		return c->drv;
-
-	if (!api)
-		return NULL;
+struct device_drv *bfg_claim_usb(struct device_drv * const api, const bool verbose, const uint8_t usbbus, const uint8_t usbaddr)
+{
+	my_dev_t dev;
+	char *desc = NULL;
+	
+	// We should be able to just initialize a const my_dev_t for this, but Xcode's clang is broken
+	// Affected: Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn) AKA Xcode 4.6.3
+	// Works with const: GCC 4.6.3, LLVM 3.1
+	memset(&dev, 0, sizeof(dev));
+	dev.bus = BDB_USB;
+	dev.usbbus = usbbus;
+	dev.usbaddr = usbaddr;
+	
+	if (verbose)
+	{
+		desc = alloca(3 + 1 + 3 + 1);
+		sprintf(desc, "%03u:%03u", (unsigned)usbbus, (unsigned)usbaddr);
+	}
+	
+	return bfg_claim_any(api, desc, &dev);
+}
 
 
-	c = malloc(sizeof(*c));
-	c->dev = dev;
-	c->drv = api;
-	HASH_ADD(hh, claims, dev, sizeof(dev), c);
-	return NULL;
+#ifdef HAVE_LIBUSB
+void cgpu_copy_libusb_strings(struct cgpu_info *cgpu, libusb_device *usb)
+{
+	unsigned char buf[0x20];
+	libusb_device_handle *h;
+	struct libusb_device_descriptor desc;
+	
+	if (LIBUSB_SUCCESS != libusb_open(usb, &h))
+		return;
+	if (libusb_get_device_descriptor(usb, &desc))
+		return;
+	
+	if ((!cgpu->dev_manufacturer) && libusb_get_string_descriptor_ascii(h, desc.iManufacturer, buf, sizeof(buf)) >= 0)
+		cgpu->dev_manufacturer = strdup((void *)buf);
+	if ((!cgpu->dev_product) && libusb_get_string_descriptor_ascii(h, desc.iProduct, buf, sizeof(buf)) >= 0)
+		cgpu->dev_product = strdup((void *)buf);
+	if ((!cgpu->dev_serial) && libusb_get_string_descriptor_ascii(h, desc.iSerialNumber, buf, sizeof(buf)) >= 0)
+		cgpu->dev_serial = strdup((void *)buf);
 }
 }
+#endif
 
 
 // This code is purely for debugging but is very useful for that
 // This code is purely for debugging but is very useful for that
 // It also took quite a bit of effort so I left it in
 // It also took quite a bit of effort so I left it in
@@ -468,68 +668,12 @@ struct device_drv *serial_claim(const char *devpath, struct device_drv *api)
 int tiospeed(speed_t speed)
 int tiospeed(speed_t speed)
 {
 {
 	switch (speed) {
 	switch (speed) {
-	case B0:
-		return 0;
-	case B50:
-		return 50;
-	case B75:
-		return 75;
-	case B110:
-		return 110;
-	case B134:
-		return 134;
-	case B150:
-		return 150;
-	case B200:
-		return 200;
-	case B300:
-		return 300;
-	case B600:
-		return 600;
-	case B1200:
-		return 1200;
-	case B1800:
-		return 1800;
-	case B2400:
-		return 2400;
-	case B4800:
-		return 4800;
-	case B9600:
-		return 9600;
-	case B19200:
-		return 19200;
-	case B38400:
-		return 38400;
-	case B57600:
-		return 57600;
-	case B115200:
-		return 115200;
-	case B230400:
-		return 230400;
-	case B460800:
-		return 460800;
-	case B500000:
-		return 500000;
-	case B576000:
-		return 576000;
-	case B921600:
-		return 921600;
-	case B1000000:
-		return 1000000;
-	case B1152000:
-		return 1152000;
-	case B1500000:
-		return 1500000;
-	case B2000000:
-		return 2000000;
-	case B2500000:
-		return 2500000;
-	case B3000000:
-		return 3000000;
-	case B3500000:
-		return 3500000;
-	case B4000000:
-		return 4000000;
+#define IOSPEED(baud)  \
+		case B ## baud:  \
+			return baud;  \
+// END
+#include "iospeeds.h"
+#undef IOSPEED
 	default:
 	default:
 		return -1;
 		return -1;
 	}
 	}
@@ -619,8 +763,37 @@ void termios_debug(const char *devpath, struct termios *my_termios, const char *
 #endif
 #endif
 			);
 			);
 }
 }
-#endif
-#endif
+#endif  /* TERMIOS_DEBUG */
+
+speed_t tiospeed_t(int baud)
+{
+	switch (baud) {
+#define IOSPEED(baud)  \
+		case baud:  \
+			return B ## baud;  \
+// END
+#include "iospeeds.h"
+#undef IOSPEED
+	default:
+		return B0;
+	}
+}
+
+#endif  /* WIN32 */
+
+bool valid_baud(int baud)
+{
+	switch (baud) {
+#define IOSPEED(baud)  \
+		case baud:  \
+			return true;  \
+// END
+#include "iospeeds.h"
+#undef IOSPEED
+		default:
+			return false;
+	}
+}
 
 
 /* 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.
@@ -680,7 +853,7 @@ int serial_open(const char *devpath, unsigned long baud, uint8_t timeout, bool p
 		if (errno == EACCES)
 		if (errno == EACCES)
 			applog(LOG_ERR, "Do not have user privileges required to open %s", devpath);
 			applog(LOG_ERR, "Do not have user privileges required to open %s", devpath);
 		else
 		else
-			applog(LOG_DEBUG, "Open %s failed, errno:%d", devpath, errno);
+			applog(LOG_DEBUG, "Open %s failed: %s", devpath, bfg_strerror(errno, BST_ERRNO));
 
 
 		return -1;
 		return -1;
 	}
 	}
@@ -693,30 +866,16 @@ int serial_open(const char *devpath, unsigned long baud, uint8_t timeout, bool p
 	termios_debug(devpath, &my_termios, "before");
 	termios_debug(devpath, &my_termios, "before");
 #endif
 #endif
 
 
-	switch (baud) {
-	case 0:
-		break;
-	case 19200:
-		cfsetispeed(&my_termios, B19200);
-		cfsetospeed(&my_termios, B19200);
-		break;
-	case 38400:
-		cfsetispeed(&my_termios, B38400);
-		cfsetospeed(&my_termios, B38400);
-		break;
-	case 57600:
-		cfsetispeed(&my_termios, B57600);
-		cfsetospeed(&my_termios, B57600);
-		break;
-	case 115200:
-		cfsetispeed(&my_termios, B115200);
-		cfsetospeed(&my_termios, B115200);
-		break;
-	// TODO: try some higher speeds with the Icarus and BFL to see
-	// if they support them and if setting them makes any difference
-	// N.B. B3000000 doesn't work on Icarus
-	default:
-		applog(LOG_WARNING, "Unrecognized baud rate: %lu", baud);
+	if (baud)
+	{
+		speed_t speed = tiospeed_t(baud);
+		if (speed == B0)
+			applog(LOG_WARNING, "Unrecognized baud rate: %lu", baud);
+		else
+		{
+			cfsetispeed(&my_termios, speed);
+			cfsetospeed(&my_termios, speed);
+		}
 	}
 	}
 
 
 	my_termios.c_cflag &= ~(CSIZE | PARENB);
 	my_termios.c_cflag &= ~(CSIZE | PARENB);
@@ -820,7 +979,7 @@ FILE *open_bitstream(const char *dname, const char *filename)
 
 
 #define check_magic(L)  do {  \
 #define check_magic(L)  do {  \
 	if (1 != fread(buf, 1, 1, f))  \
 	if (1 != fread(buf, 1, 1, f))  \
-		bailout(LOG_ERR, "%s: Error reading firmware ('%c')",  \
+		bailout(LOG_ERR, "%s: Error reading bitstream ('%c')",  \
 		        repr, L);  \
 		        repr, L);  \
 	if (buf[0] != L)  \
 	if (buf[0] != L)  \
 		bailout(LOG_ERR, "%s: Firmware has wrong magic ('%c')",  \
 		bailout(LOG_ERR, "%s: Firmware has wrong magic ('%c')",  \
@@ -829,14 +988,14 @@ FILE *open_bitstream(const char *dname, const char *filename)
 
 
 #define read_str(eng)  do {  \
 #define read_str(eng)  do {  \
 	if (1 != fread(buf, 2, 1, f))  \
 	if (1 != fread(buf, 2, 1, f))  \
-		bailout(LOG_ERR, "%s: Error reading firmware (" eng " len)",  \
+		bailout(LOG_ERR, "%s: Error reading bitstream (" eng " len)",  \
 		        repr);  \
 		        repr);  \
 	len = (ubuf[0] << 8) | ubuf[1];  \
 	len = (ubuf[0] << 8) | ubuf[1];  \
 	if (len >= sizeof(buf))  \
 	if (len >= sizeof(buf))  \
 		bailout(LOG_ERR, "%s: Firmware " eng " too long",  \
 		bailout(LOG_ERR, "%s: Firmware " eng " too long",  \
 		        repr);  \
 		        repr);  \
 	if (1 != fread(buf, len, 1, f))  \
 	if (1 != fread(buf, len, 1, f))  \
-		bailout(LOG_ERR, "%s: Error reading firmware (" eng ")",  \
+		bailout(LOG_ERR, "%s: Error reading bitstream (" eng ")",  \
 		        repr);  \
 		        repr);  \
 	buf[len] = '\0';  \
 	buf[len] = '\0';  \
 } while(0)
 } while(0)
@@ -850,10 +1009,15 @@ FILE *open_xilinx_bitstream(const char *dname, const char *repr, const char *fwf
 
 
 	FILE *f = open_bitstream(dname, fwfile);
 	FILE *f = open_bitstream(dname, fwfile);
 	if (!f)
 	if (!f)
-		bailout(LOG_ERR, "%s: Error opening firmware file %s",
+	{
+		applog(LOG_ERR, "%s: Error opening bitstream file %s",
 		        repr, fwfile);
 		        repr, fwfile);
+		applog(LOG_ERR, "%s: Did you install the necessary bitstream package?",
+		       repr);
+		return NULL;
+	}
 	if (1 != fread(buf, 2, 1, f))
 	if (1 != fread(buf, 2, 1, f))
-		bailout(LOG_ERR, "%s: Error reading firmware (magic)",
+		bailout(LOG_ERR, "%s: Error reading bitstream (magic)",
 		        repr);
 		        repr);
 	if (buf[0] || buf[1] != 9)
 	if (buf[0] || buf[1] != 9)
 		bailout(LOG_ERR, "%s: Firmware has wrong magic (9)",
 		bailout(LOG_ERR, "%s: Firmware has wrong magic (9)",
@@ -872,7 +1036,7 @@ FILE *open_xilinx_bitstream(const char *dname, const char *repr, const char *fwf
 		++p;
 		++p;
 	unsigned long fwusercode = (unsigned long)strtoll(p, &p, 16);
 	unsigned long fwusercode = (unsigned long)strtoll(p, &p, 16);
 	if (p[0] != '\0')
 	if (p[0] != '\0')
-		bailout(LOG_ERR, "%s: Bad usercode in firmware file",
+		bailout(LOG_ERR, "%s: Bad usercode in bitstream file",
 		        repr);
 		        repr);
 	if (fwusercode == 0xffffffff)
 	if (fwusercode == 0xffffffff)
 		bailout(LOG_ERR, "%s: Firmware doesn't support user code",
 		bailout(LOG_ERR, "%s: Firmware doesn't support user code",
@@ -889,7 +1053,7 @@ FILE *open_xilinx_bitstream(const char *dname, const char *repr, const char *fwf
 	applog(LOG_DEBUG, "  Build time: %s", buf);
 	applog(LOG_DEBUG, "  Build time: %s", buf);
 	check_magic('e');
 	check_magic('e');
 	if (1 != fread(buf, 4, 1, f))
 	if (1 != fread(buf, 4, 1, f))
-		bailout(LOG_ERR, "%s: Error reading firmware (data len)",
+		bailout(LOG_ERR, "%s: Error reading bitstream (data len)",
 		        repr);
 		        repr);
 	len = ((unsigned long)ubuf[0] << 24) | ((unsigned long)ubuf[1] << 16) | (ubuf[2] << 8) | ubuf[3];
 	len = ((unsigned long)ubuf[0] << 24) | ((unsigned long)ubuf[1] << 16) | (ubuf[2] << 8) | ubuf[3];
 	applog(LOG_DEBUG, "  Bitstream size: %lu", len);
 	applog(LOG_DEBUG, "  Bitstream size: %lu", len);

+ 25 - 1
fpgautils.h

@@ -6,9 +6,22 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <unistd.h>
 
 
+#ifdef HAVE_LIBUSB
+#include <libusb.h>
+#endif
+
 struct device_drv;
 struct device_drv;
 struct cgpu_info;
 struct cgpu_info;
 
 
+struct detectone_meta_info_t {
+	const char *manufacturer;
+	const char *product;
+	const char *serial;
+};
+
+// NOTE: Should detectone become run multithreaded, this will become a threadsafe #define
+extern struct detectone_meta_info_t detectone_meta_info;
+
 typedef bool(*detectone_func_t)(const char*);
 typedef bool(*detectone_func_t)(const char*);
 typedef int(*autoscan_func_t)();
 typedef int(*autoscan_func_t)();
 
 
@@ -25,10 +38,20 @@ extern int _serial_detect(struct device_drv *api, detectone_func_t, autoscan_fun
 	_serial_detect(api, detectone,     NULL, 2)
 	_serial_detect(api, detectone,     NULL, 2)
 #define noserial_detect(api, autoscan)  \
 #define noserial_detect(api, autoscan)  \
 	_serial_detect(api, NULL     , autoscan, 0)
 	_serial_detect(api, NULL     , autoscan, 0)
+#define noserial_detect_manual(api, autoscan)  \
+	_serial_detect(api, NULL     , autoscan, 4)
 extern int _serial_autodetect(detectone_func_t, ...);
 extern int _serial_autodetect(detectone_func_t, ...);
 #define serial_autodetect(...)  _serial_autodetect(__VA_ARGS__, NULL)
 #define serial_autodetect(...)  _serial_autodetect(__VA_ARGS__, NULL)
 
 
-extern struct device_drv *serial_claim(const char *devpath, struct device_drv *);
+extern struct device_drv *bfg_claim_serial(struct device_drv * const, const bool verbose, const char * const devpath);
+#define serial_claim(devpath, drv)    bfg_claim_serial(drv, false, devpath)
+#define serial_claim_v(devpath, drv)  bfg_claim_serial(drv, true , devpath)
+extern struct device_drv *bfg_claim_usb(struct device_drv * const, const bool verbose, const uint8_t usbbus, const uint8_t usbaddr);
+#define bfg_claim_libusb(api, verbose, dev)  bfg_claim_usb(api, verbose, libusb_get_bus_number(dev), libusb_get_device_address(dev))
+
+#ifdef HAVE_LIBUSB
+extern void cgpu_copy_libusb_strings(struct cgpu_info *, libusb_device *);
+#endif
 
 
 extern int serial_open(const char *devpath, unsigned long baud, uint8_t timeout, bool purge);
 extern int serial_open(const char *devpath, unsigned long baud, uint8_t timeout, bool purge);
 extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char *eol);
 extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char *eol);
@@ -42,5 +65,6 @@ extern FILE *open_bitstream(const char *dname, const char *filename);
 extern FILE *open_xilinx_bitstream(const char *dname, const char *repr, const char *fwfile, unsigned long *out_len);
 extern FILE *open_xilinx_bitstream(const char *dname, const char *repr, const char *fwfile, unsigned long *out_len);
 
 
 extern int get_serial_cts(int fd);
 extern int get_serial_cts(int fd);
+extern bool valid_baud(int baud);
 
 
 #endif
 #endif

+ 15 - 5
ft232r.c

@@ -63,12 +63,13 @@ void ft232r_scan()
 	struct ft232r_device_info *info;
 	struct ft232r_device_info *info;
 	int err;
 	int err;
 	unsigned char buf[0x100];
 	unsigned char buf[0x100];
+	int skipped = 0;
 
 
 	ft232r_scan_free();
 	ft232r_scan_free();
 
 
 	count = libusb_get_device_list(NULL, &list);
 	count = libusb_get_device_list(NULL, &list);
 	if (unlikely(count < 0)) {
 	if (unlikely(count < 0)) {
-		applog(LOG_ERR, "ft232r_scan: Error getting USB device list: %s", libusb_error_name(count));
+		applog(LOG_ERR, "ft232r_scan: Error getting USB device list: %s", bfg_strerror(count, BST_LIBUSB));
 		ft232r_devinfo_list = calloc(1, sizeof(struct ft232r_device_info *));
 		ft232r_devinfo_list = calloc(1, sizeof(struct ft232r_device_info *));
 		return;
 		return;
 	}
 	}
@@ -76,9 +77,15 @@ void ft232r_scan()
 	ft232r_devinfo_list = malloc(sizeof(struct ft232r_device_info *) * (count + 1));
 	ft232r_devinfo_list = malloc(sizeof(struct ft232r_device_info *) * (count + 1));
 
 
 	for (i = 0; i < count; ++i) {
 	for (i = 0; i < count; ++i) {
+		if (bfg_claim_libusb(NULL, false, list[i]))
+		{
+			++skipped;
+			continue;
+		}
+		
 		err = libusb_get_device_descriptor(list[i], &desc);
 		err = libusb_get_device_descriptor(list[i], &desc);
 		if (unlikely(err)) {
 		if (unlikely(err)) {
-			applog(LOG_ERR, "ft232r_scan: Error getting device descriptor: %s", libusb_error_name(err));
+			applog(LOG_ERR, "ft232r_scan: Error getting device descriptor: %s", bfg_strerror(err, BST_LIBUSB));
 			continue;
 			continue;
 		}
 		}
 		if (!(desc.idVendor == FT232R_IDVENDOR && desc.idProduct == FT232R_IDPRODUCT)) {
 		if (!(desc.idVendor == FT232R_IDVENDOR && desc.idProduct == FT232R_IDPRODUCT)) {
@@ -88,14 +95,14 @@ void ft232r_scan()
 
 
 		err = libusb_open(list[i], &handle);
 		err = libusb_open(list[i], &handle);
 		if (unlikely(err)) {
 		if (unlikely(err)) {
-			applog(LOG_ERR, "ft232r_scan: Error opening device: %s", libusb_error_name(err));
+			applog(LOG_ERR, "ft232r_scan: Error opening device: %s", bfg_strerror(err, BST_LIBUSB));
 			continue;
 			continue;
 		}
 		}
 
 
 		n = libusb_get_string_descriptor_ascii(handle, desc.iProduct, buf, sizeof(buf)-1);
 		n = libusb_get_string_descriptor_ascii(handle, desc.iProduct, buf, sizeof(buf)-1);
 		if (unlikely(n < 0)) {
 		if (unlikely(n < 0)) {
 			libusb_close(handle);
 			libusb_close(handle);
-			applog(LOG_ERR, "ft232r_scan: Error getting iProduct string: %s", libusb_error_name(n));
+			applog(LOG_ERR, "ft232r_scan: Error getting iProduct string: %s", bfg_strerror(n, BST_LIBUSB));
 			continue;
 			continue;
 		}
 		}
 		buf[n] = '\0';
 		buf[n] = '\0';
@@ -105,7 +112,7 @@ void ft232r_scan()
 		n = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, buf, sizeof(buf)-1);
 		n = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, buf, sizeof(buf)-1);
 		libusb_close(handle);
 		libusb_close(handle);
 		if (unlikely(n < 0)) {
 		if (unlikely(n < 0)) {
-			applog(LOG_ERR, "ft232r_scan: Error getting iSerialNumber string: %s", libusb_error_name(n));
+			applog(LOG_ERR, "ft232r_scan: Error getting iSerialNumber string: %s", bfg_strerror(n, BST_LIBUSB));
 			n = 0;
 			n = 0;
 		}
 		}
 		buf[n] = '\0';
 		buf[n] = '\0';
@@ -118,6 +125,9 @@ void ft232r_scan()
 
 
 	ft232r_devinfo_list[found] = NULL;
 	ft232r_devinfo_list[found] = NULL;
 	libusb_free_device_list(list, 1);
 	libusb_free_device_list(list, 1);
+	
+	if (skipped)
+		applog(LOG_DEBUG, "%s: Skipping probe of %d claimed devices", __func__, skipped);
 }
 }
 
 
 int ft232r_detect(const char *product_needle, const char *serial, foundusb_func_t cb)
 int ft232r_detect(const char *product_needle, const char *serial, foundusb_func_t cb)

+ 2 - 0
icarus-common.h

@@ -35,6 +35,8 @@
 // keeping a ongoing average of recent data
 // keeping a ongoing average of recent data
 #define INFO_HISTORY 10
 #define INFO_HISTORY 10
 
 
+extern struct device_drv icarus_drv;
+
 struct ICARUS_HISTORY {
 struct ICARUS_HISTORY {
 	struct timeval finish;
 	struct timeval finish;
 	double sumXiTi;
 	double sumXiTi;

+ 37 - 0
iospeeds.h

@@ -0,0 +1,37 @@
+IOSPEED(0)
+IOSPEED(50)
+IOSPEED(110)
+IOSPEED(134)
+IOSPEED(200)
+
+IOSPEED(75)
+IOSPEED(150)
+IOSPEED(300)
+IOSPEED(600)
+IOSPEED(1200)
+IOSPEED(1800)
+IOSPEED(2400)
+IOSPEED(4800)
+IOSPEED(9600)
+IOSPEED(19200)
+IOSPEED(38400)
+
+IOSPEED(57600)
+IOSPEED(115200)
+IOSPEED(230400)
+IOSPEED(460800)
+IOSPEED(921600)
+
+IOSPEED(576000)
+IOSPEED(1152000)
+
+IOSPEED(1500000)
+IOSPEED(3000000)
+
+IOSPEED(500000)
+IOSPEED(1000000)
+IOSPEED(2000000)
+IOSPEED(4000000)
+
+IOSPEED(2500000)
+IOSPEED(3500000)

+ 2 - 2
jtag.c

@@ -83,9 +83,9 @@ bool jtag_clock(struct jtag_port *jp, bool tms, bool tdi, bool *tdo)
 	if (tdo) {
 	if (tdo) {
 		*tdo = (rbuf[rbufsz-1] & jp->tdo);
 		*tdo = (rbuf[rbufsz-1] & jp->tdo);
 #ifdef DEBUG_JTAG_CLOCK
 #ifdef DEBUG_JTAG_CLOCK
-	char *x = bin2hex(rbuf, rbufsz);
+		char x[(rbufsz * 2) + 1];
+		bin2hex(x, rbuf, rbufsz);
 	applog(LOG_DEBUG, "%p %02x tms=%d tdi=%d tdo=%d (%u:%s)", jp, (unsigned)rbuf[rbufsz-1], (int)tms, (int)tdi, (int)(bool)(rbuf[rbufsz-1] & jp->tdo), (unsigned)rbufsz, x);
 	applog(LOG_DEBUG, "%p %02x tms=%d tdi=%d tdo=%d (%u:%s)", jp, (unsigned)rbuf[rbufsz-1], (int)tms, (int)tdi, (int)(bool)(rbuf[rbufsz-1] & jp->tdo), (unsigned)rbufsz, x);
-	free(x);
 	} else {
 	} else {
 		applog(LOG_DEBUG, "%p %02x tms=%d tdi=%d tdo=?ignore", jp, (unsigned)buf[2], (int)tms, (int)tdi);
 		applog(LOG_DEBUG, "%p %02x tms=%d tdi=%d tdo=?ignore", jp, (unsigned)buf[2], (int)tms, (int)tdi);
 #endif
 #endif

+ 35 - 11
libztex.c

@@ -34,6 +34,7 @@
 #include "miner.h"
 #include "miner.h"
 #include "fpgautils.h"
 #include "fpgautils.h"
 #include "libztex.h"
 #include "libztex.h"
+#include "util.h"
 
 
 //* Capability index for EEPROM support.
 //* Capability index for EEPROM support.
 #define CAPABILITY_EEPROM 0,0
 #define CAPABILITY_EEPROM 0,0
@@ -72,7 +73,7 @@ static int libztex_get_string_descriptor_ascii(libusb_device_handle *dev, uint8_
 	    LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | 0,
 	    LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | 0,
 	    0x0000, buf, sizeof(buf), 1000);
 	    0x0000, buf, sizeof(buf), 1000);
 	if (cnt < 0) {
 	if (cnt < 0) {
-		applog(LOG_ERR, "%s: Failed to read LANGIDs: %s", __func__, libusb_error_name(cnt));
+		applog(LOG_ERR, "%s: Failed to read LANGIDs: %s", __func__, bfg_strerror(cnt, BST_LIBUSB));
 		return cnt;
 		return cnt;
 	}
 	}
 
 
@@ -82,7 +83,7 @@ static int libztex_get_string_descriptor_ascii(libusb_device_handle *dev, uint8_
 	    LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc_index,
 	    LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc_index,
 	    langid, buf, sizeof(buf), 1000);
 	    langid, buf, sizeof(buf), 1000);
 	if (cnt < 0) {
 	if (cnt < 0) {
-		applog(LOG_ERR, "%s: Failed to read string descriptor: %s", __func__, libusb_error_name(cnt));
+		applog(LOG_ERR, "%s: Failed to read string descriptor: %s", __func__, bfg_strerror(cnt, BST_LIBUSB));
 		return cnt;
 		return cnt;
 	}
 	}
 
 
@@ -109,7 +110,7 @@ static bool libztex_firmwareReset(struct libusb_device_handle *hndl, bool enable
 	int cnt = libusb_control_transfer(hndl, 0x40, 0xA0, 0xE600, 0, &reset, 1, 1000);
 	int cnt = libusb_control_transfer(hndl, 0x40, 0xA0, 0xE600, 0, &reset, 1, 1000);
 	if (cnt < 0)
 	if (cnt < 0)
 	{
 	{
-		applog(LOG_ERR, "Ztex reset %d failed: %s", enable, libusb_error_name(cnt));
+		applog(LOG_ERR, "Ztex reset %d failed: %s", enable, bfg_strerror(cnt, BST_LIBUSB));
 		return 1;
 		return 1;
 	}
 	}
 
 
@@ -139,7 +140,7 @@ static enum check_result libztex_checkDevice(struct libusb_device *dev)
 
 
 	err = libusb_open(dev, &hndl);
 	err = libusb_open(dev, &hndl);
 	if (err != LIBUSB_SUCCESS) {
 	if (err != LIBUSB_SUCCESS) {
-		applog(LOG_ERR, "%s: Can not open ZTEX device: %s", __func__, libusb_error_name(err));
+		applog(LOG_ERR, "%s: Can not open ZTEX device: %s", __func__, bfg_strerror(err, BST_LIBUSB));
 		goto done;
 		goto done;
 	}
 	}
 
 
@@ -224,7 +225,7 @@ static enum check_result libztex_checkDevice(struct libusb_device *dev)
 	}
 	}
 
 
 	if (0 != fseek(fp, 0, SEEK_END)) {
 	if (0 != fseek(fp, 0, SEEK_END)) {
-		applog(LOG_ERR, "Ztex firmware fseek: %s", strerror(errno));
+		applog(LOG_ERR, "Ztex firmware fseek: %s", bfg_strerror(errno, BST_ERRNO));
 		goto done;
 		goto done;
 	}
 	}
 
 
@@ -232,7 +233,7 @@ static enum check_result libztex_checkDevice(struct libusb_device *dev)
 	rewind(fp);
 	rewind(fp);
 	fw_buf = malloc(length);
 	fw_buf = malloc(length);
 	if (!fw_buf) {
 	if (!fw_buf) {
-		applog(LOG_ERR, "%s: Can not allocate memory: %s", __func__, strerror(errno));
+		applog(LOG_ERR, "%s: Can not allocate memory: %s", __func__, bfg_strerror(errno, BST_ERRNO));
 		goto done;
 		goto done;
 	}
 	}
 
 
@@ -271,7 +272,7 @@ static enum check_result libztex_checkDevice(struct libusb_device *dev)
 		int k = libusb_control_transfer(hndl, 0x40, 0xA0, i, 0, fw_buf + i, numbytes, 1000);
 		int k = libusb_control_transfer(hndl, 0x40, 0xA0, i, 0, fw_buf + i, numbytes, 1000);
 		if (k < numbytes)
 		if (k < numbytes)
 		{
 		{
-			applog(LOG_ERR, "Ztex device: Failed to write firmware at %d with: %s", i, libusb_error_name(k));
+			applog(LOG_ERR, "Ztex device: Failed to write firmware at %d with: %s", i, bfg_strerror(k, BST_LIBUSB));
 			goto done;
 			goto done;
 		}
 		}
 	}
 	}
@@ -611,7 +612,7 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt
 	dclk_prepare(&newdev->dclk);
 	dclk_prepare(&newdev->dclk);
 	err = libusb_open(dev, &newdev->hndl);
 	err = libusb_open(dev, &newdev->hndl);
 	if (err != LIBUSB_SUCCESS) {
 	if (err != LIBUSB_SUCCESS) {
-		applog(LOG_ERR, "%s: Can not open ZTEX device: %s", __func__, libusb_error_name(err));
+		applog(LOG_ERR, "%s: Can not open ZTEX device: %s", __func__, bfg_strerror(err, BST_LIBUSB));
 		return CHECK_ERROR;
 		return CHECK_ERROR;
 	}
 	}
 
 
@@ -626,6 +627,18 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt
 		applog(LOG_ERR, "Ztex check device: Failed to read device snString with err %d", cnt);
 		applog(LOG_ERR, "Ztex check device: Failed to read device snString with err %d", cnt);
 		return cnt;
 		return cnt;
 	}
 	}
+	
+	cnt = libztex_get_string_descriptor_ascii(newdev->hndl, newdev->descriptor.iProduct, buf, sizeof(buf));
+	if (unlikely(cnt < 0))
+		applog(LOG_WARNING, "Ztex check device: Failed to read device product with err %d", cnt);
+	else
+		newdev->dev_product = buf[0] ? strdup((void*)buf) : NULL;
+	
+	cnt = libztex_get_string_descriptor_ascii(newdev->hndl, newdev->descriptor.iManufacturer, buf, sizeof(buf));
+	if (unlikely(cnt < 0))
+		applog(LOG_WARNING, "Ztex check device: Failed to read device manufacturer with err %d", cnt);
+	else
+		newdev->dev_manufacturer = buf[0] ? strdup((void*)buf) : NULL;
 
 
 	cnt = libusb_control_transfer(newdev->hndl, 0xc0, 0x22, 0, 0, buf, 40, 500);
 	cnt = libusb_control_transfer(newdev->hndl, 0xc0, 0x22, 0, 0, buf, 40, 500);
 	if (unlikely(cnt < 0)) {
 	if (unlikely(cnt < 0)) {
@@ -737,6 +750,7 @@ int libztex_scanDevices(struct libztex_dev_list*** devs_p)
 	int found, max_found = 0, pos = 0, err, rescan, ret = 0;
 	int found, max_found = 0, pos = 0, err, rescan, ret = 0;
 	libusb_device **list = NULL;
 	libusb_device **list = NULL;
 	ssize_t cnt, i;
 	ssize_t cnt, i;
+	int skipped = 0;
 
 
 	do {
 	do {
 		cnt = libusb_get_device_list(NULL, &list);
 		cnt = libusb_get_device_list(NULL, &list);
@@ -746,10 +760,16 @@ int libztex_scanDevices(struct libztex_dev_list*** devs_p)
 		}
 		}
 
 
 		for (found = rescan = i = 0; i < cnt; i++) {
 		for (found = rescan = i = 0; i < cnt; i++) {
+			if (bfg_claim_libusb(NULL, false, list[i]))
+			{
+				++skipped;
+				continue;
+			}
+			
 			err = libztex_checkDevice(list[i]);
 			err = libztex_checkDevice(list[i]);
 			switch (err) {
 			switch (err) {
 			case CHECK_ERROR:
 			case CHECK_ERROR:
-				applog(LOG_ERR, "Ztex: Can not check device: %s", libusb_error_name(err));
+				applog(LOG_ERR, "Ztex: Can not check device: %s", bfg_strerror(err, BST_LIBUSB));
 				continue;
 				continue;
 			case CHECK_IS_NOT_ZTEX:
 			case CHECK_IS_NOT_ZTEX:
 				continue;
 				continue;
@@ -786,7 +806,7 @@ int libztex_scanDevices(struct libztex_dev_list*** devs_p)
 		if (!ztex) {
 		if (!ztex) {
 			ztex = malloc(sizeof(*ztex));
 			ztex = malloc(sizeof(*ztex));
 			if (!ztex) {
 			if (!ztex) {
-				applog(LOG_ERR, "%s: Can not allocate memory for device struct: %s", __func__, strerror(errno));
+				applog(LOG_ERR, "%s: Can not allocate memory for device struct: %s", __func__, bfg_strerror(errno, BST_ERRNO));
 				goto done;
 				goto done;
 			}
 			}
 		}
 		}
@@ -804,7 +824,7 @@ int libztex_scanDevices(struct libztex_dev_list*** devs_p)
 
 
 		devs[pos] = malloc(sizeof(struct libztex_dev_list));
 		devs[pos] = malloc(sizeof(struct libztex_dev_list));
 		if (NULL == devs[pos]) {
 		if (NULL == devs[pos]) {
-			applog(LOG_ERR, "%s: Can not allocate memory for device: %s", __func__, strerror(errno));
+			applog(LOG_ERR, "%s: Can not allocate memory for device: %s", __func__, bfg_strerror(errno, BST_ERRNO));
 			libztex_destroy_device(ztex);
 			libztex_destroy_device(ztex);
 			ztex = NULL;
 			ztex = NULL;
 			continue;
 			continue;
@@ -827,6 +847,10 @@ done:
 		free(devs);
 		free(devs);
 	if (list)
 	if (list)
 		libusb_free_device_list(list, 1);
 		libusb_free_device_list(list, 1);
+	
+	if (skipped)
+		applog(LOG_DEBUG, "%s: Skipping probe of %d claimed devices", __func__, skipped);
+	
 	return ret;
 	return ret;
 }
 }
 
 

+ 2 - 0
libztex.h

@@ -27,6 +27,8 @@ struct libztex_device {
 	libusb_device_handle *hndl; 
 	libusb_device_handle *hndl; 
 	unsigned char usbbus;
 	unsigned char usbbus;
 	unsigned char usbaddress;
 	unsigned char usbaddress;
+	char *dev_manufacturer;
+	char *dev_product;
 	unsigned char snString[LIBZTEX_SNSTRING_LEN+1];
 	unsigned char snString[LIBZTEX_SNSTRING_LEN+1];
 	unsigned char productId[4];
 	unsigned char productId[4];
 	unsigned char fwVersion;
 	unsigned char fwVersion;

+ 6 - 3
logging.h

@@ -56,12 +56,15 @@ extern void _applog(int prio, const char *str);
 	return rv;  \
 	return rv;  \
 } while (0)
 } while (0)
 
 
+extern void _bfg_clean_up(void);
+
 #define quit(status, fmt, ...) do { \
 #define quit(status, fmt, ...) do { \
+	_bfg_clean_up();  \
 	if (fmt) { \
 	if (fmt) { \
-		char tmp42[LOGBUFSIZ]; \
-		snprintf(tmp42, sizeof(tmp42), fmt, ##__VA_ARGS__); \
-		_applog(LOG_ERR, tmp42); \
+		fprintf(stderr, fmt, ##__VA_ARGS__);  \
 	} \
 	} \
+	fprintf(stderr, "\n");  \
+	fflush(stderr);  \
 	_quit(status); \
 	_quit(status); \
 } while (0)
 } while (0)
 
 

File diff suppressed because it is too large
+ 373 - 154
miner.c


+ 32 - 23
miner.h

@@ -215,6 +215,8 @@ enum alive {
 	LIFE_NOSTART,
 	LIFE_NOSTART,
 	LIFE_INIT,
 	LIFE_INIT,
 	LIFE_WAIT,
 	LIFE_WAIT,
+	LIFE_INIT2,  // Still initializing, but safe to call functions
+	LIFE_DEAD2,  // Totally dead, NOT safe to call functions
 };
 };
 
 
 
 
@@ -282,20 +284,18 @@ struct device_drv {
 	// DRV-global functions
 	// DRV-global functions
 	void (*drv_detect)();
 	void (*drv_detect)();
 
 
-	// Device-specific functions
-	void (*get_dev_statline_before)(char *, struct cgpu_info *);
-	void (*get_dev_statline_after)(char *, struct cgpu_info *);
-
 	// Processor-specific functions
 	// Processor-specific functions
 	void (*reinit_device)(struct cgpu_info *);
 	void (*reinit_device)(struct cgpu_info *);
-	void (*get_statline_before)(char *, struct cgpu_info *);
-	void (*get_statline)(char *, struct cgpu_info *);
+	bool (*override_statline_temp)(char *buf, struct cgpu_info *, bool per_processor);
 	struct api_data* (*get_api_extra_device_detail)(struct cgpu_info *);
 	struct api_data* (*get_api_extra_device_detail)(struct cgpu_info *);
 	struct api_data* (*get_api_extra_device_status)(struct cgpu_info *);
 	struct api_data* (*get_api_extra_device_status)(struct cgpu_info *);
 	struct api_data *(*get_api_stats)(struct cgpu_info *);
 	struct api_data *(*get_api_stats)(struct cgpu_info *);
 	bool (*get_stats)(struct cgpu_info *);
 	bool (*get_stats)(struct cgpu_info *);
 	bool (*identify_device)(struct cgpu_info *);  // e.g. to flash a led
 	bool (*identify_device)(struct cgpu_info *);  // e.g. to flash a led
 	char *(*set_device)(struct cgpu_info *, char *option, char *setting, char *replybuf);
 	char *(*set_device)(struct cgpu_info *, char *option, char *setting, char *replybuf);
+	void (*proc_wlogprint_status)(struct cgpu_info *);
+	void (*proc_tui_wlogprint_choices)(struct cgpu_info *);
+	const char *(*proc_tui_handle_choice)(struct cgpu_info *, int input);
 
 
 	// Thread-specific functions
 	// Thread-specific functions
 	bool (*thread_prepare)(struct thr_info *);
 	bool (*thread_prepare)(struct thr_info *);
@@ -441,6 +441,9 @@ struct cgpu_info {
 	
 	
 	const char *device_path;
 	const char *device_path;
 	void *device_data;
 	void *device_data;
+	const char *dev_manufacturer;
+	const char *dev_product;
+	const char *dev_serial;
 	union {
 	union {
 #ifdef USE_ZTEX
 #ifdef USE_ZTEX
 		struct libztex_device *device_ztex;
 		struct libztex_device *device_ztex;
@@ -475,6 +478,7 @@ struct cgpu_info {
 	int accepted;
 	int accepted;
 	int rejected;
 	int rejected;
 	int stale;
 	int stale;
+	int bad_nonces;
 	int hw_errors;
 	int hw_errors;
 	double rolling;
 	double rolling;
 	double total_mhashes;
 	double total_mhashes;
@@ -875,7 +879,7 @@ extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
 			     const char *rpc_req, bool, bool, int *,
 			     const char *rpc_req, bool, bool, int *,
 			     struct pool *pool, bool);
 			     struct pool *pool, bool);
 extern bool our_curl_supports_proxy_uris();
 extern bool our_curl_supports_proxy_uris();
-extern char *bin2hex(const unsigned char *p, size_t len);
+extern void bin2hex(char *out, const void *in, size_t len);
 extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
 extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
 
 
 typedef bool (*sha256_func)(struct thr_info*, const unsigned char *pmidstate,
 typedef bool (*sha256_func)(struct thr_info*, const unsigned char *pmidstate,
@@ -969,6 +973,8 @@ extern int mining_threads;
 extern struct cgpu_info *cpus;
 extern struct cgpu_info *cpus;
 extern int total_devices;
 extern int total_devices;
 extern struct cgpu_info **devices;
 extern struct cgpu_info **devices;
+extern int total_devices_new;
+extern struct cgpu_info **devices_new;
 extern int total_pools;
 extern int total_pools;
 extern struct pool **pools;
 extern struct pool **pools;
 extern const char *algo_names[];
 extern const char *algo_names[];
@@ -1051,21 +1057,18 @@ enum pool_protocol {
 
 
 struct stratum_work {
 struct stratum_work {
 	char *job_id;
 	char *job_id;
-	char *prev_hash;
-	char *coinbase1;
-	char *coinbase2;
-	char **merkle;
-	char *bbversion;
-	char *nbit;
-	char *ntime;
 	bool clean;
 	bool clean;
-
-	size_t cb1_len;
-	size_t cb2_len;
-	size_t cb_len;
-
-	size_t header_len;
+	
+	bytes_t coinbase;
+	size_t nonce2_offset;
+	
 	int merkles;
 	int merkles;
+	bytes_t merkle_bin;
+	
+	uint8_t header1[36];
+	uint8_t diffbits[4];
+	uint8_t ntime[4];
+
 	double diff;
 	double diff;
 
 
 	bool transparency_probed;
 	bool transparency_probed;
@@ -1159,6 +1162,10 @@ struct pool {
 	char *nonce1;
 	char *nonce1;
 	size_t n1_len;
 	size_t n1_len;
 	uint32_t nonce2;
 	uint32_t nonce2;
+	int nonce2sz;
+#ifdef WORDS_BIGENDIAN
+	int nonce2off;
+#endif
 	int n2size;
 	int n2size;
 	char *sessionid;
 	char *sessionid;
 	bool has_stratum;
 	bool has_stratum;
@@ -1210,8 +1217,7 @@ struct work {
 
 
 	bool		stratum;
 	bool		stratum;
 	char 		*job_id;
 	char 		*job_id;
-	char		*nonce2;
-	char		*ntime;
+	bytes_t		nonce2;
 	double		sdiff;
 	double		sdiff;
 	char		*nonce1;
 	char		*nonce1;
 
 
@@ -1243,7 +1249,8 @@ struct work {
 };
 };
 
 
 extern void get_datestamp(char *, struct timeval *);
 extern void get_datestamp(char *, struct timeval *);
-extern void inc_hw_errors(struct thr_info *thr);
+extern void inc_hw_errors(struct thr_info *, const struct work *, const uint32_t bad_nonce);
+#define inc_hw_errors_only(thr)  inc_hw_errors(thr, NULL, 0)
 enum test_nonce2_result {
 enum test_nonce2_result {
 	TNR_GOOD = 1,
 	TNR_GOOD = 1,
 	TNR_HIGH = 0,
 	TNR_HIGH = 0,
@@ -1259,6 +1266,7 @@ extern struct work *find_queued_work_bymidstate(struct cgpu_info *cgpu, char *mi
 extern void work_completed(struct cgpu_info *cgpu, struct work *work);
 extern void work_completed(struct cgpu_info *cgpu, struct work *work);
 extern bool abandon_work(struct work *, struct timeval *work_runtime, uint64_t hashes);
 extern bool abandon_work(struct work *, struct timeval *work_runtime, uint64_t hashes);
 extern void hash_queued_work(struct thr_info *mythr);
 extern void hash_queued_work(struct thr_info *mythr);
+extern void get_statline3(char *buf, struct cgpu_info *, bool for_curses, bool opt_show_procs);
 extern void tailsprintf(char *f, const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 2, 3);
 extern void tailsprintf(char *f, const char *fmt, ...) FORMAT_SYNTAX_CHECK(printf, 2, 3);
 extern void _wlog(const char *str);
 extern void _wlog(const char *str);
 extern void _wlogprint(const char *str);
 extern void _wlogprint(const char *str);
@@ -1294,6 +1302,7 @@ 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 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);
+extern int scan_serial(const char *);
 
 
 enum api_data_type {
 enum api_data_type {
 	API_ESCAPE,
 	API_ESCAPE,

+ 9 - 1
ocl.c

@@ -401,6 +401,7 @@ _clState *initCl(unsigned int gpu, char *name, size_t nameSize)
 	struct cgpu_info *cgpu = &gpus[gpu];
 	struct cgpu_info *cgpu = &gpus[gpu];
 	cl_platform_id platform = NULL;
 	cl_platform_id platform = NULL;
 	char pbuff[256], vbuff[255];
 	char pbuff[256], vbuff[255];
+	char *s;
 	cl_platform_id* platforms;
 	cl_platform_id* platforms;
 	cl_uint preferred_vwidth;
 	cl_uint preferred_vwidth;
 	cl_device_id *devices;
 	cl_device_id *devices;
@@ -839,7 +840,14 @@ build:
 		    strstr(name, "Wrestler" ) ||
 		    strstr(name, "Wrestler" ) ||
 		    strstr(name, "Zacate" ) ||
 		    strstr(name, "Zacate" ) ||
 		    strstr(name, "WinterPark" ))
 		    strstr(name, "WinterPark" ))
-			patchbfi = true;
+		{
+			// BFI_INT patching only works with AMD-APP up to 1084
+			if (strstr(vbuff, "ATI-Stream"))
+				patchbfi = true;
+			else
+			if ((s = strstr(vbuff, "AMD-APP")) && (s = strchr(s, '(')) && atoi(&s[1]) < 1085)
+				patchbfi = true;
+		}
 	} else
 	} else
 		applog(LOG_DEBUG, "cl_amd_media_ops not found, will not set BITALIGN");
 		applog(LOG_DEBUG, "cl_amd_media_ops not found, will not set BITALIGN");
 
 

+ 1 - 1
openwrt/bfgminer/Makefile

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

+ 15 - 15
usbtest.py

@@ -1,6 +1,7 @@
-#!/usr/bin/env python2.7
+#!/usr/bin/env python
 # Copyright 2012 Xiangfu
 # Copyright 2012 Xiangfu
 # Copyright 2012-2013 Andrew Smith
 # Copyright 2012-2013 Andrew Smith
+# Copyright 2013 Luke Dashjr
 #
 #
 # This program is free software; you can redistribute it and/or modify it under
 # 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
 # the terms of the GNU General Public License as published by the Free Software
@@ -39,7 +40,7 @@ if len(sys.argv) < 2:
 	sys.exit("Aborting")
 	sys.exit("Aborting")
 
 
 # Open with a 10 second timeout - just to be sure
 # Open with a 10 second timeout - just to be sure
-ser = serial.Serial(sys.argv[1], 115200, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, 10, False, False, 5, False, None)
+ser = serial.Serial(sys.argv[1], 115200, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE, 10, False, False, 5)
 
 
 if sys.argv[2] == "icarus":
 if sys.argv[2] == "icarus":
 
 
@@ -48,32 +49,32 @@ if sys.argv[2] == "icarus":
 	block = "0000000120c8222d0497a7ab44a1a2c7bf39de941c9970b1dc7cdc400000079700000000e88aabe1f353238c668d8a4df9318e614c10c474f8cdf8bc5f6397b946c33d7c4e7242c31a098ea500000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000"
 	block = "0000000120c8222d0497a7ab44a1a2c7bf39de941c9970b1dc7cdc400000079700000000e88aabe1f353238c668d8a4df9318e614c10c474f8cdf8bc5f6397b946c33d7c4e7242c31a098ea500000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000"
 	midstate = "33c5bf5751ec7f7e056443b5aee3800331432c83f404d9de38b94ecbf907b92d"
 	midstate = "33c5bf5751ec7f7e056443b5aee3800331432c83f404d9de38b94ecbf907b92d"
 
 
-	rdata2  = block.decode('hex')[95:63:-1]
-	rmid    = midstate.decode('hex')[::-1]
+	rdata2  = binascii.a2b_hex(block.encode('ascii'))[95:63:-1]
+	rmid    = binascii.a2b_hex(midstate.encode('ascii'))[::-1]
 	payload = rmid + rdata2
 	payload = rmid + rdata2
 
 
-	print("Push payload to icarus: " + binascii.hexlify(payload))
+	print("Push payload to icarus: " + binascii.hexlify(payload).decode('ascii'))
 	ser.write(payload)
 	ser.write(payload)
 
 
 	b=ser.read(4)
 	b=ser.read(4)
-	print("Result:(should be: 063c5e01): " + binascii.hexlify(b))
+	print("Result:(should be: 063c5e01): " + binascii.hexlify(b).decode('ascii'))
 
 
 	# Just another test
 	# Just another test
 	payload2 = "ce92099c5a80bb81c52990d5c0924c625fd25a535640607d5a4bdf8174e2c8d500000000000000000000000080000000000000000b290c1a42313b4f21b5bcb8"
 	payload2 = "ce92099c5a80bb81c52990d5c0924c625fd25a535640607d5a4bdf8174e2c8d500000000000000000000000080000000000000000b290c1a42313b4f21b5bcb8"
 	print("Push payload to icarus: " + payload2)
 	print("Push payload to icarus: " + payload2)
-	ser.write(payload2.decode('hex'))
+	ser.write(binascii.a2b_hex(payload2.encode('ascii')))
 
 
 	b=ser.read(4)
 	b=ser.read(4)
-	print("Result:(should be: 8e0b31c5): " + binascii.hexlify(b))
+	print("Result:(should be: 8e0b31c5): " + binascii.hexlify(b).decode('ascii'))
 else:
 else:
-	data = ""
+	data = b""
 	for arg in sys.argv[2::]:
 	for arg in sys.argv[2::]:
 		if arg[0:2:] == '0x':
 		if arg[0:2:] == '0x':
-			data += arg[2::].decode('hex')
+			data += binascii.a2b_hex(arg[2::].encode('ascii'))
 		else:
 		else:
-			data += arg
+			data += arg.encode('latin-1')
 
 
-	print("Sending: 0x" + binascii.hexlify(data))
+	print("Sending: 0x" + binascii.hexlify(data).decode('ascii'))
 	ser.write(data)
 	ser.write(data)
 
 
 	# If you're expecting more than one linefeed terminated reply,
 	# If you're expecting more than one linefeed terminated reply,
@@ -81,9 +82,8 @@ else:
 	# AND with no linefeed, this will wait the 10 seconds before returning
 	# AND with no linefeed, this will wait the 10 seconds before returning
 	print("Waiting up to 10 seconds ...")
 	print("Waiting up to 10 seconds ...")
 	b=ser.readline()
 	b=ser.readline()
-	print("Result: hex 0x" + binascii.hexlify(b))
+	print("Result: hex 0x" + binascii.hexlify(b).decode('ascii'))
 
 
-	# This could mess up the display - do it last
-	print("Result: asc '" + b + "'")
+	print("Result: asc %s" % (repr(b),))
 
 
 ser.close()
 ser.close()

+ 242 - 126
util.c

@@ -668,61 +668,56 @@ char *absolute_uri(char *uri, const char *ref)
 	return abs;
 	return abs;
 }
 }
 
 
-/* Returns a malloced array string of a binary value of arbitrary length. The
- * array is rounded up to a 4 byte size to appease architectures that need
- * aligned array  sizes */
-char *bin2hex(const unsigned char *p, size_t len)
-{
-	unsigned int i;
-	ssize_t slen;
-	char *s;
-
-	slen = len * 2 + 1;
-	if (slen % 4)
-		slen += 4 - (slen % 4);
-	s = calloc(slen, 1);
-	if (unlikely(!s))
-		quit(1, "Failed to calloc in bin2hex");
+static const char _hexchars[0x10] = "0123456789abcdef";
 
 
-	for (i = 0; i < len; i++)
-		sprintf(s + (i * 2), "%02x", (unsigned int) p[i]);
+void bin2hex(char *out, const void *in, size_t len)
+{
+	const unsigned char *p = in;
+	while (len--)
+	{
+		(out++)[0] = _hexchars[p[0] >> 4];
+		(out++)[0] = _hexchars[p[0] & 0xf];
+		++p;
+	}
+	out[0] = '\0';
+}
 
 
-	return s;
+static inline
+int _hex2bin_char(const char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return (c - 'a') + 10;
+	if (c >= 'A' && c <= 'F')
+		return (c - 'A') + 10;
+	return -1;
 }
 }
 
 
 /* Does the reverse of bin2hex but does not allocate any ram */
 /* Does the reverse of bin2hex but does not allocate any ram */
 bool hex2bin(unsigned char *p, const char *hexstr, size_t len)
 bool hex2bin(unsigned char *p, const char *hexstr, size_t len)
 {
 {
-	bool ret = false;
-
-	while (*hexstr && len) {
-		char hex_byte[4];
-		unsigned int v;
-
-		if (unlikely(!hexstr[1])) {
-			applog(LOG_ERR, "hex2bin str truncated");
-			return ret;
-		}
-
-		memset(hex_byte, 0, 4);
-		hex_byte[0] = hexstr[0];
-		hex_byte[1] = hexstr[1];
-
-		if (unlikely(sscanf(hex_byte, "%x", &v) != 1)) {
-			applog(LOG_ERR, "hex2bin sscanf '%s' failed", hex_byte);
-			return ret;
+	int n, o;
+	
+	while (len--)
+	{
+		n = _hex2bin_char((hexstr++)[0]);
+		if (unlikely(n == -1))
+		{
+badchar:
+			if (!hexstr[-1])
+				applog(LOG_ERR, "hex2bin: str truncated");
+			else
+				applog(LOG_ERR, "hex2bin: invalid character 0x%02x", (int)hexstr[-1]);
+			return false;
 		}
 		}
-
-		*p = (unsigned char) v;
-
-		p++;
-		hexstr += 2;
-		len--;
+		o = _hex2bin_char((hexstr++)[0]);
+		if (unlikely(o == -1))
+			goto badchar;
+		(p++)[0] = (n << 4) | o;
 	}
 	}
-
-	if (likely(len == 0 && *hexstr == 0))
-		ret = true;
-	return ret;
+	
+	return likely(!hexstr[0]);
 }
 }
 
 
 void hash_data(unsigned char *out_hash, const unsigned char *data)
 void hash_data(unsigned char *out_hash, const unsigned char *data)
@@ -779,24 +774,22 @@ bool hash_target_check_v(const unsigned char *hash, const unsigned char *target)
 
 
 	if (opt_debug) {
 	if (opt_debug) {
 		unsigned char hash_swap[32], target_swap[32];
 		unsigned char hash_swap[32], target_swap[32];
-		char *hash_str, *target_str;
+		char hash_str[65];
+		char target_str[65];
 
 
 		for (int i = 0; i < 32; ++i) {
 		for (int i = 0; i < 32; ++i) {
 			hash_swap[i] = hash[31-i];
 			hash_swap[i] = hash[31-i];
 			target_swap[i] = target[31-i];
 			target_swap[i] = target[31-i];
 		}
 		}
 
 
-		hash_str = bin2hex(hash_swap, 32);
-		target_str = bin2hex(target_swap, 32);
+		bin2hex(hash_str, hash_swap, 32);
+		bin2hex(target_str, target_swap, 32);
 
 
 		applog(LOG_DEBUG, " Proof: %s\nTarget: %s\nTrgVal? %s",
 		applog(LOG_DEBUG, " Proof: %s\nTarget: %s\nTrgVal? %s",
 			hash_str,
 			hash_str,
 			target_str,
 			target_str,
 			rc ? "YES (hash <= target)" :
 			rc ? "YES (hash <= target)" :
 			     "no (false positive; hash > target)");
 			     "no (false positive; hash > target)");
-
-		free(hash_str);
-		free(target_str);
 	}
 	}
 
 
 	return rc;
 	return rc;
@@ -1383,9 +1376,9 @@ char *recv_line(struct pool *pool)
 			if (n < 0) {
 			if (n < 0) {
 				//Save errno from being overweitten bei socket_ commands 
 				//Save errno from being overweitten bei socket_ commands 
 				int socket_recv_errno;
 				int socket_recv_errno;
-				socket_recv_errno = errno;
-				if (!sock_blocks() || !socket_full(pool, false)) {
-					applog(LOG_DEBUG, "Failed to recv sock in recv_line: %d", socket_recv_errno);
+				socket_recv_errno = SOCKERR;
+				if (!sock_blocks() || !socket_full(pool, true)) {
+					applog(LOG_DEBUG, "Failed to recv sock in recv_line: %s", bfg_strerror(socket_recv_errno, BST_SOCKET));
 					suspend_stratum(pool);
 					suspend_stratum(pool);
 					break;
 					break;
 				}
 				}
@@ -1520,6 +1513,7 @@ static bool parse_notify(struct pool *pool, json_t *val)
 	char *job_id, *prev_hash, *coinbase1, *coinbase2, *bbversion, *nbit, *ntime;
 	char *job_id, *prev_hash, *coinbase1, *coinbase2, *bbversion, *nbit, *ntime;
 	bool clean, ret = false;
 	bool clean, ret = false;
 	int merkles, i;
 	int merkles, i;
+	size_t cb1_len, cb2_len;
 	json_t *arr;
 	json_t *arr;
 
 
 	arr = json_array_get(val, 4);
 	arr = json_array_get(val, 4);
@@ -1527,86 +1521,65 @@ static bool parse_notify(struct pool *pool, json_t *val)
 		goto out;
 		goto out;
 
 
 	merkles = json_array_size(arr);
 	merkles = json_array_size(arr);
+	for (i = 0; i < merkles; i++)
+		if (!json_is_string(json_array_get(arr, i)))
+			goto out;
 
 
-	job_id = json_array_string(val, 0);
-	prev_hash = json_array_string(val, 1);
-	coinbase1 = json_array_string(val, 2);
-	coinbase2 = json_array_string(val, 3);
-	bbversion = json_array_string(val, 5);
-	nbit = json_array_string(val, 6);
-	ntime = json_array_string(val, 7);
+	prev_hash = __json_array_string(val, 1);
+	coinbase1 = __json_array_string(val, 2);
+	coinbase2 = __json_array_string(val, 3);
+	bbversion = __json_array_string(val, 5);
+	nbit = __json_array_string(val, 6);
+	ntime = __json_array_string(val, 7);
 	clean = json_is_true(json_array_get(val, 8));
 	clean = json_is_true(json_array_get(val, 8));
 
 
-	if (!job_id || !prev_hash || !coinbase1 || !coinbase2 || !bbversion || !nbit || !ntime) {
-		/* Annoying but we must not leak memory */
-		if (job_id)
-			free(job_id);
-		if (prev_hash)
-			free(prev_hash);
-		if (coinbase1)
-			free(coinbase1);
-		if (coinbase2)
-			free(coinbase2);
-		if (bbversion)
-			free(bbversion);
-		if (nbit)
-			free(nbit);
-		if (ntime)
-			free(ntime);
+	if (!prev_hash || !coinbase1 || !coinbase2 || !bbversion || !nbit || !ntime)
+		goto out;
+	
+	job_id = json_array_string(val, 0);
+	if (!job_id)
 		goto out;
 		goto out;
-	}
 
 
 	cg_wlock(&pool->data_lock);
 	cg_wlock(&pool->data_lock);
 	free(pool->swork.job_id);
 	free(pool->swork.job_id);
-	free(pool->swork.prev_hash);
-	free(pool->swork.coinbase1);
-	free(pool->swork.coinbase2);
-	free(pool->swork.bbversion);
-	free(pool->swork.nbit);
-	free(pool->swork.ntime);
 	pool->swork.job_id = job_id;
 	pool->swork.job_id = job_id;
-	pool->swork.prev_hash = prev_hash;
-	pool->swork.coinbase1 = coinbase1;
-	pool->swork.cb1_len = strlen(coinbase1) / 2;
-	pool->swork.coinbase2 = coinbase2;
-	pool->swork.cb2_len = strlen(coinbase2) / 2;
-	pool->swork.bbversion = bbversion;
-	pool->swork.nbit = nbit;
-	pool->swork.ntime = ntime;
 	pool->submit_old = !clean;
 	pool->submit_old = !clean;
 	pool->swork.clean = true;
 	pool->swork.clean = true;
-	pool->swork.cb_len = pool->swork.cb1_len + pool->n1_len + pool->n2size + pool->swork.cb2_len;
-
-	for (i = 0; i < pool->swork.merkles; i++)
-		free(pool->swork.merkle[i]);
-	if (merkles) {
-		pool->swork.merkle = realloc(pool->swork.merkle, sizeof(char *) * merkles + 1);
-		for (i = 0; i < merkles; i++)
-			pool->swork.merkle[i] = json_array_string(arr, i);
-	}
+	
+	hex2bin(&pool->swork.header1[0], bbversion,  4);
+	hex2bin(&pool->swork.header1[4], prev_hash, 32);
+	hex2bin(&pool->swork.ntime[0], ntime, 4);
+	hex2bin(&pool->swork.diffbits[0], nbit, 4);
+	
+	cb1_len = strlen(coinbase1) / 2;
+	pool->swork.nonce2_offset = cb1_len + pool->n1_len;
+	cb2_len = strlen(coinbase2) / 2;
+
+	bytes_resize(&pool->swork.coinbase, pool->swork.nonce2_offset + pool->n2size + cb2_len);
+	uint8_t *coinbase = bytes_buf(&pool->swork.coinbase);
+	hex2bin(coinbase, coinbase1, cb1_len);
+	hex2bin(&coinbase[cb1_len], pool->nonce1, pool->n1_len);
+	// NOTE: gap for nonce2, filled at work generation time
+	hex2bin(&coinbase[pool->swork.nonce2_offset + pool->n2size], coinbase2, cb2_len);
+	
+	bytes_resize(&pool->swork.merkle_bin, 32 * merkles);
+	for (i = 0; i < merkles; i++)
+		hex2bin(&bytes_buf(&pool->swork.merkle_bin)[i * 32], json_string_value(json_array_get(arr, i)), 32);
 	pool->swork.merkles = merkles;
 	pool->swork.merkles = merkles;
 	if (clean)
 	if (clean)
 		pool->nonce2 = 0;
 		pool->nonce2 = 0;
-	pool->swork.header_len = strlen(pool->swork.bbversion) +
-				 strlen(pool->swork.prev_hash) +
-				 strlen(pool->swork.ntime) +
-				 strlen(pool->swork.nbit) +
-	/* merkle_hash */	 32 +
-	/* nonce */		 8 +
-	/* workpadding */	 96;
-	pool->swork.header_len = pool->swork.header_len * 2 + 1;
-	align_len(&pool->swork.header_len);
 	cg_wunlock(&pool->data_lock);
 	cg_wunlock(&pool->data_lock);
 
 
 	applog(LOG_DEBUG, "Received stratum notify from pool %u with job_id=%s",
 	applog(LOG_DEBUG, "Received stratum notify from pool %u with job_id=%s",
 	       pool->pool_no, job_id);
 	       pool->pool_no, job_id);
-	if (opt_protocol) {
+	if (opt_debug && opt_protocol)
+	{
 		applog(LOG_DEBUG, "job_id: %s", job_id);
 		applog(LOG_DEBUG, "job_id: %s", job_id);
 		applog(LOG_DEBUG, "prev_hash: %s", prev_hash);
 		applog(LOG_DEBUG, "prev_hash: %s", prev_hash);
 		applog(LOG_DEBUG, "coinbase1: %s", coinbase1);
 		applog(LOG_DEBUG, "coinbase1: %s", coinbase1);
 		applog(LOG_DEBUG, "coinbase2: %s", coinbase2);
 		applog(LOG_DEBUG, "coinbase2: %s", coinbase2);
 		for (i = 0; i < merkles; i++)
 		for (i = 0; i < merkles; i++)
-			applog(LOG_DEBUG, "merkle%d: %s", i, pool->swork.merkle[i]);
+			applog(LOG_DEBUG, "merkle%d: %s", i, json_string_value(json_array_get(arr, i)));
 		applog(LOG_DEBUG, "bbversion: %s", bbversion);
 		applog(LOG_DEBUG, "bbversion: %s", bbversion);
 		applog(LOG_DEBUG, "nbit: %s", nbit);
 		applog(LOG_DEBUG, "nbit: %s", nbit);
 		applog(LOG_DEBUG, "ntime: %s", ntime);
 		applog(LOG_DEBUG, "ntime: %s", ntime);
@@ -2075,6 +2048,10 @@ resend:
 	pool->nonce1 = nonce1;
 	pool->nonce1 = nonce1;
 	pool->n1_len = strlen(nonce1) / 2;
 	pool->n1_len = strlen(nonce1) / 2;
 	pool->n2size = n2size;
 	pool->n2size = n2size;
+	pool->nonce2sz  = (n2size > sizeof(pool->nonce2)) ? sizeof(pool->nonce2) : n2size;
+#ifdef WORDS_BIGENDIAN
+	pool->nonce2off = (n2size < sizeof(pool->nonce2)) ? (sizeof(pool->nonce2) - n2size) : 0;
+#endif
 	cg_wunlock(&pool->data_lock);
 	cg_wunlock(&pool->data_lock);
 
 
 	if (sessionid)
 	if (sessionid)
@@ -2239,26 +2216,160 @@ void RenameThread(const char* name)
 #endif
 #endif
 }
 }
 
 
+static pthread_key_t key_bfgtls;
+struct bfgtls_data {
+	char *bfg_strerror_result;
+	size_t bfg_strerror_resultsz;
 #ifdef WIN32
 #ifdef WIN32
-static const char *WindowsErrorStr(DWORD dwMessageId)
-{
-	static LPSTR msg = NULL;
-	if (msg)
-		LocalFree(msg);
-	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, dwMessageId, 0, (LPSTR)&msg, 0, 0))
-		return msg;
-	static const char fmt[] = "Error #%ld";
-	signed long ldMsgId = dwMessageId;
-	int sz = snprintf((char*)&sz, 0, fmt, ldMsgId) + 1;
-	msg = (LPTSTR)LocalAlloc(LMEM_FIXED, sz);
-	sprintf((char*)msg, fmt, ldMsgId);
-	return msg;
+	LPSTR bfg_strerror_socketresult;
+#endif
+};
+
+static
+struct bfgtls_data *get_bfgtls()
+{
+	struct bfgtls_data *bfgtls = pthread_getspecific(key_bfgtls);
+	if (bfgtls)
+		return bfgtls;
+	
+	void *p;
+	
+	bfgtls = malloc(sizeof(*bfgtls));
+	if (!bfgtls)
+		quit(1, "malloc bfgtls failed");
+	p = malloc(64);
+	if (!p)
+		quit(1, "malloc bfg_strerror_result failed");
+	*bfgtls = (struct bfgtls_data){
+		.bfg_strerror_resultsz = 64,
+		.bfg_strerror_result = p,
+	};
+	if (pthread_setspecific(key_bfgtls, bfgtls))
+		quit(1, "pthread_setspecific failed");
+	
+	return bfgtls;
+}
+
+void bfg_init_threadlocal()
+{
+	if (pthread_key_create(&key_bfgtls, NULL))
+		quit(1, "pthread_key_create failed");
+}
+
+static
+bool bfg_grow_buffer(char ** const bufp, size_t * const bufszp, size_t minimum)
+{
+	if (minimum <= *bufszp)
+		return false;
+	
+	while (minimum > *bufszp)
+		*bufszp = 2;
+	*bufp = realloc(*bufp, *bufszp);
+	if (unlikely(!*bufp))
+		quit(1, "realloc failed in bfg_grow_buffer");
+	
+	return true;
 }
 }
+
+static
+const char *bfg_strcpy_growing_buffer(char ** const bufp, size_t * const bufszp, const char *src)
+{
+	if (!src)
+		return NULL;
+	
+	const size_t srcsz = strlen(src) + 1;
+	
+	bfg_grow_buffer(bufp, bufszp, srcsz);
+	memcpy(*bufp, src, srcsz);
+	
+	return *bufp;
+}
+
+// Guaranteed to always return some string (or quit)
+const char *bfg_strerror(int e, enum bfg_strerror_type type)
+{
+	static __maybe_unused pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+	struct bfgtls_data *bfgtls = get_bfgtls();
+	size_t * const bufszp = &bfgtls->bfg_strerror_resultsz;
+	char ** const bufp = &bfgtls->bfg_strerror_result;
+	const char *have = NULL;
+	
+	switch (type) {
+		case BST_LIBUSB:
+// NOTE: Nested preprocessor checks since the latter isn't defined at all without the former
+#ifdef HAVE_LIBUSB
+#	if HAVE_DECL_LIBUSB_ERROR_NAME
+			// libusb makes no guarantees for thread-safety or persistence
+			mutex_lock(&mutex);
+			have = bfg_strcpy_growing_buffer(bufp, bufszp, libusb_error_name(e));
+			mutex_unlock(&mutex);
+#	endif
 #endif
 #endif
+			break;
+		case BST_SOCKET:
+		{
+#ifdef WIN32
+			// Windows has a different namespace for socket errors
+			LPSTR *msg = &bfgtls->bfg_strerror_socketresult;
+			if (*msg)
+				LocalFree(*msg);
+			if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0, e, 0, (LPSTR)msg, 0, 0))
+				return *msg;
+			*msg = NULL;
+			
+			break;
+#endif
+		}
+			// Fallthru on non-WIN32
+		case BST_ERRNO:
+		{
+#ifdef __STRERROR_S_WORKS
+			// FIXME: Not sure how to get this on MingW64
+retry:
+			if (likely(!strerror_s(*bufp, *bufszp, e)))
+			{
+				if (bfg_grow_buffer(bufp, bufszp, strlen(*bufp) + 2))
+					goto retry;
+				return *bufp;
+			}
+// TODO: XSI strerror_r
+// TODO: GNU strerror_r
+#else
+			mutex_lock(&mutex);
+			have = bfg_strcpy_growing_buffer(bufp, bufszp, strerror(e));
+			mutex_unlock(&mutex);
+#endif
+		}
+	}
+	
+	if (have)
+		return *bufp;
+	
+	// Failback: Stringify the number
+	static const char fmt[] = "%s error #%d", *typestr;
+	switch (type) {
+		case BST_ERRNO:
+			typestr = "System";
+			break;
+		case BST_SOCKET:
+			typestr = "Socket";
+			break;
+		case BST_LIBUSB:
+			typestr = "libusb";
+			break;
+		default:
+			typestr = "Unexpected";
+	}
+	int sz = snprintf((char*)bfgtls, 0, fmt, typestr, e) + 1;
+	bfg_grow_buffer(bufp, bufszp, sz);
+	sprintf(*bufp, fmt, typestr, e);
+	return *bufp;
+}
 
 
 void notifier_init(notifier_t pipefd)
 void notifier_init(notifier_t pipefd)
 {
 {
 #ifdef WIN32
 #ifdef WIN32
+#define WindowsErrorStr(e)  bfg_strerror(e, true)
 	SOCKET listener, connecter, acceptor;
 	SOCKET listener, connecter, acceptor;
 	listener = socket(AF_INET, SOCK_STREAM, 0);
 	listener = socket(AF_INET, SOCK_STREAM, 0);
 	if (listener == INVALID_SOCKET)
 	if (listener == INVALID_SOCKET)
@@ -2332,3 +2443,8 @@ void notifier_destroy(notifier_t fd)
 #endif
 #endif
 	fd[0] = fd[1] = INVSOCK;
 	fd[0] = fd[1] = INVSOCK;
 }
 }
+
+void _bytes_alloc_failure(size_t sz)
+{
+	quit(1, "bytes_resize failed to allocate %lu bytes", (unsigned long)sz);
+}

+ 96 - 3
util.h

@@ -30,7 +30,8 @@
 	#define INVINETADDR -1
 	#define INVINETADDR -1
 	#define CLOSESOCKET close
 	#define CLOSESOCKET close
 
 
-	#define SOCKERRMSG strerror(errno)
+	#define SOCKERR (errno)
+	#define SOCKERRMSG bfg_strerror(errno, BST_SOCKET)
 	static inline bool sock_blocks(void)
 	static inline bool sock_blocks(void)
 	{
 	{
 		return (errno == EAGAIN || errno == EWOULDBLOCK);
 		return (errno == EAGAIN || errno == EWOULDBLOCK);
@@ -45,8 +46,8 @@
 	#define INVINETADDR INADDR_NONE
 	#define INVINETADDR INADDR_NONE
 	#define CLOSESOCKET closesocket
 	#define CLOSESOCKET closesocket
 
 
-	extern char *WSAErrorMsg(void);
-	#define SOCKERRMSG WSAErrorMsg()
+	#define SOCKERR (WSAGetLastError())
+	#define SOCKERRMSG bfg_strerror(WSAGetLastError(), BST_SOCKET)
 
 
 	static inline bool sock_blocks(void)
 	static inline bool sock_blocks(void)
 	{
 	{
@@ -111,6 +112,13 @@ void *realloc_strcat(char *ptr, char *s);
 extern char *sanestr(char *o, char *s);
 extern char *sanestr(char *o, char *s);
 void RenameThread(const char* name);
 void RenameThread(const char* name);
 
 
+enum bfg_strerror_type {
+	BST_ERRNO,
+	BST_SOCKET,
+	BST_LIBUSB,
+};
+extern const char *bfg_strerror(int, enum bfg_strerror_type);
+
 typedef SOCKETTYPE notifier_t[2];
 typedef SOCKETTYPE notifier_t[2];
 extern void notifier_init(notifier_t);
 extern void notifier_init(notifier_t);
 extern void notifier_wake(notifier_t);
 extern void notifier_wake(notifier_t);
@@ -125,6 +133,69 @@ static inline void align_len(size_t *len)
 }
 }
 
 
 
 
+typedef struct bytes_t {
+	uint8_t *buf;
+	size_t sz;
+	size_t allocsz;
+} bytes_t;
+
+// This can't be inline without ugly const/non-const issues
+#define bytes_buf(b)  ((b)->buf)
+
+static inline
+size_t bytes_len(const bytes_t *b)
+{
+	return b->sz;
+}
+
+extern void _bytes_alloc_failure(size_t);
+
+static inline
+void bytes_resize(bytes_t *b, size_t newsz)
+{
+	b->sz = newsz;
+	if (newsz <= b->allocsz)
+		return;
+	
+	if (!b->allocsz)
+		b->allocsz = 0x10;
+	do {
+		b->allocsz *= 2;
+	} while (newsz > b->allocsz);
+	b->buf = realloc(b->buf, b->allocsz);
+	if (!b->buf)
+		_bytes_alloc_failure(b->allocsz);
+}
+
+static inline
+void bytes_cat(bytes_t *b, const bytes_t *cat)
+{
+	size_t origsz = bytes_len(b);
+	size_t addsz = bytes_len(cat);
+	bytes_resize(b, origsz + addsz);
+	memcpy(&bytes_buf(b)[origsz], bytes_buf(cat), addsz);
+}
+
+static inline
+void bytes_cpy(bytes_t *dst, const bytes_t *src)
+{
+	dst->allocsz = src->allocsz;
+	dst->sz = src->sz;
+	size_t half;
+	while (dst->sz <= (half = dst->allocsz / 2))
+		dst->allocsz = half;
+	dst->buf = malloc(dst->allocsz);
+	memcpy(dst->buf, src->buf, dst->sz);
+}
+
+static inline
+void bytes_free(bytes_t *b)
+{
+	free(b->buf);
+	b->sz = b->allocsz = 0;
+}
+
+
 static inline
 static inline
 void set_maxfd(int *p_maxfd, int fd)
 void set_maxfd(int *p_maxfd, int fd)
 {
 {
@@ -181,4 +252,26 @@ struct timeval *select_timeout(struct timeval *tvp_timeout, struct timeval *tvp_
 }
 }
 
 
 
 
+#define RUNONCE(rv)  do {  \
+	static bool _runonce = false;  \
+	if (_runonce)  \
+		return rv;  \
+	_runonce = true;  \
+} while(0)
+
+
+static inline
+char *maybe_strdup(const char *s)
+{
+	return s ? strdup(s) : NULL;
+}
+
+static inline
+void maybe_strdup_if_null(const char **p, const char *s)
+{
+	if (!*p)
+		*p = maybe_strdup(s);
+}
+
+
 #endif /* __UTIL_H__ */
 #endif /* __UTIL_H__ */

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