Browse Source

Merge tag 'bfgminer-3.1.4' into bigpic

BFGMiner version 3.1.4
Luke Dashjr 12 years ago
parent
commit
caaf00ea5a
33 changed files with 1602 additions and 537 deletions
  1. 143 0
      NEWS
  2. 37 34
      README
  3. 9 1
      README.RPC
  4. 2 2
      adl.c
  5. 4 4
      api.c
  6. 4 1
      compat.h
  7. 39 8
      configure.ac
  8. 16 0
      debian/changelog
  9. 1 1
      debian/control
  10. 119 13
      deviceapi.c
  11. 21 0
      deviceapi.h
  12. 3 5
      driver-avalon.c
  13. 69 6
      driver-bitforce.c
  14. 3 3
      driver-cpu.c
  15. 21 2
      driver-erupter.c
  16. 111 26
      driver-icarus.c
  17. 76 22
      driver-modminer.c
  18. 5 9
      driver-opencl.c
  19. 107 29
      driver-x6500.c
  20. 3 5
      driver-ztex.c
  21. 1 1
      findnonce.c
  22. 54 130
      fpgautils.c
  23. 3 19
      fpgautils.h
  24. 1 1
      ft232r.c
  25. 3 0
      icarus-common.h
  26. 37 44
      logging.c
  27. 434 127
      miner.c
  28. 32 6
      miner.h
  29. 7 1
      miner.php
  30. 1 1
      ocl.c
  31. 1 1
      openwrt/bfgminer/Makefile
  32. 160 27
      util.c
  33. 75 8
      util.h

+ 143 - 0
NEWS

@@ -1,3 +1,146 @@
+BFGMiner Version 3.1.4 - August 2, 2013
+- Windows: Rebuild pdcurses with UTF-8 and wide character support
+- Bugfix: Avoid using wide curses symbols/macros when USE_UNICODE is not defined
+- Unicode: Use line drawing in TUI Help
+- Use bfg_waddstr even with Unicode disabled, since it's needed for red
+highlight
+- Colour bad conditions in red
+- Unicode: Cross-tee intersecting lines
+- Unicode: Use WACS_VLINE for vertical lines
+- Unicode: If degrees symbol is available, add it to temperatures
+- Unicode: bfg_waddstr wrapper to handle non-ASCII characters, currently used
+only by logging and statlines
+- Unicode: Use WACS_HLINE for horizontal lines
+- Add framework for using Unicode in TUI (can be disabled with --no-unicode)
+- Avoid using potentially locale-dependent ctype functions in locale-independent
+contexts
+- Refactor temperature in TUI statlines to share code nicer
+- Bugfix: avalon: Fix applog formatting
+- Bugfix: Align totals columns in per-processor view
+- Bugfix: Fix curses-less build
+- configure: Workaround buggy autoconf versions
+- Bugfix: erupter: Include headers in order necessary for Windows
+- Bugfix: Reimplement get_intrange using strtol instead of sscanf (which is
+broken on Windows)
+- Bugfix: get_intrange: Check for extra garbage at the end, only after we know
+we have an end-position
+- Bugfix: Fix Enter key in TUI on Windows
+- erupter: Split identify-handling logic into handle_identify function
+- Bugfix: erupter: Ensure identify is handled during no-once or firstrun
+- erupter: After identify, check if a work restart is needed immediately
+- erupter: Implement identify function by pausing hashing for 3 seconds
+- Bugfix: icarus: Remember firstrun state in case it gets changed for the next
+run
+- icarus: Move actual dynclock updates to icarus_job_start
+- icarus: Split out icarus_job_prepare, and rename icarus_job_start
+- Bugfix: ZeroStats: Reset column widths to 1
+- miner.php: Include max temperature in device totals line
+- Bugfix: Stratum Fix debug logging of initial mining.subscribe command
+- Bugfix: Call pool_set_opaque from work_decode, so block content hiding/
+providing messages work for getwork/GBT
+- Split block contents hiding/providing notices out from stratum code
+- Add test suite for get_intrange
+- Bugfix: Check for error conditions in get_intrange to not have weird --device
+behaviour when bad values are provided
+- Bugfix: erupter: Take advantage of detectone_meta_info to handle Emerald
+autodetection
+- TUI Help describing the various status fields (contributed by midnightmagic)
+- Bugfix: ManageTUI: Allow 'I' key to be used by devices not supporting identify
+- Bugfix: Prefer Sapphire over Emerald for -S erupter:*
+- Bugfix: Clear total_bad_nonces when zeroing statistics
+- Bugfix: modminer: Since we are not searching iManuf string for needles, only
+look for "ModMiner"
+- Bugfix: sysfs autodetect: Recurse into tty/ subdirectory (necessary for
+CDC/ACM ttys)
+- sysfs autodetect: Split tty* directory search into new _sysfs_find_tty
+function
+- modminer: Reduce default clock to 190 MHz
+- README: Update driver info to include Erupter driver
+- README: FAQ about scrypt and difficulty
+- Include count of working devices/processors in totals statline
+- Format totals statline the same way as individual device/processor statlines
+- Rearrange TUI a bit, including menu at the top (+1 log line) and hashrate
+total closer to device summaries
+- Bugfix: setup_stratum_curl: Need to release stratum lock on connection failure
+too
+- Bugfix: Avoid unnecessary locks inside curses_print_status, which is called
+with the console lock held
+- Bugfix: setup_stratum_curl: Hold stratum lock until connection completes, to
+avoid potential races
+- Bugfix: stratum_works: If stratum is already active, it works (avoid trying to
+initialise it again)
+- Replace hashrate_to_bufstr/ti_hashrate_bufstr with format_unit/
+multi_format_unit_array
+- New multi_format_unit_array to fill multiple buffers instead of building a
+delimited string
+- multi_format_unit: Skip recounting length of fixed-length strings
+- Shrink status line to fit in 80 columns
+- Add network bandwidth rate to TUI
+- New multi_format_unit variadic macro to handle formatting multiple numbers at
+once
+- format_unit: Option to choose 3-digit integer display vs 5-character floating-
+point display
+- Optimization: format_unit: Handle number first, to avoid having to restore
+suffix later
+- Generalise hashrate_pick_unit/hashrate_to_bufstr into pick_unit/format_unit
+- Extend hashrate_pick_unit/hashrate_to_bufstr to handle sub-kilo units
+- Split total_bytes_xfer to total_bytes_rcvd and total_bytes_sent
+- Bugfix: _decode_udev_enc_dup: Allocate enough space for full string
+- Bugfix: Never use waddstr for logwin, since it would bypass special newline
+handling
+- Bugfix: bitforce: Set kname on chip processors
+- bitforce: Include voltages in Manage device TUI
+- Defer newlines going to curses logwin, to avoid a useless blank line at the
+bottom of the window
+- Ensure printing to logwin always goes through _wlog
+- Remove blank line above log window
+- bitforce: Identify parallel queue protocol distinctly from mere bulk queue
+- ManageTUI: Include kernel name, when available
+- Stratum: Roll ntime as we generate work
+- Stratum: Make swork.ntime native-endian
+- Stratum: Treat ntime as uint32_t (as it should be), still always big endian
+- Debuglog ManageTUI actions/responses
+- ManageTUI: Add generic Identify support
+- Bugfix: Move serial_detect* and open_bitstream to DevAPI code so CPU/OpenCL
+can build properly without fpgautils
+- Short-circuit logging sooner in quiet mode
+- Write to both stderr and console within same console lock "session"
+- Bugfix: Also hold the console lock when writing to stderr
+- Use common console locking function for stdout in logging.c
+- Move console lock and unlock functions (which also handle thread cancelstate)
+to miner.h
+- Bugfix: bitforce: Only try to clear queues of SC devices, since FPGA MR boards
+interpret ZQX/ZOX differently
+- Timer-based gettimeofday substitute for systems with poor time-of-day clocks
+(Windows)
+- Use clock_gettime(CLOCK_MONOTONIC) for timers when available
+- Use QueryPerformanceCounter for timers on Windows
+- Generic refactoring for timer_set_now
+- Replace all remaining uses of gettimeofday for timers, with timer_set_now (aka
+cgtime)
+- Don't mix timers with timestamps (visual only)
+- Always use struct timeval for timers, and don't mix timers with timestamps
+(functional only)
+- get_datestamp: Change timeval parameter to time_t, and implement
+get_now_datestamp for common "current time" use case
+- Use get_datestamp for (non-microsecond) log timestamps
+- Bugfix: ztex: Allocate final processor names on the heap, so they survive when
+the stack for ztex_prepare is gone
+- Bugfix: ztex: Copy serial number to device "name" before cloning it for other
+processors
+- Bugfix: x6500: Use cgpu->temp directly since there is only one sensor per
+processor
+- Bugfix: Actually show the highest temperature, not just calculate it
+- x6500: Allow changing clock speed from TUI Manage device
+- x6500: Port pgaset clock from modminer driver at
+66d2a3ab072fcdbc3c7ed41a97f265afa917bbee
+- modminer: Allow changing clock speed from TUI Manage device
+- bitforce: Flush job and result queues at startup to avoid unnecessary warnings
+- x6500: Reduce default clock to 190 MHz
+- Bugfix: fpgautils: Close libusb handle after copying USB strings
+- use BSD sed syntax to generate iospeed_local.h
+
+
 BFGMiner Version 3.1.3 - July 11, 2013
 BFGMiner Version 3.1.3 - July 11, 2013
 - Bugfix: Reset staged_full flag when discarding (stale) popped work, or
 - Bugfix: Reset staged_full flag when discarding (stale) popped work, or
 increasing the queue minimum
 increasing the queue minimum

+ 37 - 34
README

@@ -327,7 +327,7 @@ WHILE RUNNING:
 
 
 The following options are available while running with a single keypress:
 The following options are available while running with a single keypress:
 
 
-[M]anage devices [P]ool management [S]ettings [D]isplay options [Q]uit
+[M]anage devices [P]ool management [S]ettings [D]isplay options  [H]elp [Q]uit
 
 
 M gives you something like:
 M gives you something like:
 
 
@@ -392,49 +392,44 @@ dedicated to this program,
 	https://bitcointalk.org/?topic=78192
 	https://bitcointalk.org/?topic=78192
 	https://bitcointalk.org/?topic=168174
 	https://bitcointalk.org/?topic=168174
 
 
-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/.81%
+The block display shows:
+Block: ...1b89f8d3 #217364  Diff:7.67M (54.93Th/s)  Started: [17:17:22]
 
 
-Each column is as follows:
-5s:  A 5 second exponentially decaying average hash rate
-avg: An all time average hash rate
-u:   An all time average hash rate based on actual accepted shares
-A:   The number of Accepted shares
-R:   The number of Rejected shares, stale shares discarded (never submitted),
-     and the percentage these are of total found.
-HW:  The number of HardWare errors, and percentage invalid of nonces returned
+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
+the search for the new block started.
 
 
 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  F:0  NB:1  AS:0  BW:[ 75/241 B/s]  E:2.42  U:22.53/m  BS:2.71k
 
 
 ST is STaged work items (ready to use).
 ST is STaged work items (ready to use).
-GF is Getwork Fail Occasions (server slow to provide work)
+F  is network Failure occasions (server down or slow to provide work)
 NB is New Blocks detected on the network
 NB is New Blocks detected on the network
 AS is Active Submissions (shares in the process of submitting)
 AS is Active Submissions (shares in the process of submitting)
-RF is Remote Fail occasions (server slow to accept work)
+BW is BandWidth usage on the network
 E  is Efficiency defined as number of shares accepted (multiplied by their
 E  is Efficiency defined as number of shares accepted (multiplied by their
           difficulty) per 2 KB of bandwidth
           difficulty) per 2 KB of bandwidth
 U  is Utility defined as the number of shares / minute
 U  is Utility defined as the number of shares / minute
 BS is the all time Best Share difficulty you've found
 BS is the all time Best Share difficulty you've found
 
 
-The block display shows:
-Block: ...1b89f8d3 #217364  Diff:7.67M (54.93Th/s)  Started: [17:17:22]
+The totals line shows the following:
+ 6/32   75.0C | 171.3/170.8/171.2Gh/s | A:729 R:8+0(.01%) HW:0/.81%
 
 
-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
-the search for the new block started.
+Each column is as follows:
+  The number of devices and processors currently mining
+  Hottest temperature reported by any processor
+  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 stale shares discarded (never submitted),
+      and the percentage these are of total found.
+  The number of HardWare errors, and percentage invalid of nonces returned
 
 
 Each device shows:
 Each device shows:
  BFL 2: 74.0C | 51.97/58.90/57.17Gh/s | A:847 R:15+0(.54%) HW:496/.91%
  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
+Columns are the same as in the totals line.
 
 
 
 
 ---
 ---
@@ -694,13 +689,15 @@ performance per unit power due to being dedicated to only one purpose.
 Q: How do I get my BFL/Icarus/Lancelot/Cairnsmore device to auto-recognise?
 Q: How do I get my BFL/Icarus/Lancelot/Cairnsmore device to auto-recognise?
 A: On Linux, if the /dev/ttyUSB* devices don't automatically appear, the only
 A: On Linux, if the /dev/ttyUSB* devices don't automatically appear, the only
 thing that needs to be done is to load the driver for them:
 thing that needs to be done is to load the driver for them:
-BFL: sudo modprobe ftdi_sio vendor=0x0403 product=0x6014
-Icarus: sudo modprobe pl2303 vendor=0x067b product=0x230
-Lancelot: sudo modprobe ftdi_sio vendor=0x0403 product=0x6001
-Cairnsmore: sudo modprobe ftdi_sio product=0x8350 vendor=0x0403
-On windows you must install the pl2303 or ftdi driver required for the device
-pl2303: http://prolificusa.com/pl-2303hx-drivers/
-ftdi: http://www.ftdichip.com/Drivers/VCP.htm
+  BitForce:   sudo modprobe ftdi_sio vendor=0x0403 product=0x6014
+  Erupter:    sudo modprobe cp210x   vendor=0x10c4 product=0xea60
+  Icarus:     sudo modprobe pl2303   vendor=0x067b product=0x0230
+  Lancelot:   sudo modprobe ftdi_sio vendor=0x0403 product=0x6001
+  Cairnsmore: sudo modprobe ftdi_sio vendor=0x0403 product=0x8350
+On Windows, you must install the driver required for the device:
+  FTDI:       http://www.ftdichip.com/Drivers/VCP.htm
+  Erupter:    http://www.silabs.com/products/mcu/pages/usbtouartbridgevcpdrivers.aspx
+  Icarus:     http://prolificusa.com/pl-2303hx-drivers/
 
 
 Q: On Linux I can see the /dev/ttyUSB* devices for my ICA/BFL/MMQ FPGA, but
 Q: On Linux I can see the /dev/ttyUSB* devices for my ICA/BFL/MMQ FPGA, but
 BFGMiner can't mine on them
 BFGMiner can't mine on them
@@ -717,6 +714,12 @@ Then logout and back in again
 Q: Can I mine scrypt with FPGAs or ASICs?
 Q: Can I mine scrypt with FPGAs or ASICs?
 A: No.
 A: No.
 
 
+Q: Why does BFGMiner show difficulty 0 when mining scrypt?
+A: BFGMiner consistently uses pdiff measurement for difficulty everywhere,
+rather than other measurements that may exist. For scrypt, pdiff 1 is very
+difficult, and higher get exponentially harder. It is unlikely you will want to
+use pdiff 1+ with scrypt until you have FPGAs and/or ASICs for it.
+
 Q: What is stratum and how do I use it?
 Q: What is stratum and how do I use it?
 A: Stratum is a protocol designed to reduce resources for mining pools at the
 A: Stratum is a protocol designed to reduce resources for mining pools at the
 cost of keeping the miner in the dark and blindly transferring his mining
 cost of keeping the miner in the dark and blindly transferring his mining

+ 9 - 1
README.RPC

@@ -351,7 +351,8 @@ The list of requests - a (*) means it requires privileged access - and replies a
                               help message about the options available
                               help message about the options available
 
 
                               The current options are:
                               The current options are:
-                               MMQ opt=clock val=2 to 230 (and a multiple of 2)
+                               MMQ opt=clock val=2 to 250 (and a multiple of 2)
+                               XBS opt=clock val=2 to 250 (and a multiple of 2)
 
 
  zero|Which,true/false (*)
  zero|Which,true/false (*)
                none           There is no reply section just the STATUS section
                none           There is no reply section just the STATUS section
@@ -414,6 +415,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.2
+
+Modified API commands:
+ 'pgaset' - added: XBS opt=clock val=2 to 250 (and a multiple of 2)
+
+----------
+
 API V1.25.1 (BFGMiner v3.1.2)
 API V1.25.1 (BFGMiner v3.1.2)
 
 
 Added API commands:
 Added API commands:

+ 2 - 2
adl.c

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

+ 4 - 4
api.c

@@ -3471,7 +3471,7 @@ static void setup_ipaccess()
 
 
 		group = NOPRIVGROUP;
 		group = NOPRIVGROUP;
 
 
-		if (isalpha(*ptr) && *(ptr+1) == ':') {
+		if (VALIDGROUP(*ptr) && *(ptr+1) == ':') {
 			if (DEFINEDGROUP(*ptr))
 			if (DEFINEDGROUP(*ptr))
 				group = GROUP(*ptr);
 				group = GROUP(*ptr);
 
 
@@ -3568,7 +3568,7 @@ void api(int api_thr_id)
 	int n, bound;
 	int n, bound;
 	char *connectaddr;
 	char *connectaddr;
 	const char *binderror;
 	const char *binderror;
-	time_t bindstart;
+	struct timeval bindstart;
 	short int port = opt_api_port;
 	short int port = opt_api_port;
 	struct sockaddr_in serv;
 	struct sockaddr_in serv;
 	struct sockaddr_in cli;
 	struct sockaddr_in cli;
@@ -3653,11 +3653,11 @@ void api(int api_thr_id)
 
 
 	// try for more than 1 minute ... in case the old one hasn't completely gone yet
 	// try for more than 1 minute ... in case the old one hasn't completely gone yet
 	bound = 0;
 	bound = 0;
-	bindstart = time(NULL);
+	cgtime(&bindstart);
 	while (bound == 0) {
 	while (bound == 0) {
 		if (SOCKETFAIL(bind(*apisock, (struct sockaddr *)(&serv), sizeof(serv)))) {
 		if (SOCKETFAIL(bind(*apisock, (struct sockaddr *)(&serv), sizeof(serv)))) {
 			binderror = SOCKERRMSG;
 			binderror = SOCKERRMSG;
-			if ((time(NULL) - bindstart) > 61)
+			if (timer_elapsed(&bindstart, NULL) > 61)
 				break;
 				break;
 			else {
 			else {
 				applog(LOG_WARNING, "API bind to port %d failed - trying again in 30sec", port);
 				applog(LOG_WARNING, "API bind to port %d failed - trying again in 30sec", port);

+ 4 - 1
compat.h

@@ -85,7 +85,8 @@ struct tm *localtime_convert(time_t t)
 #endif
 #endif
 
 
 #ifndef HAVE_NANOSLEEP
 #ifndef HAVE_NANOSLEEP
-extern void cgtime(struct timeval *);
+extern void (*timer_set_now)(struct timeval *);
+#define cgtime(tvp)  timer_set_now(tvp)
 
 
 static inline int nanosleep(const struct timespec *req, struct timespec *rem)
 static inline int nanosleep(const struct timespec *req, struct timespec *rem)
 {
 {
@@ -118,6 +119,8 @@ static inline int nanosleep(const struct timespec *req, struct timespec *rem)
 	}
 	}
 	return 0;
 	return 0;
 }
 }
+
+#undef cgtime
 #endif
 #endif
 
 
 #ifdef WIN32
 #ifdef WIN32

+ 39 - 8
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], [3])
+m4_define([v_mic], [4])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 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))
@@ -145,6 +145,7 @@ m4_define([BFG_PREPROC_IFELSE],
 
 
 AC_CHECK_DECL([HASH_ITER],[
 AC_CHECK_DECL([HASH_ITER],[
 	AC_CHECK_DECL([DL_FOREACH_SAFE],[
 	AC_CHECK_DECL([DL_FOREACH_SAFE],[
+		true
 	],[
 	],[
 		AC_MSG_ERROR([Could not find DL_FOREACH_SAFE - install uthash-dev 1.9.2+])
 		AC_MSG_ERROR([Could not find DL_FOREACH_SAFE - install uthash-dev 1.9.2+])
 	],[
 	],[
@@ -204,7 +205,7 @@ m4_define([BFG_PTHREAD_FLAG_CHECK],
 				fi
 				fi
 				$2
 				$2
 				break 2
 				break 2
-			],[])
+			])
 		done
 		done
 	done
 	done
 	if test "x${found_pthread}" = "xfalse"; then
 	if test "x${found_pthread}" = "xfalse"; then
@@ -357,7 +358,7 @@ PKG_CHECK_MODULES([LIBUSB], [libusb-1.0],[
 		AC_CHECK_LIB($usb_lib, libusb_init, [
 		AC_CHECK_LIB($usb_lib, libusb_init, [
 			libusb=yes
 			libusb=yes
 			break
 			break
-		], [])
+		])
 	done
 	done
 	if test "x$libusb" = xyes; then
 	if test "x$libusb" = xyes; then
 			AC_CHECK_DECL([libusb_init],[
 			AC_CHECK_DECL([libusb_init],[
@@ -426,7 +427,7 @@ if test "x$libusb" = xyes; then
 	AC_DEFINE([HAVE_LIBUSB], [1], [Define if you have libusb-1.0])
 	AC_DEFINE([HAVE_LIBUSB], [1], [Define if you have libusb-1.0])
 	save_CFLAGS="$CFLAGS"
 	save_CFLAGS="$CFLAGS"
 	CFLAGS="$LIBUSB_CFLAGS $CFLAGS"
 	CFLAGS="$LIBUSB_CFLAGS $CFLAGS"
-	AC_CHECK_DECLS([libusb_error_name],[],[],[#include <libusb.h>])
+	AC_CHECK_DECLS([libusb_error_name],[true],[true],[#include <libusb.h>])
 	CFLAGS="$save_CFLAGS"
 	CFLAGS="$save_CFLAGS"
 fi
 fi
 
 
@@ -443,15 +444,16 @@ fi
 
 
 
 
 need_fpgautils=no
 need_fpgautils=no
-if test x$avalon$icarus$bitforce$modminer$opencl$x6500$ztex != xnonononononono; then
+if test x$avalon$icarus$bitforce$modminer$x6500$ztex != xnononononono; then
 	need_fpgautils=yes
 	need_fpgautils=yes
+	AC_DEFINE([HAVE_FPGAUTILS], [1], [Defined to 1 if fpgautils is being used])
 	
 	
 	if $have_win32; then
 	if $have_win32; then
 		echo '#include <iospeeds.h>' >iospeeds_local.h
 		echo '#include <iospeeds.h>' >iospeeds_local.h
 	else
 	else
 		AC_PROG_CPP
 		AC_PROG_CPP
 		AC_MSG_CHECKING([what baud rates your system supports])
 		AC_MSG_CHECKING([what baud rates your system supports])
-		echo '#include <termios.h>' | ${CPP} -dM - 2>/dev/null | sed 's/.* B\([0-9]\+\) .*/IOSPEED(\1)/;t;d' >iospeeds_local.h
+		echo '#include <termios.h>' | ${CPP} -dM - 2>/dev/null | sed 's/.*[ 	]B\([0-9][0-9]*\)[ 	].*/IOSPEED(\1)/' | grep IOSPEED >iospeeds_local.h
 		if grep -q IOSPEED iospeeds_local.h; then
 		if grep -q IOSPEED iospeeds_local.h; then
 			AC_MSG_RESULT([done])
 			AC_MSG_RESULT([done])
 		else
 		else
@@ -536,7 +538,7 @@ else
 fi
 fi
 
 
 
 
-AC_ARG_WITH([system-libblkmaker], [AC_HELP_STRING([--with-system-libblkmaker], [Use system libblkmaker rather than bundled one (default disabled)])],[],[with_system_libblkmaker=no])
+AC_ARG_WITH([system-libblkmaker], [AC_HELP_STRING([--with-system-libblkmaker], [Use system libblkmaker rather than bundled one (default disabled)])],[true],[with_system_libblkmaker=no])
 if test "x$with_system_libblkmaker" = "xyes"; then
 if test "x$with_system_libblkmaker" = "xyes"; then
 	PKG_CHECK_MODULES([libblkmaker],[libblkmaker_jansson-0.1],[
 	PKG_CHECK_MODULES([libblkmaker],[libblkmaker_jansson-0.1],[
 		true
 		true
@@ -783,7 +785,7 @@ for sym in bswap_ __builtin_bswap __bswap_ __swap swap OSSwapInt; do
 				AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$headerfile]), 1)
 				AC_DEFINE_UNQUOTED(AS_TR_CPP([HAVE_$headerfile]), 1)
 			fi
 			fi
 			break 2
 			break 2
-		],[])
+		])
 	done
 	done
 	AC_MSG_RESULT([no])
 	AC_MSG_RESULT([no])
 done
 done
@@ -855,6 +857,35 @@ AC_TRY_COMPILE([
 ])
 ])
 
 
 
 
+AC_MSG_CHECKING([for clock_gettime(CLOCK_MONOTONIC)])
+AC_TRY_COMPILE([
+	#define _GNU_SOURCE
+	#include <time.h>
+],[
+	struct timespec ts;
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+],[
+	AC_MSG_RESULT([yes])
+	AC_DEFINE([HAVE_CLOCK_GETTIME_MONOTONIC], [1], [Defined to 1 if clock_gettime(CLOCK_MONOTONIC) is defined])
+	AC_SEARCH_LIBS([clock_gettime],[rt posix4])
+	AC_MSG_CHECKING([for clock_gettime(CLOCK_MONOTONIC_RAW)])
+	AC_TRY_COMPILE([
+		#define _GNU_SOURCE
+		#include <time.h>
+	],[
+		struct timespec ts;
+		clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+	],[
+		AC_MSG_RESULT([yes])
+		AC_DEFINE([HAVE_CLOCK_GETTIME_MONOTONIC_RAW], [1], [Defined to 1 if clock_gettime(CLOCK_MONOTONIC_RAW) is defined])
+	],[
+		AC_MSG_RESULT([no])
+	])
+],[
+	AC_MSG_RESULT([no])
+])
+
+
 if test "x$prefix" = xNONE; then
 if test "x$prefix" = xNONE; then
 	prefix=/usr/local
 	prefix=/usr/local
 fi
 fi

+ 16 - 0
debian/changelog

@@ -1,3 +1,19 @@
+bfgminer (3.1.4-0precise1) precise; urgency=low
+
+  * Enable triggering "identify" (flash LED) function from Manage device TUI for devices that support it.
+  * modminer & x6500: Enable changing clock frequency from Manage devices TUI interface.
+  * Device ailments (SICK, ERR, etc) are now displayed in red/pink.
+  * erupter: Add support for "identify" (flash LED) function. After some delay (up to 13 seconds), the LED will light for 3 seconds (hashing stops during this time).
+  * bitforce: Display voltages in Manage device TUI.
+  * Reorganised TUI display, adding network transfer rate, and totals summary line including count of total devices/processors hashing as well as hottest temperature across all sensors.
+  * Improved timer functionality under the hood, taking advantage of clock_gettime. This should fix issues (eg, erupters reporting insane hashrates) related to system clock changes (such as NTP drift adjustment).
+  * Removed blank/wasted lines above/below log window in TUI mode.
+  * bitforce: Clear queues at startup to avoid spurious warnings.
+  * Stratum: Add support for rolling ntime header.
+
+ -- Luke Dashjr <luke+bfgminer@dashjr.org>  Fri, 02 Aug 2013 02:28:17 -0000
+
+
 bfgminer (3.1.3-0precise1) precise; urgency=low
 bfgminer (3.1.3-0precise1) precise; urgency=low
 
 
   * Fix 100% CPU usage hang with GBT/getwork pools.
   * Fix 100% CPU usage hang with GBT/getwork pools.

+ 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.3
+Standards-Version: 3.1.4
 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

+ 119 - 13
deviceapi.c

@@ -37,8 +37,7 @@ bool hashes_done(struct thr_info *thr, int64_t hashes, struct timeval *tvp_hashe
 	const long cycle = opt_log_interval / 5 ? : 1;
 	const long cycle = opt_log_interval / 5 ? : 1;
 	
 	
 	if (unlikely(hashes == -1)) {
 	if (unlikely(hashes == -1)) {
-		time_t now = time(NULL);
-		if (difftime(now, cgpu->device_last_not_well) > 1.)
+		if (timer_elapsed(&cgpu->tv_device_last_not_well, NULL) > 0)
 			dev_error(cgpu, REASON_THREAD_ZERO_HASH);
 			dev_error(cgpu, REASON_THREAD_ZERO_HASH);
 		
 		
 		if (thr->scanhash_working && opt_restart) {
 		if (thr->scanhash_working && opt_restart) {
@@ -103,7 +102,7 @@ int restart_wait(struct thr_info *thr, unsigned int mstime)
 		return (thr->work_restart ? 0 : ETIMEDOUT);
 		return (thr->work_restart ? 0 : ETIMEDOUT);
 	}
 	}
 	
 	
-	gettimeofday(&tv_now, NULL);
+	timer_set_now(&tv_now);
 	timer_set_delay(&tv_timer, &tv_now, mstime * 1000);
 	timer_set_delay(&tv_timer, &tv_now, mstime * 1000);
 	while (true)
 	while (true)
 	{
 	{
@@ -119,7 +118,7 @@ int restart_wait(struct thr_info *thr, unsigned int mstime)
 				return 0;
 				return 0;
 			notifier_read(thr->work_restart_notifier);
 			notifier_read(thr->work_restart_notifier);
 		}
 		}
-		gettimeofday(&tv_now, NULL);
+		timer_set_now(&tv_now);
 	}
 	}
 }
 }
 
 
@@ -164,16 +163,16 @@ void minerloop_scanhash(struct thr_info *mythr)
 		work = get_and_prepare_work(mythr);
 		work = get_and_prepare_work(mythr);
 		if (!work)
 		if (!work)
 			break;
 			break;
-		gettimeofday(&(work->tv_work_start), NULL);
+		timer_set_now(&work->tv_work_start);
 		
 		
 		do {
 		do {
 			thread_reportin(mythr);
 			thread_reportin(mythr);
 			/* Only allow the mining thread to be cancelled when
 			/* Only allow the mining thread to be cancelled when
 			* it is not in the driver code. */
 			* it is not in the driver code. */
 			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
-			gettimeofday(&tv_start, NULL);
+			timer_set_now(&tv_start);
 			hashes = api->scanhash(mythr, work, work->blk.nonce + max_nonce);
 			hashes = api->scanhash(mythr, work, work->blk.nonce + max_nonce);
-			gettimeofday(&tv_end, NULL);
+			timer_set_now(&tv_end);
 			pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
 			pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
 			pthread_testcancel();
 			pthread_testcancel();
 			thread_reportin(mythr);
 			thread_reportin(mythr);
@@ -277,7 +276,7 @@ void job_results_fetched(struct thr_info *mythr)
 	{
 	{
 		struct timeval tv_now;
 		struct timeval tv_now;
 		
 		
-		gettimeofday(&tv_now, NULL);
+		timer_set_now(&tv_now);
 		
 		
 		do_process_results(mythr, &tv_now, mythr->prev_work, true);
 		do_process_results(mythr, &tv_now, mythr->prev_work, true);
 	}
 	}
@@ -296,7 +295,7 @@ void mt_job_transition(struct thr_info *mythr)
 {
 {
 	struct timeval tv_now;
 	struct timeval tv_now;
 	
 	
-	gettimeofday(&tv_now, NULL);
+	timer_set_now(&tv_now);
 	
 	
 	if (mythr->starting_next_work)
 	if (mythr->starting_next_work)
 	{
 	{
@@ -315,7 +314,7 @@ void job_start_complete(struct thr_info *mythr)
 {
 {
 	struct timeval tv_now;
 	struct timeval tv_now;
 	
 	
-	gettimeofday(&tv_now, NULL);
+	timer_set_now(&tv_now);
 	
 	
 	do_process_results(mythr, &tv_now, mythr->prev_work, false);
 	do_process_results(mythr, &tv_now, mythr->prev_work, false);
 }
 }
@@ -359,7 +358,7 @@ void do_notifier_select(struct thr_info *thr, struct timeval *tvp_timeout)
 	int maxfd;
 	int maxfd;
 	fd_set rfds;
 	fd_set rfds;
 	
 	
-	gettimeofday(&tv_now, NULL);
+	timer_set_now(&tv_now);
 	FD_ZERO(&rfds);
 	FD_ZERO(&rfds);
 	FD_SET(thr->notifier[0], &rfds);
 	FD_SET(thr->notifier[0], &rfds);
 	maxfd = thr->notifier[0];
 	maxfd = thr->notifier[0];
@@ -404,7 +403,7 @@ void minerloop_async(struct thr_info *mythr)
 	
 	
 	while (likely(!cgpu->shutdown)) {
 	while (likely(!cgpu->shutdown)) {
 		tv_timeout.tv_sec = -1;
 		tv_timeout.tv_sec = -1;
-		gettimeofday(&tv_now, NULL);
+		timer_set_now(&tv_now);
 		for (proc = cgpu; proc; proc = proc->next_proc)
 		for (proc = cgpu; proc; proc = proc->next_proc)
 		{
 		{
 			mythr = proc->thr[0];
 			mythr = proc->thr[0];
@@ -489,7 +488,7 @@ void minerloop_queue(struct thr_info *thr)
 	
 	
 	while (likely(!cgpu->shutdown)) {
 	while (likely(!cgpu->shutdown)) {
 		tv_timeout.tv_sec = -1;
 		tv_timeout.tv_sec = -1;
-		gettimeofday(&tv_now, NULL);
+		timer_set_now(&tv_now);
 		for (proc = cgpu; proc; proc = proc->next_proc)
 		for (proc = cgpu; proc; proc = proc->next_proc)
 		{
 		{
 			mythr = proc->thr[0];
 			mythr = proc->thr[0];
@@ -618,9 +617,11 @@ 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);
 	
 	
+#ifdef HAVE_FPGAUTILS
 	maybe_strdup_if_null(&cgpu->dev_manufacturer, detectone_meta_info.manufacturer);
 	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_product,      detectone_meta_info.product);
 	maybe_strdup_if_null(&cgpu->dev_serial,       detectone_meta_info.serial);
 	maybe_strdup_if_null(&cgpu->dev_serial,       detectone_meta_info.serial);
+#endif
 	
 	
 	devices_new = realloc(devices_new, sizeof(struct cgpu_info *) * (total_devices_new + lpcount + 1));
 	devices_new = realloc(devices_new, sizeof(struct cgpu_info *) * (total_devices_new + lpcount + 1));
 	devices_new[total_devices_new++] = cgpu;
 	devices_new[total_devices_new++] = cgpu;
@@ -670,3 +671,108 @@ bool add_cgpu(struct cgpu_info *cgpu)
 	
 	
 	return true;
 	return true;
 }
 }
+
+int _serial_detect(struct device_drv *api, detectone_func_t detectone, autoscan_func_t autoscan, int flags)
+{
+	struct string_elist *iter, *tmp;
+	const char *dev, *colon;
+	bool inhibitauto = flags & 4;
+	char found = 0;
+	bool forceauto = flags & 1;
+	bool hasname;
+	size_t namel = strlen(api->name);
+	size_t dnamel = strlen(api->dname);
+
+#ifdef HAVE_FPGAUTILS
+	clear_detectone_meta_info();
+#endif
+	DL_FOREACH_SAFE(scan_devices, iter, tmp) {
+		dev = iter->string;
+		if ((colon = strchr(dev, ':')) && colon[1] != '\0') {
+			size_t idlen = colon - dev;
+
+			// allow either name:device or dname:device
+			if ((idlen != namel || strncasecmp(dev, api->name, idlen))
+			&&  (idlen != dnamel || strncasecmp(dev, api->dname, idlen)))
+				continue;
+
+			dev = colon + 1;
+			hasname = true;
+		}
+		else
+			hasname = false;
+		if (!strcmp(dev, "auto"))
+			forceauto = true;
+		else if (!strcmp(dev, "noauto"))
+			inhibitauto = true;
+		else
+		if ((flags & 2) && !hasname)
+			continue;
+		else
+		if (!detectone)
+		{}  // do nothing
+#ifdef HAVE_FPGAUTILS
+		else
+		if (serial_claim(dev, NULL))
+		{
+			applog(LOG_DEBUG, "%s is already claimed... skipping probes", dev);
+			string_elist_del(&scan_devices, iter);
+		}
+#endif
+		else if (detectone(dev)) {
+			string_elist_del(&scan_devices, iter);
+			inhibitauto = true;
+			++found;
+		}
+	}
+
+	if ((forceauto || !inhibitauto) && autoscan)
+		found += autoscan();
+
+	return found;
+}
+
+static
+FILE *_open_bitstream(const char *path, const char *subdir, const char *sub2, const char *filename)
+{
+	char fullpath[PATH_MAX];
+	strcpy(fullpath, path);
+	strcat(fullpath, "/");
+	if (subdir) {
+		strcat(fullpath, subdir);
+		strcat(fullpath, "/");
+	}
+	if (sub2) {
+		strcat(fullpath, sub2);
+		strcat(fullpath, "/");
+	}
+	strcat(fullpath, filename);
+	return fopen(fullpath, "rb");
+}
+#define _open_bitstream(path, subdir, sub2)  do {  \
+	f = _open_bitstream(path, subdir, sub2, filename);  \
+	if (f)  \
+		return f;  \
+} while(0)
+
+#define _open_bitstream2(path, path3)  do {  \
+	_open_bitstream(path, NULL, path3);  \
+	_open_bitstream(path, "../share/" PACKAGE, path3);  \
+} while(0)
+
+#define _open_bitstream3(path)  do {  \
+	_open_bitstream2(path, dname);  \
+	_open_bitstream2(path, "bitstreams");  \
+	_open_bitstream2(path, NULL);  \
+} while(0)
+
+FILE *open_bitstream(const char *dname, const char *filename)
+{
+	FILE *f;
+
+	_open_bitstream3(opt_kernel_path);
+	_open_bitstream3(cgminer_path);
+	_open_bitstream3(".");
+
+	return NULL;
+}

+ 21 - 0
deviceapi.h

@@ -32,4 +32,25 @@ extern void minerloop_queue(struct thr_info *);
 
 
 extern void *miner_thread(void *);
 extern void *miner_thread(void *);
 
 
+typedef bool(*detectone_func_t)(const char*);
+typedef int(*autoscan_func_t)();
+
+extern int _serial_detect(struct device_drv *api, detectone_func_t, autoscan_func_t, int flags);
+#define serial_detect_fauto(api, detectone, autoscan)  \
+	_serial_detect(api, detectone, autoscan, 1)
+#define serial_detect_auto(api, detectone, autoscan)  \
+	_serial_detect(api, detectone, autoscan, 0)
+#define serial_detect_auto_byname(api, detectone, autoscan)  \
+	_serial_detect(api, detectone, autoscan, 2)
+#define serial_detect(api, detectone)  \
+	_serial_detect(api, detectone,     NULL, 0)
+#define serial_detect_byname(api, detectone)  \
+	_serial_detect(api, detectone,     NULL, 2)
+#define noserial_detect(api, autoscan)  \
+	_serial_detect(api, NULL     , autoscan, 0)
+#define noserial_detect_manual(api, autoscan)  \
+	_serial_detect(api, NULL     , autoscan, 4)
+
+extern FILE *open_bitstream(const char *dname, const char *filename);
+
 #endif
 #endif

+ 3 - 5
driver-avalon.c

@@ -662,7 +662,6 @@ static bool avalon_prepare(struct thr_info *thr)
 {
 {
 	struct cgpu_info *avalon = thr->cgpu;
 	struct cgpu_info *avalon = thr->cgpu;
 	struct avalon_info *info = avalon->device_data;
 	struct avalon_info *info = avalon->device_data;
-	struct timeval now;
 
 
 	free(avalon->works);
 	free(avalon->works);
 	avalon->works = calloc(info->miner_count * sizeof(struct work *),
 	avalon->works = calloc(info->miner_count * sizeof(struct work *),
@@ -674,8 +673,7 @@ static bool avalon_prepare(struct thr_info *thr)
 	else
 	else
 		__avalon_init(avalon);
 		__avalon_init(avalon);
 
 
-	cgtime(&now);
-	get_datestamp(avalon->init, &now);
+	get_now_datestamp(avalon->init);
 	avalon->status = LIFE_INIT2;
 	avalon->status = LIFE_INIT2;
 	return true;
 	return true;
 }
 }
@@ -925,9 +923,9 @@ static int64_t avalon_scanhash(struct thr_info *thr)
 		if (opt_debug) {
 		if (opt_debug) {
 			timersub(&tv_finish, &tv_start, &elapsed);
 			timersub(&tv_finish, &tv_start, &elapsed);
 			applog(LOG_DEBUG,
 			applog(LOG_DEBUG,
-			       "Avalon: nonce = 0x%08x = 0x%08"PRIx64" hashes "
+			       "Avalon: nonce = 0x%08"PRIx32" = 0x%08"PRIx64" hashes "
 			       "(%ld.%06lds)", nonce, (uint64_t)hash_count,
 			       "(%ld.%06lds)", nonce, (uint64_t)hash_count,
-			       elapsed.tv_sec, elapsed.tv_usec);
+			       (long)elapsed.tv_sec, (long)elapsed.tv_usec);
 		}
 		}
 	}
 	}
 	if (hash_count && avalon->results < AVALON_ARRAY_SIZE)
 	if (hash_count && avalon->results < AVALON_ARRAY_SIZE)

+ 69 - 6
driver-bitforce.c

@@ -10,6 +10,7 @@
 
 
 #include "config.h"
 #include "config.h"
 
 
+#include <ctype.h>
 #include <limits.h>
 #include <limits.h>
 #include <pthread.h>
 #include <pthread.h>
 #include <stdint.h>
 #include <stdint.h>
@@ -48,6 +49,7 @@ enum bitforce_proto {
 	BFP_RANGE,
 	BFP_RANGE,
 	BFP_QUEUE,
 	BFP_QUEUE,
 	BFP_BQUEUE,
 	BFP_BQUEUE,
+	BFP_PQUEUE,
 };
 };
 
 
 static const char *protonames[] = {
 static const char *protonames[] = {
@@ -55,6 +57,7 @@ static const char *protonames[] = {
 	"nonce range",
 	"nonce range",
 	"work queue",
 	"work queue",
 	"bulk queue",
 	"bulk queue",
+	"parallel queue",
 };
 };
 
 
 struct device_drv bitforce_drv;
 struct device_drv bitforce_drv;
@@ -321,6 +324,7 @@ struct bitforce_data {
 	unsigned sleep_ms_default;
 	unsigned sleep_ms_default;
 	struct timeval tv_hashmeter_start;
 	struct timeval tv_hashmeter_start;
 	float temp[2];
 	float temp[2];
+	char *voltinfo;
 };
 };
 
 
 struct bitforce_proc_data {
 struct bitforce_proc_data {
@@ -356,7 +360,6 @@ static bool bitforce_thread_prepare(struct thr_info *thr)
 {
 {
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct cgpu_info *bitforce = thr->cgpu;
 	int fdDev = BFopen(bitforce->device_path);
 	int fdDev = BFopen(bitforce->device_path);
-	struct timeval now;
 
 
 	if (unlikely(fdDev == -1)) {
 	if (unlikely(fdDev == -1)) {
 		applog(LOG_ERR, "%s: Failed to open %s", bitforce->dev_repr, bitforce->device_path);
 		applog(LOG_ERR, "%s: Failed to open %s", bitforce->dev_repr, bitforce->device_path);
@@ -366,8 +369,7 @@ static bool bitforce_thread_prepare(struct thr_info *thr)
 	bitforce->device_fd = fdDev;
 	bitforce->device_fd = fdDev;
 
 
 	applog(LOG_INFO, "%s: Opened %s", bitforce->dev_repr, bitforce->device_path);
 	applog(LOG_INFO, "%s: Opened %s", bitforce->dev_repr, bitforce->device_path);
-	cgtime(&now);
-	get_datestamp(bitforce->init, &now);
+	get_now_datestamp(bitforce->init);
 
 
 	return true;
 	return true;
 }
 }
@@ -546,7 +548,8 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
 	struct bitforce_data *data = bitforce->device_data;
 	struct bitforce_data *data = bitforce->device_data;
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
 	int fdDev = bitforce->device->device_fd;
 	int fdDev = bitforce->device->device_fd;
-	char pdevbuf[0x100];
+	char pdevbuf[0x40];
+	char voltbuf[0x40];
 	char *s;
 	char *s;
 	struct cgpu_info *chip_cgpu;
 	struct cgpu_info *chip_cgpu;
 
 
@@ -569,9 +572,51 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
 	if (mutex_trylock(mutexp))
 	if (mutex_trylock(mutexp))
 		return false;
 		return false;
 
 
+	if (data->sc)
+		bitforce_cmd1(fdDev, data->xlink_id, voltbuf, sizeof(voltbuf), "ZTX");
 	bitforce_cmd1(fdDev, data->xlink_id, pdevbuf, sizeof(pdevbuf), "ZLX");
 	bitforce_cmd1(fdDev, data->xlink_id, pdevbuf, sizeof(pdevbuf), "ZLX");
 	mutex_unlock(mutexp);
 	mutex_unlock(mutexp);
 	
 	
+	if (data->sc && likely(voltbuf[0]))
+	{
+		// Process voltage info
+		// "NNNxxx,NNNxxx,NNNxxx" -> "NNN.xxx / NNN.xxx / NNN.xxx"
+		size_t sz = strlen(voltbuf) * 4;
+		char *saveptr, *v, *outbuf = malloc(sz);
+		char *out = outbuf;
+		if (!out)
+			goto skipvolts;
+		for (v = strtok_r(voltbuf, ",", &saveptr); v; v = strtok_r(NULL, ",", &saveptr))
+		{
+			while (isCspace(v[0]))
+				++v;
+			sz = strlen(v);
+			while (isCspace(v[sz - 1]))
+				--sz;
+			if (sz < 4)
+			{
+				memcpy(out, "0.00? / ", 8);
+				memcpy(&out[5 - sz], v, sz);
+				out += 8;
+			}
+			else
+			{
+				memcpy(out, v, sz - 3);
+				out += sz - 3;
+				out[0] = '.';
+				memcpy(&out[1], &v[sz - 3], 3);
+				memcpy(&out[4], " / ", 3);
+				out += 7;
+			}
+		}
+		out[-3] = '\0';
+		assert(out[-2]=='/');
+		saveptr = data->voltinfo;
+		data->voltinfo = outbuf;
+		free(saveptr);
+	}
+	
+skipvolts:
 	if (unlikely(!pdevbuf[0])) {
 	if (unlikely(!pdevbuf[0])) {
 		struct thr_info *thr = bitforce->thr[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);
@@ -652,6 +697,8 @@ bool bitforce_job_prepare(struct thr_info *thr, struct work *work, __maybe_unuse
 	{
 	{
 		case BFP_BQUEUE:
 		case BFP_BQUEUE:
 			quit(1, "%"PRIpreprv": Impossible BFP_BQUEUE in bitforce_job_prepare", bitforce->proc_repr);
 			quit(1, "%"PRIpreprv": Impossible BFP_BQUEUE in bitforce_job_prepare", bitforce->proc_repr);
+		case BFP_PQUEUE:
+			quit(1, "%"PRIpreprv": Impossible BFP_PQUEUE in bitforce_job_prepare", bitforce->proc_repr);
 		case BFP_RANGE:
 		case BFP_RANGE:
 		{
 		{
 			uint32_t *ob_nonce = (uint32_t*)&(ob_dt[32]);
 			uint32_t *ob_nonce = (uint32_t*)&(ob_dt[32]);
@@ -1232,6 +1279,8 @@ static bool bitforce_thread_init(struct thr_info *thr)
 	bool sc = initdata->sc;
 	bool sc = initdata->sc;
 	int xlink_id = 0, boardno = 0;
 	int xlink_id = 0, boardno = 0;
 	struct bitforce_proc_data *first_on_this_board;
 	struct bitforce_proc_data *first_on_this_board;
+	char buf[100];
+	int fd = bitforce->device_fd;
 	
 	
 	for ( ; bitforce; bitforce = bitforce->next_proc)
 	for ( ; bitforce; bitforce = bitforce->next_proc)
 	{
 	{
@@ -1269,7 +1318,7 @@ static bool bitforce_thread_init(struct thr_info *thr)
 			
 			
 			if (bitforce->drv == &bitforce_queue_api)
 			if (bitforce->drv == &bitforce_queue_api)
 			{
 			{
-				bitforce_change_mode(bitforce, BFP_BQUEUE);
+				bitforce_change_mode(bitforce, data->parallel_protocol ? BFP_PQUEUE : BFP_BQUEUE);
 				bitforce->sleep_ms = data->sleep_ms_default = 100;
 				bitforce->sleep_ms = data->sleep_ms_default = 100;
 				timer_set_delay_from_now(&thr->tv_poll, 0);
 				timer_set_delay_from_now(&thr->tv_poll, 0);
 				data->queued_max = data->parallel * 2;
 				data->queued_max = data->parallel * 2;
@@ -1280,6 +1329,9 @@ static bool bitforce_thread_init(struct thr_info *thr)
 			}
 			}
 			else
 			else
 				bitforce_change_mode(bitforce, BFP_QUEUE);
 				bitforce_change_mode(bitforce, BFP_QUEUE);
+			
+			// Clear job queue to start fresh; ignore response
+			bitforce_cmd1(fd, data->xlink_id, buf, sizeof(buf), "ZQX");
 		}
 		}
 		else
 		else
 		{
 		{
@@ -1308,6 +1360,7 @@ static bool bitforce_thread_init(struct thr_info *thr)
 			procdata->cgpu = bitforce;
 			procdata->cgpu = bitforce;
 			bitforce->device_data = data;
 			bitforce->device_data = data;
 			bitforce->status = LIFE_INIT2;
 			bitforce->status = LIFE_INIT2;
+			bitforce->kname = first_on_this_board->cgpu->kname;
 		}
 		}
 		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);
 		
 		
@@ -1316,6 +1369,7 @@ static bool bitforce_thread_init(struct thr_info *thr)
 		{}
 		{}
 	}
 	}
 	
 	
+	// NOTE: This doesn't restore the first processor, but it does get us the last one; this is sufficient for the delay debug and start of the next loop below
 	bitforce = thr->cgpu;
 	bitforce = thr->cgpu;
 
 
 	free(initdata->parallels);
 	free(initdata->parallels);
@@ -1327,6 +1381,13 @@ static bool bitforce_thread_init(struct thr_info *thr)
 	applog(LOG_DEBUG, "%s: Delaying start by %dms", bitforce->dev_repr, wait / 1000);
 	applog(LOG_DEBUG, "%s: Delaying start by %dms", bitforce->dev_repr, wait / 1000);
 	nmsleep(wait);
 	nmsleep(wait);
 
 
+	if (sc)
+	{
+		// Clear results queue last, to start fresh; ignore response
+		for (bitforce = bitforce->device; bitforce; bitforce = bitforce->next_proc)
+			bitforce_zox(thr, "ZOX");
+	}
+	
 	return true;
 	return true;
 }
 }
 
 
@@ -1383,6 +1444,8 @@ void bitforce_wlogprint_status(struct cgpu_info *cgpu)
 	struct bitforce_data *data = cgpu->device_data;
 	struct bitforce_data *data = cgpu->device_data;
 	if (data->temp[0] > 0 && data->temp[1] > 0)
 	if (data->temp[0] > 0 && data->temp[1] > 0)
 		wlogprint("Temperatures: %4.1fC %4.1fC\n", data->temp[0], data->temp[1]);
 		wlogprint("Temperatures: %4.1fC %4.1fC\n", data->temp[0], data->temp[1]);
+	if (data->voltinfo)
+		wlogprint("Voltages: %s\n", data->voltinfo);
 }
 }
 #endif
 #endif
 
 
@@ -1396,7 +1459,7 @@ static struct api_data *bitforce_drv_stats(struct cgpu_info *cgpu)
 	// locking access to displaying API debug 'stats'
 	// locking access to displaying API debug 'stats'
 	// If locking becomes an issue for any of them, use copy_data=true also
 	// If locking becomes an issue for any of them, use copy_data=true also
 	root = api_add_uint(root, "Sleep Time", &(cgpu->sleep_ms), false);
 	root = api_add_uint(root, "Sleep Time", &(cgpu->sleep_ms), false);
-	if (data->proto != BFP_BQUEUE)
+	if (data->proto != BFP_BQUEUE && data->proto != BFP_PQUEUE)
 		root = api_add_uint(root, "Avg Wait", &(cgpu->avg_wait_d), false);
 		root = api_add_uint(root, "Avg Wait", &(cgpu->avg_wait_d), false);
 	if (data->temp[0] > 0 && data->temp[1] > 0)
 	if (data->temp[0] > 0 && data->temp[1] > 0)
 	{
 	{

+ 3 - 3
driver-cpu.c

@@ -30,7 +30,7 @@
 #include <libgen.h>
 #include <libgen.h>
 
 
 #include "compat.h"
 #include "compat.h"
-#include "fpgautils.h"
+#include "deviceapi.h"
 #include "miner.h"
 #include "miner.h"
 #include "bench_block.h"
 #include "bench_block.h"
 #include "util.h"
 #include "util.h"
@@ -246,7 +246,7 @@ double bench_algo_stage3(
 
 
 	memcpy(&hash1[0], &hash1_init[0], sizeof(hash1));
 	memcpy(&hash1[0], &hash1_init[0], sizeof(hash1));
 
 
-	gettimeofday(&start, 0);
+	timer_set_now(&start);
 			{
 			{
 				sha256_func func = sha256_funcs[algo];
 				sha256_func func = sha256_funcs[algo];
 				(*func)(
 				(*func)(
@@ -261,7 +261,7 @@ double bench_algo_stage3(
 					work.blk.nonce
 					work.blk.nonce
 				);
 				);
 			}
 			}
-	gettimeofday(&end, 0);
+	timer_set_now(&end);
 
 
 	uint64_t usec_end = ((uint64_t)end.tv_sec)*1000*1000 + end.tv_usec;
 	uint64_t usec_end = ((uint64_t)end.tv_sec)*1000*1000 + end.tv_usec;
 	uint64_t usec_start = ((uint64_t)start.tv_sec)*1000*1000 + start.tv_usec;
 	uint64_t usec_start = ((uint64_t)start.tv_sec)*1000*1000 + start.tv_usec;

+ 21 - 2
driver-erupter.c

@@ -7,6 +7,9 @@
  * any later version.  See COPYING for more details.
  * any later version.  See COPYING for more details.
  */
  */
 
 
+#include "config.h"
+
+#include "miner.h"
 #include "fpgautils.h"
 #include "fpgautils.h"
 #include "icarus-common.h"
 #include "icarus-common.h"
 
 
@@ -37,12 +40,19 @@ static bool _erupter_detect_one(const char *devpath, struct device_drv *drv)
 
 
 static bool erupter_emerald_detect_one(const char *devpath)
 static bool erupter_emerald_detect_one(const char *devpath)
 {
 {
+	// For detection via BEE:*
 	return _erupter_detect_one(devpath, &erupter_drv_emerald);
 	return _erupter_detect_one(devpath, &erupter_drv_emerald);
 }
 }
 
 
 static bool erupter_detect_one(const char *devpath)
 static bool erupter_detect_one(const char *devpath)
 {
 {
-	return _erupter_detect_one(devpath, &erupter_drv);
+	struct device_drv *drv = &erupter_drv;
+	
+	// For autodetection
+	if (unlikely(detectone_meta_info.product && strstr(detectone_meta_info.product, "Emerald")))
+		drv = &erupter_drv_emerald;
+	
+	return _erupter_detect_one(devpath, drv);
 }
 }
 
 
 static int erupter_emerald_detect_auto(void)
 static int erupter_emerald_detect_auto(void)
@@ -61,8 +71,16 @@ static void erupter_detect()
 {
 {
 	erupter_drv_init();
 	erupter_drv_init();
 	// Actual serial detection is handled by Icarus driver
 	// 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);
 	serial_detect_auto_byname(&erupter_drv, erupter_detect_one, erupter_detect_auto);
+	serial_detect_auto_byname(&erupter_drv_emerald, erupter_emerald_detect_one, erupter_emerald_detect_auto);
+}
+
+static bool erupter_identify(struct cgpu_info *erupter)
+{
+	struct thr_info *thr = erupter->thr[0];
+	struct icarus_state *state = thr->cgpu_data;
+	state->identify = true;
+	return true;
 }
 }
 
 
 static void erupter_drv_init()
 static void erupter_drv_init()
@@ -71,6 +89,7 @@ static void erupter_drv_init()
 	erupter_drv.dname = "erupter";
 	erupter_drv.dname = "erupter";
 	erupter_drv.name = "BES";
 	erupter_drv.name = "BES";
 	erupter_drv.drv_detect = erupter_detect;
 	erupter_drv.drv_detect = erupter_detect;
+	erupter_drv.identify_device = erupter_identify;
 	
 	
 	erupter_drv_emerald = erupter_drv;
 	erupter_drv_emerald = erupter_drv;
 	erupter_drv_emerald.name = "BEE";
 	erupter_drv_emerald.name = "BEE";

+ 111 - 26
driver-icarus.c

@@ -645,8 +645,6 @@ static bool icarus_prepare(struct thr_info *thr)
 	struct cgpu_info *icarus = thr->cgpu;
 	struct cgpu_info *icarus = thr->cgpu;
 	struct ICARUS_INFO *info = icarus->device_data;
 	struct ICARUS_INFO *info = icarus->device_data;
 
 
-	struct timeval now;
-
 	icarus->device_fd = -1;
 	icarus->device_fd = -1;
 
 
 	int fd = icarus_open2(icarus->device_path, info->baud, true);
 	int fd = icarus_open2(icarus->device_path, info->baud, true);
@@ -659,8 +657,7 @@ static bool icarus_prepare(struct thr_info *thr)
 	icarus->device_fd = fd;
 	icarus->device_fd = fd;
 
 
 	applog(LOG_INFO, "Opened Icarus on %s", icarus->device_path);
 	applog(LOG_INFO, "Opened Icarus on %s", icarus->device_path);
-	cgtime(&now);
-	get_datestamp(icarus->init, &now);
+	get_now_datestamp(icarus->init);
 
 
 	struct icarus_state *state;
 	struct icarus_state *state;
 	thr->cgpu_data = state = calloc(1, sizeof(*state));
 	thr->cgpu_data = state = calloc(1, sizeof(*state));
@@ -750,13 +747,44 @@ static bool icarus_reopen(struct cgpu_info *icarus, struct icarus_state *state,
 	return true;
 	return true;
 }
 }
 
 
-static bool icarus_start_work(struct thr_info *thr, const unsigned char *ob_bin)
+static
+bool icarus_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused uint64_t max_nonce)
+{
+	struct cgpu_info * const icarus = thr->cgpu;
+	struct icarus_state * const state = thr->cgpu_data;
+	uint8_t * const ob_bin = state->ob_bin;
+	
+	memcpy(ob_bin, work->midstate, 32);
+	memcpy(ob_bin + 52, work->data + 64, 12);
+	if (!(memcmp(&ob_bin[56], "\xff\xff\xff\xff", 4)
+	   || memcmp(&ob_bin, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 32))) {
+		// This sequence is used on cairnsmore bitstreams for commands, NEVER send it otherwise
+		applog(LOG_WARNING, "%"PRIpreprv": Received job attempting to send a command, corrupting it!",
+		       icarus->proc_repr);
+		ob_bin[56] = 0;
+	}
+	rev(ob_bin, 32);
+	rev(ob_bin + 52, 12);
+	
+	return true;
+}
+
+static bool icarus_job_start(struct thr_info *thr)
 {
 {
 	struct cgpu_info *icarus = thr->cgpu;
 	struct cgpu_info *icarus = thr->cgpu;
+	struct ICARUS_INFO *info = icarus->device_data;
 	struct icarus_state *state = thr->cgpu_data;
 	struct icarus_state *state = thr->cgpu_data;
+	const uint8_t * const ob_bin = state->ob_bin;
 	int fd = icarus->device_fd;
 	int fd = icarus->device_fd;
 	int ret;
 	int ret;
 
 
+	// Handle dynamic clocking for "subclass" devices
+	// This needs to run before sending next job, since it hashes the command too
+	if (info->dclk.freqM && likely(!state->firstrun)) {
+		dclk_preUpdate(&info->dclk);
+		dclk_updateFreq(&info->dclk, info->dclk_change_clock_func, thr);
+	}
+	
 	cgtime(&state->tv_workstart);
 	cgtime(&state->tv_workstart);
 
 
 	ret = icarus_write(fd, ob_bin, 64);
 	ret = icarus_write(fd, ob_bin, 64);
@@ -778,6 +806,63 @@ static bool icarus_start_work(struct thr_info *thr, const unsigned char *ob_bin)
 	return true;
 	return true;
 }
 }
 
 
+static
+void handle_identify(struct thr_info * const thr, int ret, const bool was_first_run)
+{
+	const struct cgpu_info * const icarus = thr->cgpu;
+	const struct ICARUS_INFO * const info = icarus->device_data;
+	struct icarus_state * const state = thr->cgpu_data;
+	int fd = icarus->device_fd;
+	struct timeval tv_now;
+	double delapsed;
+	uint32_t nonce;
+	
+	// If identify is requested (block erupters):
+	// 1. Don't start the next job right away (above)
+	// 2. Wait for the current job to complete 100%
+	
+	if (!was_first_run)
+	{
+		applog(LOG_DEBUG, "%"PRIpreprv": Identify: Waiting for current job to finish", icarus->proc_repr);
+		while (true)
+		{
+			cgtime(&tv_now);
+			delapsed = tdiff(&tv_now, &state->tv_workstart);
+			if (delapsed + 0.1 > info->fullnonce)
+				break;
+			
+			// Try to get more nonces (ignoring work restart)
+			ret = icarus_gets((void *)&nonce, fd, &tv_now, NULL, (info->fullnonce - delapsed) * 10);
+			if (ret == ICA_GETS_OK)
+			{
+				nonce = be32toh(nonce);
+				submit_nonce(thr, &state->last_work, nonce);
+			}
+		}
+	}
+	else
+		applog(LOG_DEBUG, "%"PRIpreprv": Identify: Current job should already be finished", icarus->proc_repr);
+	
+	// 3. Delay 3 more seconds
+	applog(LOG_DEBUG, "%"PRIpreprv": Identify: Leaving idle for 3 seconds", icarus->proc_repr);
+	nmsleep(3000);
+	
+	// Check for work restart in the meantime
+	if (thr->work_restart)
+	{
+		applog(LOG_DEBUG, "%"PRIpreprv": Identify: Work restart requested during delay", icarus->proc_repr);
+		goto no_job_start;
+	}
+	
+	// 4. Start next job
+	applog(LOG_DEBUG, "%"PRIpreprv": Identify: Starting next job", icarus->proc_repr);
+	if (!icarus_job_start(thr))
+no_job_start:
+		state->firstrun = true;
+	
+	state->identify = false;
+}
+
 static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 				__maybe_unused int64_t max_nonce)
 				__maybe_unused int64_t max_nonce)
 {
 {
@@ -787,7 +872,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 
 	struct ICARUS_INFO *info;
 	struct ICARUS_INFO *info;
 
 
-	unsigned char ob_bin[64] = {0}, nonce_bin[ICARUS_READ_SIZE] = {0};
+	unsigned char nonce_bin[ICARUS_READ_SIZE] = {0};
 	uint32_t nonce;
 	uint32_t nonce;
 	int64_t hash_count;
 	int64_t hash_count;
 	struct timeval tv_start, elapsed;
 	struct timeval tv_start, elapsed;
@@ -795,6 +880,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	double Ti, Xi;
 	double Ti, Xi;
 	int curr_hw_errors, i;
 	int curr_hw_errors, i;
 	bool was_hw_error;
 	bool was_hw_error;
+	bool was_first_run;
 
 
 	struct ICARUS_HISTORY *history0, *history;
 	struct ICARUS_HISTORY *history0, *history;
 	int count;
 	int count;
@@ -808,19 +894,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 
 	icarus = thr->cgpu;
 	icarus = thr->cgpu;
 	struct icarus_state *state = thr->cgpu_data;
 	struct icarus_state *state = thr->cgpu_data;
+	was_first_run = state->firstrun;
 
 
-	// Prepare the next work immediately
-	memcpy(ob_bin, work->midstate, 32);
-	memcpy(ob_bin + 52, work->data + 64, 12);
-	if (!(memcmp(&ob_bin[56], "\xff\xff\xff\xff", 4)
-	   || memcmp(&ob_bin, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 32))) {
-		// This sequence is used on cairnsmore bitstreams for commands, NEVER send it otherwise
-		applog(LOG_WARNING, "%"PRIpreprv": Received job attempting to send a command, corrupting it!",
-		       icarus->proc_repr);
-		ob_bin[56] = 0;
-	}
-	rev(ob_bin, 32);
-	rev(ob_bin + 52, 12);
+	icarus_job_prepare(thr, work, max_nonce);
 
 
 	// Wait for the previous run's result
 	// Wait for the previous run's result
 	fd = icarus->device_fd;
 	fd = icarus->device_fd;
@@ -874,17 +950,20 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 
 	// Handle dynamic clocking for "subclass" devices
 	// Handle dynamic clocking for "subclass" devices
 	// This needs to run before sending next job, since it hashes the command too
 	// This needs to run before sending next job, since it hashes the command too
-	if (info->dclk.freqM && likely(!state->firstrun)) {
+	if (info->dclk.freqM && likely(!was_first_run)) {
 		int qsec = ((4 * elapsed.tv_sec) + (elapsed.tv_usec / 250000)) ?: 1;
 		int qsec = ((4 * elapsed.tv_sec) + (elapsed.tv_usec / 250000)) ?: 1;
 		for (int n = qsec; n; --n)
 		for (int n = qsec; n; --n)
 			dclk_gotNonces(&info->dclk);
 			dclk_gotNonces(&info->dclk);
 		if (nonce && !test_nonce(&state->last_work, nonce, false))
 		if (nonce && !test_nonce(&state->last_work, nonce, false))
 			dclk_errorCount(&info->dclk, qsec);
 			dclk_errorCount(&info->dclk, qsec);
-		dclk_preUpdate(&info->dclk);
-		dclk_updateFreq(&info->dclk, info->dclk_change_clock_func, thr);
 	}
 	}
 
 
-	if (!icarus_start_work(thr, ob_bin))
+	if (unlikely(state->identify))
+	{
+		// Delay job start until later...
+	}
+	else
+	if (!icarus_job_start(thr))
 		/* This should never happen */
 		/* This should never happen */
 		state->firstrun = true;
 		state->firstrun = true;
 
 
@@ -893,10 +972,11 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 
 	work->blk.nonce = 0xffffffff;
 	work->blk.nonce = 0xffffffff;
 
 
-	if (state->firstrun) {
+	if (was_first_run) {
 		state->firstrun = false;
 		state->firstrun = false;
 		__copy_work(&state->last_work, work);
 		__copy_work(&state->last_work, work);
-		return 0;
+		hash_count = 0;
+		goto out;
 	}
 	}
 
 
 	// OK, done starting Icarus's next job... now process the last run's result!
 	// OK, done starting Icarus's next job... now process the last run's result!
@@ -921,7 +1001,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 					(int64_t)elapsed.tv_sec, (unsigned long)elapsed.tv_usec);
 					(int64_t)elapsed.tv_sec, (unsigned long)elapsed.tv_usec);
 		}
 		}
 
 
-		return estimate_hashes;
+		hash_count = estimate_hashes;
+		goto out;
 	}
 	}
 
 
 	curr_hw_errors = icarus->hw_errors;
 	curr_hw_errors = icarus->hw_errors;
@@ -935,7 +1016,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 			if (!icarus_reopen(icarus, state, &fd))
 			if (!icarus_reopen(icarus, state, &fd))
 				state->firstrun = true;
 				state->firstrun = true;
 			// Some devices (Cairnsmore1, for example) abort hashing when reopened, so send the job again
 			// Some devices (Cairnsmore1, for example) abort hashing when reopened, so send the job again
-			if (!icarus_start_work(thr, ob_bin))
+			if (!icarus_job_start(thr))
 				state->firstrun = true;
 				state->firstrun = true;
 		}
 		}
 
 
@@ -1082,6 +1163,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		timeradd(&tv_history_finish, &(info->history_time), &(info->history_time));
 		timeradd(&tv_history_finish, &(info->history_time), &(info->history_time));
 	}
 	}
 
 
+out:
+	if (unlikely(state->identify))
+		handle_identify(thr, ret, was_first_run);
+	
 	return hash_count;
 	return hash_count;
 }
 }
 
 

+ 76 - 22
driver-modminer.c

@@ -26,7 +26,7 @@
 #define BISTREAM_USER_ID "\2\4$B"
 #define BISTREAM_USER_ID "\2\4$B"
 
 
 #define MODMINER_MAX_CLOCK 250
 #define MODMINER_MAX_CLOCK 250
-#define MODMINER_DEF_CLOCK 210
+#define MODMINER_DEF_CLOCK 190
 #define MODMINER_MIN_CLOCK   2
 #define MODMINER_MIN_CLOCK   2
 
 
 // Commands
 // Commands
@@ -64,7 +64,7 @@ struct modminer_fpga_state {
 	// Number of nonces did meet pdiff 1, ever
 	// Number of nonces did meet pdiff 1, ever
 	int good_share_counter;
 	int good_share_counter;
 	// Time the clock was last reduced due to temperature
 	// Time the clock was last reduced due to temperature
-	time_t last_cutoff_reduced;
+	struct timeval tv_last_cutoff_reduced;
 
 
 	unsigned char temp;
 	unsigned char temp;
 
 
@@ -157,7 +157,7 @@ modminer_detect_one(const char *devpath)
 static int
 static int
 modminer_detect_auto()
 modminer_detect_auto()
 {
 {
-	return serial_autodetect(modminer_detect_one, "BTCFPGA", "ModMiner");
+	return serial_autodetect(modminer_detect_one, "ModMiner");
 }
 }
 
 
 static void
 static void
@@ -276,9 +276,7 @@ modminer_device_prepare(struct cgpu_info *modminer)
 	modminer->device->device_fd = fd;
 	modminer->device->device_fd = fd;
 	applog(LOG_INFO, "%s: Opened %s", modminer->dev_repr, modminer->device_path);
 	applog(LOG_INFO, "%s: Opened %s", modminer->dev_repr, modminer->device_path);
 
 
-	struct timeval now;
-	gettimeofday(&now, NULL);
-	get_datestamp(modminer->init, &now);
+	get_now_datestamp(modminer->init);
 
 
 	return true;
 	return true;
 }
 }
@@ -486,9 +484,10 @@ static void modminer_get_temperature(struct cgpu_info *modminer, struct thr_info
 		state->temp = temperature;
 		state->temp = temperature;
 		if (temperature > modminer->targettemp + opt_hysteresis) {
 		if (temperature > modminer->targettemp + opt_hysteresis) {
 			{
 			{
-				time_t now = time(NULL);
-				if (state->last_cutoff_reduced != now) {
-					state->last_cutoff_reduced = now;
+				struct timeval now;
+				cgtime(&now);
+				if (timer_elapsed(&state->tv_last_cutoff_reduced, &now)) {
+					state->tv_last_cutoff_reduced = now;
 					int oldFreq = state->dclk.freqM;
 					int oldFreq = state->dclk.freqM;
 					if (modminer_reduce_clock(thr, false))
 					if (modminer_reduce_clock(thr, false))
 						applog(LOG_NOTICE, "%s: Frequency %s from %u to %u MHz (temp: %d)",
 						applog(LOG_NOTICE, "%s: Frequency %s from %u to %u MHz (temp: %d)",
@@ -593,7 +592,7 @@ fd_set fds;
 
 
 	if (46 != write(fd, state->next_work_cmd, 46))
 	if (46 != write(fd, state->next_work_cmd, 46))
 		bailout2(LOG_ERR, "%s: Error writing (start work)", modminer->proc_repr);
 		bailout2(LOG_ERR, "%s: Error writing (start work)", modminer->proc_repr);
-	gettimeofday(&state->tv_workstart, NULL);
+	timer_set_now(&state->tv_workstart);
 	state->hashes = 0;
 	state->hashes = 0;
 	status_read("start work");
 	status_read("start work");
 	mutex_unlock(mutexp);
 	mutex_unlock(mutexp);
@@ -674,7 +673,7 @@ modminer_process_results(struct thr_info*thr)
 	}
 	}
 
 
 	struct timeval tv_workend, elapsed;
 	struct timeval tv_workend, elapsed;
-	gettimeofday(&tv_workend, NULL);
+	timer_set_now(&tv_workend);
 	timersub(&tv_workend, &state->tv_workstart, &elapsed);
 	timersub(&tv_workend, &state->tv_workstart, &elapsed);
 
 
 	uint64_t hashes = (uint64_t)state->dclk.freqM * 2 * (((uint64_t)elapsed.tv_sec * 1000000) + elapsed.tv_usec);
 	uint64_t hashes = (uint64_t)state->dclk.freqM * 2 * (((uint64_t)elapsed.tv_sec * 1000000) + elapsed.tv_usec);
@@ -744,6 +743,21 @@ modminer_fpga_shutdown(struct thr_info *thr)
 	thr->cgpu_data = NULL;
 	thr->cgpu_data = NULL;
 }
 }
 
 
+static
+bool modminer_user_set_clock(struct cgpu_info *cgpu, const int val)
+{
+	struct thr_info * const thr = cgpu->thr[0];
+	struct modminer_fpga_state * const state = thr->cgpu_data;
+	const int multiplier = val / 2;
+	const uint8_t oldFreqM = state->dclk.freqM;
+	const signed char delta = (multiplier - oldFreqM) * 2;
+	state->dclk.freqMDefault = multiplier;
+	const bool rv = modminer_change_clock(thr, true, delta);
+	if (likely(rv))
+		dclk_msg_freqchange(cgpu->proc_repr, oldFreqM * 2, state->dclk.freqM * 2, " on user request");
+	return rv;
+}
+
 static char *modminer_set_device(struct cgpu_info *modminer, char *option, char *setting, char *replybuf)
 static char *modminer_set_device(struct cgpu_info *modminer, char *option, char *setting, char *replybuf)
 {
 {
 	int val;
 	int val;
@@ -755,8 +769,6 @@ static char *modminer_set_device(struct cgpu_info *modminer, char *option, char
 	}
 	}
 
 
 	if (strcasecmp(option, "clock") == 0) {
 	if (strcasecmp(option, "clock") == 0) {
-		int multiplier;
-
 		if (!setting || !*setting) {
 		if (!setting || !*setting) {
 			sprintf(replybuf, "missing clock setting");
 			sprintf(replybuf, "missing clock setting");
 			return replybuf;
 			return replybuf;
@@ -769,20 +781,13 @@ static char *modminer_set_device(struct cgpu_info *modminer, char *option, char
 			return replybuf;
 			return replybuf;
 		}
 		}
 
 
-		multiplier = val / 2;
-		struct thr_info *thr = modminer->thr[0];
-		struct modminer_fpga_state *state = thr->cgpu_data;
-		uint8_t oldFreqM = state->dclk.freqM;
-		signed char delta = (multiplier - oldFreqM) * 2;
-		state->dclk.freqMDefault = multiplier;
-		if (unlikely(!modminer_change_clock(thr, true, delta))) {
+		if (unlikely(!modminer_user_set_clock(modminer, val)))
+		{
 			sprintf(replybuf, "Set clock failed: %s",
 			sprintf(replybuf, "Set clock failed: %s",
 			        modminer->proc_repr);
 			        modminer->proc_repr);
 			return replybuf;
 			return replybuf;
 		}
 		}
 
 
-		dclk_msg_freqchange(modminer->proc_repr, oldFreqM * 2, state->dclk.freqM * 2, " on user request");
-
 		return NULL;
 		return NULL;
 	}
 	}
 
 
@@ -790,6 +795,50 @@ static char *modminer_set_device(struct cgpu_info *modminer, char *option, char
 	return replybuf;
 	return replybuf;
 }
 }
 
 
+#ifdef HAVE_CURSES
+static
+void modminer_tui_wlogprint_choices(struct cgpu_info *cgpu)
+{
+	wlogprint("[C]lock speed ");
+}
+
+static
+const char *modminer_tui_handle_choice(struct cgpu_info *cgpu, int input)
+{
+	static char buf[0x100];  // Static for replies
+	
+	switch (input)
+	{
+		case 'c': case 'C':
+		{
+			int val;
+			char *intvar;
+			
+			sprintf(buf, "Set clock speed (range %d-%d, multiple of 2)", MODMINER_MIN_CLOCK, MODMINER_MAX_CLOCK);
+			intvar = curses_input(buf);
+			if (!intvar)
+				return "Invalid clock speed\n";
+			val = atoi(intvar);
+			free(intvar);
+			if (val < MODMINER_MIN_CLOCK || val > MODMINER_MAX_CLOCK || (val & 1) != 0)
+				return "Invalid clock speed\n";
+			
+			if (unlikely(!modminer_user_set_clock(cgpu, val)))
+				return "Set clock failed\n";
+			return "Clock speed changed\n";
+		}
+	}
+	return NULL;
+}
+
+static
+void modminer_wlogprint_status(struct cgpu_info *cgpu)
+{
+	struct modminer_fpga_state *state = cgpu->thr[0]->cgpu_data;
+	wlogprint("Clock speed: %d\n", (int)(state->dclk.freqM * 2));
+}
+#endif
+
 struct device_drv modminer_drv = {
 struct device_drv modminer_drv = {
 	.dname = "modminer",
 	.dname = "modminer",
 	.name = "MMQ",
 	.name = "MMQ",
@@ -798,6 +847,11 @@ struct device_drv modminer_drv = {
 	.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,
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = modminer_wlogprint_status,
+	.proc_tui_wlogprint_choices = modminer_tui_wlogprint_choices,
+	.proc_tui_handle_choice = modminer_tui_handle_choice,
+#endif
 	.thread_prepare = modminer_fpga_prepare,
 	.thread_prepare = modminer_fpga_prepare,
 	.thread_init = modminer_fpga_init,
 	.thread_init = modminer_fpga_init,
 	.scanhash = modminer_scanhash,
 	.scanhash = modminer_scanhash,

+ 5 - 9
driver-opencl.c

@@ -39,8 +39,8 @@
 #define OMIT_OPENCL_API
 #define OMIT_OPENCL_API
 
 
 #include "compat.h"
 #include "compat.h"
-#include "fpgautils.h"
 #include "miner.h"
 #include "miner.h"
+#include "deviceapi.h"
 #include "driver-opencl.h"
 #include "driver-opencl.h"
 #include "findnonce.h"
 #include "findnonce.h"
 #include "ocl.h"
 #include "ocl.h"
@@ -888,7 +888,7 @@ void opencl_wlogprint_status(struct cgpu_info *cgpu)
 		if (thr->cgpu != cgpu)
 		if (thr->cgpu != cgpu)
 			continue;
 			continue;
 		
 		
-		get_datestamp(checkin, &thr->last);
+		get_datestamp(checkin, time(NULL) - timer_elapsed(&thr->last, NULL));
 		displayed_rolling = thr->rolling;
 		displayed_rolling = thr->rolling;
 		if (!mhash_base)
 		if (!mhash_base)
 			displayed_rolling *= 1000;
 			displayed_rolling *= 1000;
@@ -963,7 +963,7 @@ const char *opencl_tui_handle_choice(struct cgpu_info *cgpu, int input)
 			clear_logwin();
 			clear_logwin();
 			get_statline3(logline, cgpu, true, true);
 			get_statline3(logline, cgpu, true, true);
 			wattron(logwin, A_BOLD);
 			wattron(logwin, A_BOLD);
-			waddstr(logwin, logline);
+			wlogprint("%s", logline);
 			wattroff(logwin, A_BOLD);
 			wattroff(logwin, A_BOLD);
 			wlogprint("\n");
 			wlogprint("\n");
 			
 			
@@ -1251,7 +1251,6 @@ void *reinit_gpu(void *userdata)
 	struct thr_info *mythr = userdata;
 	struct thr_info *mythr = userdata;
 	struct cgpu_info *cgpu, *sel_cgpu;
 	struct cgpu_info *cgpu, *sel_cgpu;
 	struct thr_info *thr;
 	struct thr_info *thr;
-	struct timeval now;
 	char name[256];
 	char name[256];
 	int thr_id;
 	int thr_id;
 	int i;
 	int i;
@@ -1317,8 +1316,7 @@ select_cgpu:
 		applog(LOG_WARNING, "Thread %d restarted", thr_id);
 		applog(LOG_WARNING, "Thread %d restarted", thr_id);
 	}
 	}
 
 
-	cgtime(&now);
-	get_datestamp(sel_cgpu->init, &now);
+	get_now_datestamp(sel_cgpu->init);
 
 
 	proc_enable(cgpu);
 	proc_enable(cgpu);
 
 
@@ -1500,7 +1498,6 @@ static uint32_t *blank_res;
 static bool opencl_thread_prepare(struct thr_info *thr)
 static bool opencl_thread_prepare(struct thr_info *thr)
 {
 {
 	char name[256];
 	char name[256];
-	struct timeval now;
 	struct cgpu_info *cgpu = thr->cgpu;
 	struct cgpu_info *cgpu = thr->cgpu;
 	int gpu = cgpu->device_id;
 	int gpu = cgpu->device_id;
 	int virtual_gpu = cgpu->virtual_gpu;
 	int virtual_gpu = cgpu->virtual_gpu;
@@ -1571,8 +1568,7 @@ static bool opencl_thread_prepare(struct thr_info *thr)
 		}
 		}
 	}
 	}
 	applog(LOG_INFO, "initCl() finished. Found %s", name);
 	applog(LOG_INFO, "initCl() finished. Found %s", name);
-	cgtime(&now);
-	get_datestamp(cgpu->init, &now);
+	get_now_datestamp(cgpu->init);
 
 
 	have_opencl = true;
 	have_opencl = true;
 
 

+ 107 - 29
driver-x6500.c

@@ -1,5 +1,6 @@
 /*
 /*
  * Copyright 2012-2013 Luke Dashjr
  * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012 Andrew Smith
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * under the terms of the GNU General Public License as published by the Free
@@ -13,6 +14,7 @@
 #include <winsock2.h>
 #include <winsock2.h>
 #endif
 #endif
 
 
+#include <limits.h>
 #include <math.h>
 #include <math.h>
 #include <sys/time.h>
 #include <sys/time.h>
 
 
@@ -32,7 +34,7 @@
 // NOTE: X6500_BITSTREAM_USERID is bitflipped
 // NOTE: X6500_BITSTREAM_USERID is bitflipped
 #define X6500_BITSTREAM_USERID "\x40\x20\x24\x42"
 #define X6500_BITSTREAM_USERID "\x40\x20\x24\x42"
 #define X6500_MINIMUM_CLOCK    2
 #define X6500_MINIMUM_CLOCK    2
-#define X6500_DEFAULT_CLOCK  200
+#define X6500_DEFAULT_CLOCK  190
 #define X6500_MAXIMUM_CLOCK  250
 #define X6500_MAXIMUM_CLOCK  250
 
 
 struct device_drv x6500_api;
 struct device_drv x6500_api;
@@ -200,10 +202,8 @@ struct x6500_fpga_data {
 	uint8_t freqMaxMaxM;
 	uint8_t freqMaxMaxM;
 
 
 	// Time the clock was last reduced due to temperature
 	// Time the clock was last reduced due to temperature
-	time_t last_cutoff_reduced;
+	struct timeval tv_last_cutoff_reduced;
 
 
-	float temp;
-	
 	uint32_t prepwork_last_register;
 	uint32_t prepwork_last_register;
 };
 };
 
 
@@ -488,25 +488,27 @@ void x6500_get_temperature(struct cgpu_info *x6500)
 		if (!fpga) continue;
 		if (!fpga) continue;
 
 
 		if (code[i] == 0xffff || !code[i]) {
 		if (code[i] == 0xffff || !code[i]) {
-			fpga->temp = 0;
+			x6500->temp = 0;
 			continue;
 			continue;
 		}
 		}
 		if ((code[i] >> 15) & 1)
 		if ((code[i] >> 15) & 1)
 			code[i] -= 0x10000;
 			code[i] -= 0x10000;
-		fpga->temp = (float)(code[i] >> 2) * 0.03125f;
-		applog(LOG_DEBUG,"x6500_get_temperature: fpga[%d]->temp=%.1fC",i,fpga->temp);
+		x6500->temp = (float)(code[i] >> 2) * 0.03125f;
+		applog(LOG_DEBUG,"x6500_get_temperature: fpga[%d]->temp=%.1fC",
+		       i, x6500->temp);
 
 
-		int temperature = round(fpga->temp);
+		int temperature = round(x6500->temp);
 		if (temperature > x6500->targettemp + opt_hysteresis) {
 		if (temperature > x6500->targettemp + opt_hysteresis) {
-			time_t now = time(NULL);
-			if (fpga->last_cutoff_reduced != now) {
-				fpga->last_cutoff_reduced = now;
+			struct timeval now;
+			cgtime(&now);
+			if (timer_elapsed(&fpga->tv_last_cutoff_reduced, &now)) {
+				fpga->tv_last_cutoff_reduced = now;
 				int oldFreq = fpga->dclk.freqM;
 				int oldFreq = fpga->dclk.freqM;
 				if (x6500_change_clock(thr, oldFreq - 1))
 				if (x6500_change_clock(thr, oldFreq - 1))
 					applog(LOG_NOTICE, "%"PRIprepr": Frequency dropped from %u to %u MHz (temp: %.1fC)",
 					applog(LOG_NOTICE, "%"PRIprepr": Frequency dropped from %u to %u MHz (temp: %.1fC)",
 					       x6500->proc_repr,
 					       x6500->proc_repr,
 					       oldFreq * 2, fpga->dclk.freqM * 2,
 					       oldFreq * 2, fpga->dclk.freqM * 2,
-					       fpga->temp
+					       x6500->temp
 					);
 					);
 				fpga->dclk.freqMaxM = fpga->dclk.freqM;
 				fpga->dclk.freqMaxM = fpga->dclk.freqM;
 			}
 			}
@@ -534,7 +536,6 @@ bool x6500_all_idle(struct cgpu_info *any_proc)
 
 
 static bool x6500_get_stats(struct cgpu_info *x6500)
 static bool x6500_get_stats(struct cgpu_info *x6500)
 {
 {
-	float hottest = 0;
 	if (x6500_all_idle(x6500)) {
 	if (x6500_all_idle(x6500)) {
 		struct cgpu_info *cgpu = x6500->device;
 		struct cgpu_info *cgpu = x6500->device;
 		// Getting temperature more efficiently while running
 		// Getting temperature more efficiently while running
@@ -547,18 +548,6 @@ static bool x6500_get_stats(struct cgpu_info *x6500)
 		mutex_unlock(mutexp);
 		mutex_unlock(mutexp);
 	}
 	}
 
 
-	for (int i = x6500->threads; i--; ) {
-		struct thr_info *thr = x6500->thr[i];
-		struct x6500_fpga_data *fpga = thr->cgpu_data;
-		if (!fpga)
-			continue;
-		float temp = fpga->temp;
-		if (temp > hottest)
-			hottest = temp;
-	}
-
-	x6500->temp = hottest;
-
 	return true;
 	return true;
 }
 }
 
 
@@ -581,8 +570,6 @@ get_x6500_api_extra_device_status(struct cgpu_info *x6500)
 	struct x6500_fpga_data *fpga = thr->cgpu_data;
 	struct x6500_fpga_data *fpga = thr->cgpu_data;
 	double d;
 	double d;
 
 
-	if (fpga->temp)
-		root = api_add_temp(root, "Temperature", &fpga->temp, true);
 	d = (double)fpga->dclk.freqM * 2;
 	d = (double)fpga->dclk.freqM * 2;
 	root = api_add_freq(root, "Frequency", &d, true);
 	root = api_add_freq(root, "Frequency", &d, true);
 	d = (double)fpga->dclk.freqMaxM * 2;
 	d = (double)fpga->dclk.freqMaxM * 2;
@@ -637,7 +624,7 @@ void x6500_job_start(struct thr_info *thr)
 
 
 	ft232r_flush(jp->a->ftdi);
 	ft232r_flush(jp->a->ftdi);
 
 
-	gettimeofday(&tv_now, NULL);
+	timer_set_now(&tv_now);
 	if (!thr->prev_work)
 	if (!thr->prev_work)
 		fpga->tv_hashstart = tv_now;
 		fpga->tv_hashstart = tv_now;
 	else
 	else
@@ -693,7 +680,7 @@ int64_t x6500_process_results(struct thr_info *thr, struct work *work)
 	bool bad;
 	bool bad;
 
 
 	while (1) {
 	while (1) {
-		gettimeofday(&tv_now, NULL);
+		timer_set_now(&tv_now);
 		nonce = x6500_get_register(jtag, 0xE);
 		nonce = x6500_get_register(jtag, 0xE);
 		if (nonce != 0xffffffff) {
 		if (nonce != 0xffffffff) {
 			bad = !(work && test_nonce(work, nonce, false));
 			bad = !(work && test_nonce(work, nonce, false));
@@ -743,6 +730,91 @@ void x6500_fpga_poll(struct thr_info *thr)
 		timer_set_delay_from_now(&thr->tv_poll, 10000);
 		timer_set_delay_from_now(&thr->tv_poll, 10000);
 }
 }
 
 
+static
+void x6500_user_set_clock(struct cgpu_info *cgpu, const int val)
+{
+	struct thr_info * const thr = cgpu->thr[0];
+	struct x6500_fpga_data *fpga = thr->cgpu_data;
+	const int multiplier = val / 2;
+	fpga->dclk.freqMDefault = multiplier;
+}
+
+static
+char *x6500_set_device(struct cgpu_info *cgpu, char *option, char *setting, char *replybuf)
+{
+	int val;
+	
+	if (strcasecmp(option, "help") == 0) {
+		sprintf(replybuf, "clock: range %d-%d and a multiple of 2",
+		        X6500_MINIMUM_CLOCK, X6500_MAXIMUM_CLOCK);
+		return replybuf;
+	}
+	
+	if (strcasecmp(option, "clock") == 0) {
+		if (!setting || !*setting) {
+			sprintf(replybuf, "missing clock setting");
+			return replybuf;
+		}
+		
+		val = atoi(setting);
+		if (val < X6500_MINIMUM_CLOCK || val > X6500_MAXIMUM_CLOCK || (val & 1) != 0) {
+			sprintf(replybuf, "invalid clock: '%s' valid range %d-%d and a multiple of 2",
+			        setting, X6500_MINIMUM_CLOCK, X6500_MAXIMUM_CLOCK);
+			return replybuf;
+		}
+		
+		x6500_user_set_clock(cgpu, val);
+		
+		return NULL;
+	}
+
+	sprintf(replybuf, "Unknown option: %s", option);
+	return replybuf;
+}
+
+#ifdef HAVE_CURSES
+static
+void x6500_tui_wlogprint_choices(struct cgpu_info *cgpu)
+{
+	wlogprint("[C]lock speed ");
+}
+
+static
+const char *x6500_tui_handle_choice(struct cgpu_info *cgpu, int input)
+{
+	static char buf[0x100];  // Static for replies
+	
+	switch (input)
+	{
+		case 'c': case 'C':
+		{
+			int val;
+			char *intvar;
+			
+			sprintf(buf, "Set clock speed (range %d-%d, multiple of 2)", X6500_MINIMUM_CLOCK, X6500_MAXIMUM_CLOCK);
+			intvar = curses_input(buf);
+			if (!intvar)
+				return "Invalid clock speed\n";
+			val = atoi(intvar);
+			free(intvar);
+			if (val < X6500_MINIMUM_CLOCK || val > X6500_MAXIMUM_CLOCK || (val & 1) != 0)
+				return "Invalid clock speed\n";
+			
+			x6500_user_set_clock(cgpu, val);
+			return "Clock speed changed\n";
+		}
+	}
+	return NULL;
+}
+
+static
+void x6500_wlogprint_status(struct cgpu_info *cgpu)
+{
+	struct x6500_fpga_data *fpga = cgpu->thr[0]->cgpu_data;
+	wlogprint("Clock speed: %d\n", (int)(fpga->dclk.freqM * 2));
+}
+#endif
+
 struct device_drv x6500_api = {
 struct device_drv x6500_api = {
 	.dname = "x6500",
 	.dname = "x6500",
 	.name = "XBS",
 	.name = "XBS",
@@ -752,6 +824,12 @@ struct device_drv x6500_api = {
 	.get_stats = x6500_get_stats,
 	.get_stats = x6500_get_stats,
 	.override_statline_temp = get_x6500_upload_percent,
 	.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,
+	.set_device = x6500_set_device,
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = x6500_wlogprint_status,
+	.proc_tui_wlogprint_choices = x6500_tui_wlogprint_choices,
+	.proc_tui_handle_choice = x6500_tui_handle_choice,
+#endif
 	.poll = x6500_fpga_poll,
 	.poll = x6500_fpga_poll,
 	.minerloop = minerloop_async,
 	.minerloop = minerloop_async,
 	.job_prepare = x6500_job_prepare,
 	.job_prepare = x6500_job_prepare,

+ 3 - 5
driver-ztex.c

@@ -64,9 +64,9 @@ static struct cgpu_info *ztex_setup(struct libztex_device *dev, int fpgacount)
 	ztex->dev_manufacturer = dev->dev_manufacturer;
 	ztex->dev_manufacturer = dev->dev_manufacturer;
 	ztex->dev_product = dev->dev_product;
 	ztex->dev_product = dev->dev_product;
 	ztex->dev_serial = (char*)&dev->snString[0];
 	ztex->dev_serial = (char*)&dev->snString[0];
+	ztex->name = fpganame;
 	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;
 	applog(LOG_INFO, "%"PRIpreprv": Found Ztex (ZTEX %s)", ztex->dev_repr, fpganame);
 	applog(LOG_INFO, "%"PRIpreprv": Found Ztex (ZTEX %s)", ztex->dev_repr, fpganame);
 
 
 	return ztex;
 	return ztex;
@@ -339,15 +339,13 @@ get_ztex_drv_extra_device_status(struct cgpu_info *ztex)
 
 
 static bool ztex_prepare(struct thr_info *thr)
 static bool ztex_prepare(struct thr_info *thr)
 {
 {
-	struct timeval now;
 	struct cgpu_info *cgpu = thr->cgpu;
 	struct cgpu_info *cgpu = thr->cgpu;
 	struct libztex_device *ztex = cgpu->device_ztex;
 	struct libztex_device *ztex = cgpu->device_ztex;
 
 
-	cgtime(&now);
-	get_datestamp(cgpu->init, &now);
+	get_now_datestamp(cgpu->init);
 	
 	
 	{
 	{
-		char fpganame[LIBZTEX_SNSTRING_LEN+3+1];
+		char *fpganame = malloc(LIBZTEX_SNSTRING_LEN+3+1);
 		sprintf(fpganame, "%s-%u", ztex->snString, cgpu->proc_id+1);
 		sprintf(fpganame, "%s-%u", ztex->snString, cgpu->proc_id+1);
 		cgpu->name = fpganame;
 		cgpu->name = fpganame;
 	}
 	}

+ 1 - 1
findnonce.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2011-2012 Con Kolivas
+ * Copyright 2011-2013 Con Kolivas
  * Copyright 2012-2013 Luke Dashjr
  * Copyright 2012-2013 Luke Dashjr
  * Copyright 2011 Nils Schneider
  * Copyright 2011 Nils Schneider
  *
  *

+ 54 - 130
fpgautils.c

@@ -119,7 +119,6 @@ int _detectone_wrap(const detectone_func_t detectone, const char * const param,
 
 
 struct detectone_meta_info_t detectone_meta_info;
 struct detectone_meta_info_t detectone_meta_info;
 
 
-static
 void clear_detectone_meta_info(void)
 void clear_detectone_meta_info(void)
 {
 {
 	detectone_meta_info = (struct detectone_meta_info_t){
 	detectone_meta_info = (struct detectone_meta_info_t){
@@ -150,7 +149,7 @@ char *_decode_udev_enc_dup(const char *s)
 	if (!s)
 	if (!s)
 		return NULL;
 		return NULL;
 	
 	
-	char *o = malloc(strlen(s));
+	char *o = malloc(strlen(s) + 1);
 	if (!o)
 	if (!o)
 	{
 	{
 		applog(LOG_ERR, "Failed to malloc in _decode_udev_enc_dup");
 		applog(LOG_ERR, "Failed to malloc in _decode_udev_enc_dup");
@@ -259,7 +258,7 @@ char *_sysfs_do_read(char *buf, size_t bufsz, const char *devpath, char *devfile
 		if (fgets(buf, bufsz, F))
 		if (fgets(buf, bufsz, F))
 		{
 		{
 			size_t L = strlen(buf);
 			size_t L = strlen(buf);
-			while (isspace(buf[--L]))
+			while (isCspace(buf[--L]))
 				buf[L] = '\0';
 				buf[L] = '\0';
 		}
 		}
 		else
 		else
@@ -272,15 +271,59 @@ char *_sysfs_do_read(char *buf, size_t bufsz, const char *devpath, char *devfile
 	return buf[0] ? buf : NULL;
 	return buf[0] ? buf : NULL;
 }
 }
 
 
+static
+void _sysfs_find_tty(detectone_func_t detectone, char *devpath, char *devfile, const char *prod, char *pfound)
+{
+	DIR *DT;
+	struct dirent *de;
+	char ttybuf[0x10] = "/dev/";
+	char manuf[0x40], serial[0x40];
+	char *mydevfile = strdup(devfile);
+	
+	DT = opendir(devpath);
+	if (!DT)
+		goto out;
+	
+	while ( (de = readdir(DT)) )
+	{
+		if (strncmp(de->d_name, "tty", 3))
+			continue;
+		if (!de->d_name[3])
+		{
+			// "tty" directory: recurse (needed for ttyACM)
+			sprintf(devfile, "%s/tty", mydevfile);
+			_sysfs_find_tty(detectone, devpath, devfile, prod, pfound);
+			continue;
+		}
+		if (strncmp(&de->d_name[3], "USB", 3) && strncmp(&de->d_name[3], "ACM", 3))
+			continue;
+		
+		
+		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))
+			++*pfound;
+	}
+	closedir(DT);
+	
+out:
+	free(mydevfile);
+}
+
 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;
 	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 ttybuf[0x10], manuf[0x40], prod[0x40], serial[0x40];
+	char prod[0x40];
 	char *devfile, *upfile;
 	char *devfile, *upfile;
 	char found = 0;
 	char found = 0;
 	size_t len, len2;
 	size_t len, len2;
@@ -310,8 +353,6 @@ int _serial_autodetect_sysfs(detectone_func_t detectone, va_list needles)
 		devfile[0] = '/';
 		devfile[0] = '/';
 		++devfile;
 		++devfile;
 		
 		
-		memcpy(ttybuf, "/dev/", 5);
-		
 		while ( (de = readdir(DS)) )
 		while ( (de = readdir(DS)) )
 		{
 		{
 			if (strncmp(de->d_name, upfile, len))
 			if (strncmp(de->d_name, upfile, len))
@@ -320,29 +361,7 @@ int _serial_autodetect_sysfs(detectone_func_t detectone, va_list needles)
 			len2 = strlen(de->d_name);
 			len2 = strlen(de->d_name);
 			memcpy(devfile, de->d_name, len2 + 1);
 			memcpy(devfile, de->d_name, len2 + 1);
 			
 			
-			DT = opendir(devpath);
-			if (!DT)
-				continue;
-			
-			while ( (de = readdir(DT)) )
-			{
-				if (strncmp(de->d_name, "tty", 3))
-					continue;
-				if (strncmp(&de->d_name[3], "USB", 3) && strncmp(&de->d_name[3], "ACM", 3))
-					continue;
-				
-				
-				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;
-			}
-			closedir(DT);
+			_sysfs_find_tty(detectone, devpath, devfile, prod, &found);
 		}
 		}
 		closedir(DS);
 		closedir(DS);
 	}
 	}
@@ -475,62 +494,6 @@ int _serial_autodetect(detectone_func_t detectone, ...)
 	return rv;
 	return rv;
 }
 }
 
 
-int _serial_detect(struct device_drv *api, detectone_func_t detectone, autoscan_func_t autoscan, int flags)
-{
-	struct string_elist *iter, *tmp;
-	const char *dev, *colon;
-	bool inhibitauto = flags & 4;
-	char found = 0;
-	bool forceauto = flags & 1;
-	bool hasname;
-	size_t namel = strlen(api->name);
-	size_t dnamel = strlen(api->dname);
-
-	clear_detectone_meta_info();
-	DL_FOREACH_SAFE(scan_devices, iter, tmp) {
-		dev = iter->string;
-		if ((colon = strchr(dev, ':')) && colon[1] != '\0') {
-			size_t idlen = colon - dev;
-
-			// allow either name:device or dname:device
-			if ((idlen != namel || strncasecmp(dev, api->name, idlen))
-			&&  (idlen != dnamel || strncasecmp(dev, api->dname, idlen)))
-				continue;
-
-			dev = colon + 1;
-			hasname = true;
-		}
-		else
-			hasname = false;
-		if (!strcmp(dev, "auto"))
-			forceauto = true;
-		else if (!strcmp(dev, "noauto"))
-			inhibitauto = true;
-		else
-		if ((flags & 2) && !hasname)
-			continue;
-		else
-		if (!detectone)
-		{}  // do nothing
-		else
-		if (serial_claim(dev, NULL))
-		{
-			applog(LOG_DEBUG, "%s is already claimed... skipping probes", dev);
-			string_elist_del(&scan_devices, iter);
-		}
-		else if (detectone(dev)) {
-			string_elist_del(&scan_devices, iter);
-			inhibitauto = true;
-			++found;
-		}
-	}
-
-	if ((forceauto || !inhibitauto) && autoscan)
-		found += autoscan();
-
-	return found;
-}
-
 enum bfg_device_bus {
 enum bfg_device_bus {
 	BDB_SERIAL,
 	BDB_SERIAL,
 	BDB_USB,
 	BDB_USB,
@@ -643,7 +606,10 @@ void cgpu_copy_libusb_strings(struct cgpu_info *cgpu, libusb_device *usb)
 	if (LIBUSB_SUCCESS != libusb_open(usb, &h))
 	if (LIBUSB_SUCCESS != libusb_open(usb, &h))
 		return;
 		return;
 	if (libusb_get_device_descriptor(usb, &desc))
 	if (libusb_get_device_descriptor(usb, &desc))
+	{
+		libusb_close(h);
 		return;
 		return;
+	}
 	
 	
 	if ((!cgpu->dev_manufacturer) && libusb_get_string_descriptor_ascii(h, desc.iManufacturer, buf, sizeof(buf)) >= 0)
 	if ((!cgpu->dev_manufacturer) && libusb_get_string_descriptor_ascii(h, desc.iManufacturer, buf, sizeof(buf)) >= 0)
 		cgpu->dev_manufacturer = strdup((void *)buf);
 		cgpu->dev_manufacturer = strdup((void *)buf);
@@ -651,6 +617,8 @@ void cgpu_copy_libusb_strings(struct cgpu_info *cgpu, libusb_device *usb)
 		cgpu->dev_product = strdup((void *)buf);
 		cgpu->dev_product = strdup((void *)buf);
 	if ((!cgpu->dev_serial) && libusb_get_string_descriptor_ascii(h, desc.iSerialNumber, buf, sizeof(buf)) >= 0)
 	if ((!cgpu->dev_serial) && libusb_get_string_descriptor_ascii(h, desc.iSerialNumber, buf, sizeof(buf)) >= 0)
 		cgpu->dev_serial = strdup((void *)buf);
 		cgpu->dev_serial = strdup((void *)buf);
+	
+	libusb_close(h);
 }
 }
 #endif
 #endif
 
 
@@ -928,50 +896,6 @@ ssize_t _serial_read(int fd, char *buf, size_t bufsiz, char *eol)
 	return tlen;
 	return tlen;
 }
 }
 
 
-static FILE *_open_bitstream(const char *path, const char *subdir, const char *sub2, const char *filename)
-{
-	char fullpath[PATH_MAX];
-	strcpy(fullpath, path);
-	strcat(fullpath, "/");
-	if (subdir) {
-		strcat(fullpath, subdir);
-		strcat(fullpath, "/");
-	}
-	if (sub2) {
-		strcat(fullpath, sub2);
-		strcat(fullpath, "/");
-	}
-	strcat(fullpath, filename);
-	return fopen(fullpath, "rb");
-}
-#define _open_bitstream(path, subdir, sub2)  do {  \
-	f = _open_bitstream(path, subdir, sub2, filename);  \
-	if (f)  \
-		return f;  \
-} while(0)
-
-#define _open_bitstream2(path, path3)  do {  \
-	_open_bitstream(path, NULL, path3);  \
-	_open_bitstream(path, "../share/" PACKAGE, path3);  \
-} while(0)
-
-#define _open_bitstream3(path)  do {  \
-	_open_bitstream2(path, dname);  \
-	_open_bitstream2(path, "bitstreams");  \
-	_open_bitstream2(path, NULL);  \
-} while(0)
-
-FILE *open_bitstream(const char *dname, const char *filename)
-{
-	FILE *f;
-
-	_open_bitstream3(opt_kernel_path);
-	_open_bitstream3(cgminer_path);
-	_open_bitstream3(".");
-
-	return NULL;
-}
-
 #define bailout(...)  do {  \
 #define bailout(...)  do {  \
 	applog(__VA_ARGS__);  \
 	applog(__VA_ARGS__);  \
 	return NULL;  \
 	return NULL;  \

+ 3 - 19
fpgautils.h

@@ -10,6 +10,8 @@
 #include <libusb.h>
 #include <libusb.h>
 #endif
 #endif
 
 
+#include "deviceapi.h"
+
 struct device_drv;
 struct device_drv;
 struct cgpu_info;
 struct cgpu_info;
 
 
@@ -21,25 +23,8 @@ struct detectone_meta_info_t {
 
 
 // NOTE: Should detectone become run multithreaded, this will become a threadsafe #define
 // NOTE: Should detectone become run multithreaded, this will become a threadsafe #define
 extern struct detectone_meta_info_t detectone_meta_info;
 extern struct detectone_meta_info_t detectone_meta_info;
+extern void clear_detectone_meta_info(void);
 
 
-typedef bool(*detectone_func_t)(const char*);
-typedef int(*autoscan_func_t)();
-
-extern int _serial_detect(struct device_drv *api, detectone_func_t, autoscan_func_t, int flags);
-#define serial_detect_fauto(api, detectone, autoscan)  \
-	_serial_detect(api, detectone, autoscan, 1)
-#define serial_detect_auto(api, detectone, autoscan)  \
-	_serial_detect(api, detectone, autoscan, 0)
-#define serial_detect_auto_byname(api, detectone, autoscan)  \
-	_serial_detect(api, detectone, autoscan, 2)
-#define serial_detect(api, detectone)  \
-	_serial_detect(api, detectone,     NULL, 0)
-#define serial_detect_byname(api, detectone)  \
-	_serial_detect(api, detectone,     NULL, 2)
-#define noserial_detect(api, autoscan)  \
-	_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)
 
 
@@ -61,7 +46,6 @@ extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char *eol);
 	_serial_read(fd, buf, bufsiz, &eol)
 	_serial_read(fd, buf, bufsiz, &eol)
 #define serial_close(fd)  close(fd)
 #define serial_close(fd)  close(fd)
 
 
-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);

+ 1 - 1
ft232r.c

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

+ 3 - 0
icarus-common.h

@@ -94,6 +94,9 @@ struct icarus_state {
 	struct timeval tv_workfinish;
 	struct timeval tv_workfinish;
 	struct work last_work;
 	struct work last_work;
 	bool changework;
 	bool changework;
+	bool identify;
+	
+	uint8_t ob_bin[64];
 };
 };
 
 
 bool icarus_detect_custom(const char *devpath, struct device_drv *, struct ICARUS_INFO *);
 bool icarus_detect_custom(const char *devpath, struct device_drv *, struct ICARUS_INFO *);

+ 37 - 44
logging.c

@@ -25,27 +25,15 @@ bool opt_log_microseconds;
 /* per default priorities higher than LOG_NOTICE are logged */
 /* per default priorities higher than LOG_NOTICE are logged */
 int opt_log_level = LOG_NOTICE;
 int opt_log_level = LOG_NOTICE;
 
 
-static void my_log_curses(int prio, const char *datetime, const char *str)
+static void _my_log_curses(int prio, const char *datetime, const char *str)
 {
 {
-	if (opt_quiet && prio != LOG_ERR)
-		return;
-
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 	extern bool use_curses;
 	extern bool use_curses;
-	if (use_curses && log_curses_only(prio, datetime, str))
+	if (use_curses && _log_curses_only(prio, datetime, str))
 		;
 		;
 	else
 	else
 #endif
 #endif
-	{
-		int cancelstate;
-		bool scs;
-		scs = !pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate);
-		mutex_lock(&console_lock);
-		printf("%s%s%s", datetime, str, "                    \n");
-		mutex_unlock(&console_lock);
-		if (scs)
-			pthread_setcancelstate(cancelstate, &cancelstate);
-	}
+		printf(" %s %s%s", datetime, str, "                    \n");
 }
 }
 
 
 /* high-level logging function, based on global opt_log_level */
 /* high-level logging function, based on global opt_log_level */
@@ -63,45 +51,50 @@ void _applog(int prio, const char *str)
 	if (0) {}
 	if (0) {}
 #endif
 #endif
 	else {
 	else {
-		bool writetocon = opt_debug_console || (opt_log_output && prio != LOG_DEBUG) || prio <= LOG_NOTICE;
+		bool writetocon =
+			(opt_debug_console || (opt_log_output && prio != LOG_DEBUG) || prio <= LOG_NOTICE)
+		 && !(opt_quiet && prio != LOG_ERR);
 		bool writetofile = !isatty(fileno((FILE *)stderr));
 		bool writetofile = !isatty(fileno((FILE *)stderr));
 		if (!(writetocon || writetofile))
 		if (!(writetocon || writetofile))
 			return;
 			return;
 
 
 		char datetime[64];
 		char datetime[64];
-		struct timeval tv = {0, 0};
-		struct tm _tm;
-		struct tm *tm = &_tm;
-
-		cgtime(&tv);
-
-		localtime_r(&tv.tv_sec, tm);
 
 
 		if (opt_log_microseconds)
 		if (opt_log_microseconds)
-			sprintf(datetime, " [%d-%02d-%02d %02d:%02d:%02d.%06ld] ",
-				tm->tm_year + 1900,
-				tm->tm_mon + 1,
-				tm->tm_mday,
-				tm->tm_hour,
-				tm->tm_min,
-				tm->tm_sec,
+		{
+			struct timeval tv;
+			struct tm tm;
+			
+			bfg_init_time();
+			bfg_gettimeofday(&tv);
+			localtime_r(&tv.tv_sec, &tm);
+			
+			sprintf(datetime, "[%d-%02d-%02d %02d:%02d:%02d.%06ld]",
+				tm.tm_year + 1900,
+				tm.tm_mon + 1,
+				tm.tm_mday,
+				tm.tm_hour,
+				tm.tm_min,
+				tm.tm_sec,
 				(long)tv.tv_usec);
 				(long)tv.tv_usec);
+		}
 		else
 		else
-			sprintf(datetime, " [%d-%02d-%02d %02d:%02d:%02d] ",
-				tm->tm_year + 1900,
-				tm->tm_mon + 1,
-				tm->tm_mday,
-				tm->tm_hour,
-				tm->tm_min,
-				tm->tm_sec);
+			get_now_datestamp(datetime);
 
 
-		/* Only output to stderr if it's not going to the screen as well */
-		if (writetofile) {
-			fprintf(stderr, "%s%s\n", datetime, str);	/* atomic write to stderr */
-			fflush(stderr);
-		}
+		if (writetofile || writetocon)
+		{
+			bfg_console_lock();
+			
+			/* Only output to stderr if it's not going to the screen as well */
+			if (writetofile) {
+				fprintf(stderr, " %s %s\n", datetime, str);	/* atomic write to stderr */
+				fflush(stderr);
+			}
 
 
-		if (writetocon)
-			my_log_curses(prio, datetime, str);
+			if (writetocon)
+				_my_log_curses(prio, datetime, str);
+			
+			bfg_console_unlock();
+		}
 	}
 	}
 }
 }

File diff suppressed because it is too large
+ 434 - 127
miner.c


+ 32 - 6
miner.h

@@ -543,6 +543,7 @@ struct cgpu_info {
 
 
 	time_t device_last_well;
 	time_t device_last_well;
 	time_t device_last_not_well;
 	time_t device_last_not_well;
+	struct timeval tv_device_last_not_well;
 	enum dev_reason device_not_well_reason;
 	enum dev_reason device_not_well_reason;
 	float reinit_backoff;
 	float reinit_backoff;
 	int thread_fail_init_count;
 	int thread_fail_init_count;
@@ -904,6 +905,26 @@ extern cglock_t ch_lock;
 extern pthread_rwlock_t mining_thr_lock;
 extern pthread_rwlock_t mining_thr_lock;
 extern pthread_rwlock_t devices_lock;
 extern pthread_rwlock_t devices_lock;
 
 
+
+extern bool _bfg_console_cancel_disabled;
+extern int _bfg_console_prev_cancelstate;
+
+static inline
+void bfg_console_lock(void)
+{
+	_bfg_console_cancel_disabled = !pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &_bfg_console_prev_cancelstate);
+	mutex_lock(&console_lock);
+}
+
+static inline
+void bfg_console_unlock(void)
+{
+	mutex_unlock(&console_lock);
+	if (_bfg_console_cancel_disabled)
+		pthread_setcancelstate(_bfg_console_prev_cancelstate, &_bfg_console_prev_cancelstate);
+}
+
+
 extern void thread_reportin(struct thr_info *thr);
 extern void thread_reportin(struct thr_info *thr);
 extern void thread_reportout(struct thr_info *);
 extern void thread_reportout(struct thr_info *);
 extern void clear_stratum_shares(struct pool *pool);
 extern void clear_stratum_shares(struct pool *pool);
@@ -932,7 +953,7 @@ extern void api(int thr_id);
 
 
 extern struct pool *current_pool(void);
 extern struct pool *current_pool(void);
 extern int enabled_pools;
 extern int enabled_pools;
-extern void get_intrange(char *arg, int *val1, int *val2);
+extern bool get_intrange(const char *arg, int *val1, int *val2);
 extern bool detect_stratum(struct pool *pool, char *url);
 extern bool detect_stratum(struct pool *pool, char *url);
 extern void print_summary(void);
 extern void print_summary(void);
 extern struct pool *add_pool(void);
 extern struct pool *add_pool(void);
@@ -987,7 +1008,8 @@ extern unsigned int new_blocks;
 extern unsigned int found_blocks;
 extern unsigned int found_blocks;
 extern int total_accepted, total_rejected, total_diff1;;
 extern int total_accepted, total_rejected, total_diff1;;
 extern int total_getworks, total_stale, total_discarded;
 extern int total_getworks, total_stale, total_discarded;
-extern uint64_t total_bytes_xfer;
+extern uint64_t total_bytes_rcvd, total_bytes_sent;
+#define total_bytes_xfer (total_bytes_rcvd + total_bytes_sent)
 extern double total_diff_accepted, total_diff_rejected, total_diff_stale;
 extern double total_diff_accepted, total_diff_rejected, total_diff_stale;
 extern unsigned int local_work;
 extern unsigned int local_work;
 extern unsigned int total_go, total_ro;
 extern unsigned int total_go, total_ro;
@@ -1067,12 +1089,13 @@ struct stratum_work {
 	
 	
 	uint8_t header1[36];
 	uint8_t header1[36];
 	uint8_t diffbits[4];
 	uint8_t diffbits[4];
-	uint8_t ntime[4];
+	uint32_t ntime;
+	struct timeval tv_received;
 
 
 	double diff;
 	double diff;
 
 
 	bool transparency_probed;
 	bool transparency_probed;
-	time_t transparency_time;
+	struct timeval tv_transparency;
 	bool opaque;
 	bool opaque;
 };
 };
 
 
@@ -1144,6 +1167,7 @@ struct pool {
 	struct submit_work_state *sws_waiting_on_curl;
 	struct submit_work_state *sws_waiting_on_curl;
 
 
 	time_t last_work_time;
 	time_t last_work_time;
+	struct timeval tv_last_work_time;
 	time_t last_share_time;
 	time_t last_share_time;
 	double last_share_diff;
 	double last_share_diff;
 	uint64_t best_diff;
 	uint64_t best_diff;
@@ -1237,6 +1261,7 @@ struct work {
 	bool		do_foreign_submit;
 	bool		do_foreign_submit;
 
 
 	struct timeval	tv_getwork;
 	struct timeval	tv_getwork;
+	time_t		ts_getwork;
 	struct timeval	tv_getwork_reply;
 	struct timeval	tv_getwork_reply;
 	struct timeval	tv_cloned;
 	struct timeval	tv_cloned;
 	struct timeval	tv_work_start;
 	struct timeval	tv_work_start;
@@ -1248,7 +1273,8 @@ struct work {
 	struct work *next;
 	struct work *next;
 };
 };
 
 
-extern void get_datestamp(char *, struct timeval *);
+extern void get_datestamp(char *, time_t);
+#define get_now_datestamp(buf)  get_datestamp(buf, INVALID_TIMESTAMP)
 extern void inc_hw_errors(struct thr_info *, const struct work *, const uint32_t bad_nonce);
 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)
 #define inc_hw_errors_only(thr)  inc_hw_errors(thr, NULL, 0)
 enum test_nonce2_result {
 enum test_nonce2_result {
@@ -1284,7 +1310,7 @@ extern void write_config(FILE *fcfg);
 extern void zero_bestshare(void);
 extern void zero_bestshare(void);
 extern void zero_stats(void);
 extern void zero_stats(void);
 extern void default_save_file(char *filename);
 extern void default_save_file(char *filename);
-extern bool log_curses_only(int prio, const char *datetime, const char *str);
+extern bool _log_curses_only(int prio, const char *datetime, const char *str);
 extern void clear_logwin(void);
 extern void clear_logwin(void);
 extern void logwin_update(void);
 extern void logwin_update(void);
 extern bool pool_tclear(struct pool *pool, bool *var);
 extern bool pool_tclear(struct pool *pool, bool *var);

+ 7 - 1
miner.php

@@ -994,6 +994,7 @@ function showdatetime()
 global $singlerigsum;
 global $singlerigsum;
 $singlerigsum = array(
 $singlerigsum = array(
  'devs' => array('MHS av' => 1, 'MHS 5s' => 1, 'Accepted' => 1, 'Rejected' => 1,
  'devs' => array('MHS av' => 1, 'MHS 5s' => 1, 'Accepted' => 1, 'Rejected' => 1,
+                 'Temperature' => 2,
 			'Hardware Errors' => 1, 'Utility' => 1, 'Total MH' => 1),
 			'Hardware Errors' => 1, 'Utility' => 1, 'Total MH' => 1),
  'pools' => array('Getworks' => 1, 'Accepted' => 1, 'Rejected' => 1, 'Discarded' => 1,
  'pools' => array('Getworks' => 1, 'Accepted' => 1, 'Rejected' => 1, 'Discarded' => 1,
 			'Stale' => 1, 'Get Failures' => 1, 'Remote Failures' => 1),
 			'Stale' => 1, 'Get Failures' => 1, 'Remote Failures' => 1),
@@ -1151,7 +1152,12 @@ function details($cmd, $list, $rig)
 		||  (isset($dototal['*']) and substr($name, 0, 1) == '*'))
 		||  (isset($dototal['*']) and substr($name, 0, 1) == '*'))
 		{
 		{
 			if (isset($total[$name]))
 			if (isset($total[$name]))
-				$total[$name] += $value;
+			{
+				if ($dototal[$name] == 2)
+					$total[$name] = max($total[$name], $value);
+				else
+					$total[$name] += $value;
+			}
 			else
 			else
 				$total[$name] = $value;
 				$total[$name] = $value;
 		}
 		}

+ 1 - 1
ocl.c

@@ -33,8 +33,8 @@
 
 
 #define OMIT_OPENCL_API
 #define OMIT_OPENCL_API
 
 
+#include "deviceapi.h"
 #include "findnonce.h"
 #include "findnonce.h"
-#include "fpgautils.h"
 #include "ocl.h"
 #include "ocl.h"
 
 
 /* Platform API */
 /* Platform API */

+ 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.3
+PKG_VERSION:=3.1.4
 PKG_RELEASE:=1
 PKG_RELEASE:=1
 
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tbz2
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tbz2

+ 160 - 27
util.c

@@ -117,7 +117,7 @@ static size_t all_data_cb(const void *ptr, size_t size, size_t nmemb,
 	if (db->idlemarker) {
 	if (db->idlemarker) {
 		const unsigned char *cptr = ptr;
 		const unsigned char *cptr = ptr;
 		for (size_t i = 0; i < len; ++i)
 		for (size_t i = 0; i < len; ++i)
-			if (!(isspace(cptr[i]) || cptr[i] == '{')) {
+			if (!(isCspace(cptr[i]) || cptr[i] == '{')) {
 				*db->idlemarker = CURL_SOCKET_BAD;
 				*db->idlemarker = CURL_SOCKET_BAD;
 				db->idlemarker = NULL;
 				db->idlemarker = NULL;
 				break;
 				break;
@@ -182,14 +182,14 @@ static size_t resp_hdr_cb(void *ptr, size_t size, size_t nmemb, void *user_data)
 
 
 	rem = ptr + slen + 1;		/* trim value's leading whitespace */
 	rem = ptr + slen + 1;		/* trim value's leading whitespace */
 	remlen = ptrlen - slen - 1;
 	remlen = ptrlen - slen - 1;
-	while ((remlen > 0) && (isspace(*rem))) {
+	while ((remlen > 0) && (isCspace(*rem))) {
 		remlen--;
 		remlen--;
 		rem++;
 		rem++;
 	}
 	}
 
 
 	memcpy(val, rem, remlen);	/* store value, trim trailing ws */
 	memcpy(val, rem, remlen);	/* store value, trim trailing ws */
 	val[remlen] = 0;
 	val[remlen] = 0;
-	while ((*val) && (isspace(val[strlen(val) - 1])))
+	while ((*val) && (isCspace(val[strlen(val) - 1])))
 		val[strlen(val) - 1] = 0;
 		val[strlen(val) - 1] = 0;
 
 
 	if (!*val)			/* skip blank value */
 	if (!*val)			/* skip blank value */
@@ -339,14 +339,14 @@ static int curl_debug_cb(__maybe_unused CURL *handle, curl_infotype type,
 		case CURLINFO_DATA_IN:
 		case CURLINFO_DATA_IN:
 		case CURLINFO_SSL_DATA_IN:
 		case CURLINFO_SSL_DATA_IN:
 			pool->cgminer_pool_stats.bytes_received += size;
 			pool->cgminer_pool_stats.bytes_received += size;
-			total_bytes_xfer += size;
+			total_bytes_rcvd += size;
 			pool->cgminer_pool_stats.net_bytes_received += size;
 			pool->cgminer_pool_stats.net_bytes_received += size;
 			break;
 			break;
 		case CURLINFO_HEADER_OUT:
 		case CURLINFO_HEADER_OUT:
 		case CURLINFO_DATA_OUT:
 		case CURLINFO_DATA_OUT:
 		case CURLINFO_SSL_DATA_OUT:
 		case CURLINFO_SSL_DATA_OUT:
 			pool->cgminer_pool_stats.bytes_sent += size;
 			pool->cgminer_pool_stats.bytes_sent += size;
-			total_bytes_xfer += size;
+			total_bytes_sent += size;
 			pool->cgminer_pool_stats.net_bytes_sent += size;
 			pool->cgminer_pool_stats.net_bytes_sent += size;
 			break;
 			break;
 		case CURLINFO_TEXT:
 		case CURLINFO_TEXT:
@@ -356,7 +356,7 @@ static int curl_debug_cb(__maybe_unused CURL *handle, curl_infotype type,
 			// data is not null-terminated, so we need to copy and terminate it for applog
 			// data is not null-terminated, so we need to copy and terminate it for applog
 			char datacp[size + 1];
 			char datacp[size + 1];
 			memcpy(datacp, data, size);
 			memcpy(datacp, data, size);
-			while (likely(size) && unlikely(isspace(datacp[size-1])))
+			while (likely(size) && unlikely(isCspace(datacp[size-1])))
 				--size;
 				--size;
 			if (unlikely(!size))
 			if (unlikely(!size))
 				break;
 				break;
@@ -1098,12 +1098,11 @@ void nusleep(unsigned int usecs)
 #endif
 #endif
 }
 }
 
 
-/* This is a cgminer gettimeofday wrapper. Since we always call gettimeofday
- * with tz set to NULL, and windows' default resolution is only 15ms, this
- * gives us higher resolution times on windows. */
-void cgtime(struct timeval *tv)
+static
+void _now_gettimeofday(struct timeval *tv)
 {
 {
 #ifdef WIN32
 #ifdef WIN32
+	// Windows' default resolution is only 15ms. This requests 1ms.
 	timeBeginPeriod(1);
 	timeBeginPeriod(1);
 #endif
 #endif
 	gettimeofday(tv, NULL);
 	gettimeofday(tv, NULL);
@@ -1112,6 +1111,134 @@ void cgtime(struct timeval *tv)
 #endif
 #endif
 }
 }
 
 
+#ifdef HAVE_POOR_GETTIMEOFDAY
+static struct timeval tv_timeofday_offset;
+static struct timeval _tv_timeofday_lastchecked;
+static pthread_mutex_t _tv_timeofday_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static
+void bfg_calibrate_timeofday(struct timeval *expected, char *buf)
+{
+	struct timeval actual, delta;
+	timeradd(expected, &tv_timeofday_offset, expected);
+	_now_gettimeofday(&actual);
+	if (expected->tv_sec >= actual.tv_sec - 1 && expected->tv_sec <= actual.tv_sec + 1)
+		// Within reason - no change necessary
+		return;
+	
+	timersub(&actual, expected, &delta);
+	timeradd(&tv_timeofday_offset, &delta, &tv_timeofday_offset);
+	sprintf(buf, "Recalibrating timeofday offset (delta %ld.%06lds)", (long)delta.tv_sec, (long)delta.tv_usec);
+	*expected = actual;
+}
+
+void bfg_gettimeofday(struct timeval *out)
+{
+	char buf[64] = "";
+	timer_set_now(out);
+	mutex_lock(&_tv_timeofday_mutex);
+	if (_tv_timeofday_lastchecked.tv_sec < out->tv_sec - 21)
+		bfg_calibrate_timeofday(out, buf);
+	else
+		timeradd(out, &tv_timeofday_offset, out);
+	mutex_unlock(&_tv_timeofday_mutex);
+	if (unlikely(buf[0]))
+		applog(LOG_WARNING, "%s", buf);
+}
+#endif
+
+#ifdef WIN32
+static LARGE_INTEGER _perffreq;
+
+static
+void _now_queryperformancecounter(struct timeval *tv)
+{
+	LARGE_INTEGER now;
+	if (unlikely(!QueryPerformanceCounter(&now)))
+		quit(1, "QueryPerformanceCounter failed");
+	
+	*tv = (struct timeval){
+		.tv_sec = now.QuadPart / _perffreq.QuadPart,
+		.tv_usec = (now.QuadPart % _perffreq.QuadPart) * 1000000 / _perffreq.QuadPart,
+	};
+}
+#endif
+
+static
+void _now_is_not_set(__maybe_unused struct timeval *tv)
+{
+	// Might be unclean to swap algorithms after getting a timer
+	quit(1, "timer_set_now called before bfg_init_time");
+}
+
+void (*timer_set_now)(struct timeval *tv) = _now_is_not_set;
+
+#ifdef HAVE_CLOCK_GETTIME_MONOTONIC
+static clockid_t bfg_timer_clk;
+
+static
+void _now_clock_gettime(struct timeval *tv)
+{
+	struct timespec ts;
+	if (unlikely(clock_gettime(bfg_timer_clk, &ts)))
+		quit(1, "clock_gettime failed");
+	
+	*tv = (struct timeval){
+		.tv_sec = ts.tv_sec,
+		.tv_usec = ts.tv_nsec / 1000,
+	};
+}
+
+static
+bool _bfg_try_clock_gettime(clockid_t clk)
+{
+	struct timespec ts;
+	if (clock_gettime(clk, &ts))
+		return false;
+	
+	bfg_timer_clk = clk;
+	timer_set_now = _now_clock_gettime;
+	return true;
+}
+#endif
+
+void bfg_init_time()
+{
+	if (timer_set_now != _now_is_not_set)
+		return;
+	
+#ifdef HAVE_CLOCK_GETTIME_MONOTONIC
+#ifdef HAVE_CLOCK_GETTIME_MONOTONIC_RAW
+	if (_bfg_try_clock_gettime(CLOCK_MONOTONIC_RAW))
+		applog(LOG_DEBUG, "Timers: Using clock_gettime(CLOCK_MONOTONIC_RAW)");
+	else
+#endif
+	if (_bfg_try_clock_gettime(CLOCK_MONOTONIC))
+		applog(LOG_DEBUG, "Timers: Using clock_gettime(CLOCK_MONOTONIC)");
+	else
+#endif
+#ifdef WIN32
+	if (QueryPerformanceFrequency(&_perffreq) && _perffreq.QuadPart)
+	{
+		timer_set_now = _now_queryperformancecounter;
+		applog(LOG_DEBUG, "Timers: Using QueryPerformanceCounter");
+	}
+	else
+#endif
+	{
+		timer_set_now = _now_gettimeofday;
+		applog(LOG_DEBUG, "Timers: Using gettimeofday");
+	}
+	
+#ifdef HAVE_POOR_GETTIMEOFDAY
+	char buf[64] = "";
+	struct timeval tv;
+	timer_set_now(&tv);
+	bfg_calibrate_timeofday(&tv, buf);
+	applog(LOG_DEBUG, "%s", buf);
+#endif
+}
+
 void subtime(struct timeval *a, struct timeval *b)
 void subtime(struct timeval *a, struct timeval *b)
 {
 {
 	timersub(a, b, b);
 	timersub(a, b, b);
@@ -1239,12 +1366,12 @@ static enum send_ret __stratum_send(struct pool *pool, char *s, ssize_t len)
 
 
 	pool->cgminer_pool_stats.times_sent++;
 	pool->cgminer_pool_stats.times_sent++;
 	pool->cgminer_pool_stats.bytes_sent += ssent;
 	pool->cgminer_pool_stats.bytes_sent += ssent;
-	total_bytes_xfer += ssent;
+	total_bytes_sent += ssent;
 	pool->cgminer_pool_stats.net_bytes_sent += ssent;
 	pool->cgminer_pool_stats.net_bytes_sent += ssent;
 	return SEND_OK;
 	return SEND_OK;
 }
 }
 
 
-bool stratum_send(struct pool *pool, char *s, ssize_t len)
+bool _stratum_send(struct pool *pool, char *s, ssize_t len, bool force)
 {
 {
 	enum send_ret ret = SEND_INACTIVE;
 	enum send_ret ret = SEND_INACTIVE;
 
 
@@ -1252,7 +1379,7 @@ bool stratum_send(struct pool *pool, char *s, ssize_t len)
 		applog(LOG_DEBUG, "Pool %u: SEND: %s", pool->pool_no, s);
 		applog(LOG_DEBUG, "Pool %u: SEND: %s", pool->pool_no, s);
 
 
 	mutex_lock(&pool->stratum_lock);
 	mutex_lock(&pool->stratum_lock);
-	if (pool->stratum_active)
+	if (pool->stratum_active || force)
 		ret = __stratum_send(pool, s, len);
 		ret = __stratum_send(pool, s, len);
 	mutex_unlock(&pool->stratum_lock);
 	mutex_unlock(&pool->stratum_lock);
 
 
@@ -1409,7 +1536,7 @@ char *recv_line(struct pool *pool)
 
 
 	pool->cgminer_pool_stats.times_received++;
 	pool->cgminer_pool_stats.times_received++;
 	pool->cgminer_pool_stats.bytes_received += len;
 	pool->cgminer_pool_stats.bytes_received += len;
-	total_bytes_xfer += len;
+	total_bytes_rcvd += len;
 	pool->cgminer_pool_stats.net_bytes_received += len;
 	pool->cgminer_pool_stats.net_bytes_received += len;
 
 
 out:
 out:
@@ -1451,7 +1578,7 @@ char *json_dumps_ANY(json_t *json, size_t flags)
 	if (!s)
 	if (!s)
 		return NULL;
 		return NULL;
 	for (i = 0; s[i] != '['; ++i)
 	for (i = 0; s[i] != '['; ++i)
-		if (unlikely(!(s[i] && isspace(s[i]))))
+		if (unlikely(!(s[i] && isCspace(s[i]))))
 			quit(1, "json_dumps_ANY failed to find opening bracket in array dump");
 			quit(1, "json_dumps_ANY failed to find opening bracket in array dump");
 	len = strlen(&s[++i]) - 1;
 	len = strlen(&s[++i]) - 1;
 	if (unlikely(s[i+len] != ']'))
 	if (unlikely(s[i+len] != ']'))
@@ -1503,8 +1630,8 @@ void stratum_probe_transparency(struct pool *pool)
 	        pool->swork.job_id,
 	        pool->swork.job_id,
 	        pool->swork.job_id);
 	        pool->swork.job_id);
 	stratum_send(pool, s, sLen);
 	stratum_send(pool, s, sLen);
-	if ((!pool->swork.opaque) && pool->swork.transparency_time == (time_t)-1)
-		pool->swork.transparency_time = time(NULL);
+	if ((!pool->swork.opaque) && !timer_isset(&pool->swork.tv_transparency))
+		cgtime(&pool->swork.tv_transparency);
 	pool->swork.transparency_probed = true;
 	pool->swork.transparency_probed = true;
 }
 }
 
 
@@ -1541,6 +1668,7 @@ static bool parse_notify(struct pool *pool, json_t *val)
 		goto out;
 		goto out;
 
 
 	cg_wlock(&pool->data_lock);
 	cg_wlock(&pool->data_lock);
+	cgtime(&pool->swork.tv_received);
 	free(pool->swork.job_id);
 	free(pool->swork.job_id);
 	pool->swork.job_id = job_id;
 	pool->swork.job_id = job_id;
 	pool->submit_old = !clean;
 	pool->submit_old = !clean;
@@ -1548,7 +1676,8 @@ static bool parse_notify(struct pool *pool, json_t *val)
 	
 	
 	hex2bin(&pool->swork.header1[0], bbversion,  4);
 	hex2bin(&pool->swork.header1[0], bbversion,  4);
 	hex2bin(&pool->swork.header1[4], prev_hash, 32);
 	hex2bin(&pool->swork.header1[4], prev_hash, 32);
-	hex2bin(&pool->swork.ntime[0], ntime, 4);
+	hex2bin((void*)&pool->swork.ntime, ntime, 4);
+	pool->swork.ntime = be32toh(pool->swork.ntime);
 	hex2bin(&pool->swork.diffbits[0], nbit, 4);
 	hex2bin(&pool->swork.diffbits[0], nbit, 4);
 	
 	
 	cb1_len = strlen(coinbase1) / 2;
 	cb1_len = strlen(coinbase1) / 2;
@@ -1590,7 +1719,7 @@ static bool parse_notify(struct pool *pool, json_t *val)
 	pool->getwork_requested++;
 	pool->getwork_requested++;
 	total_getworks++;
 	total_getworks++;
 
 
-	if ((merkles && (!pool->swork.transparency_probed || rand() <= RAND_MAX / (opt_skip_checks + 1))) || pool->swork.transparency_time != (time_t)-1)
+	if ((merkles && (!pool->swork.transparency_probed || rand() <= RAND_MAX / (opt_skip_checks + 1))) || timer_isset(&pool->swork.tv_transparency))
 		if (pool->stratum_init)
 		if (pool->stratum_init)
 			stratum_probe_transparency(pool);
 			stratum_probe_transparency(pool);
 
 
@@ -1836,10 +1965,11 @@ static bool setup_stratum_curl(struct pool *pool)
 	char curl_err_str[CURL_ERROR_SIZE];
 	char curl_err_str[CURL_ERROR_SIZE];
 	CURL *curl = NULL;
 	CURL *curl = NULL;
 	char s[RBUFSIZE];
 	char s[RBUFSIZE];
+	bool ret = false;
 
 
 	applog(LOG_DEBUG, "initiate_stratum with sockbuf=%p", pool->sockbuf);
 	applog(LOG_DEBUG, "initiate_stratum with sockbuf=%p", pool->sockbuf);
 	mutex_lock(&pool->stratum_lock);
 	mutex_lock(&pool->stratum_lock);
-	pool->swork.transparency_time = (time_t)-1;
+	timer_unset(&pool->swork.tv_transparency);
 	pool->stratum_active = false;
 	pool->stratum_active = false;
 	pool->stratum_notify = false;
 	pool->stratum_notify = false;
 	pool->swork.transparency_probed = false;
 	pool->swork.transparency_probed = false;
@@ -1850,7 +1980,6 @@ static bool setup_stratum_curl(struct pool *pool)
 		quit(1, "Failed to curl_easy_init in initiate_stratum");
 		quit(1, "Failed to curl_easy_init in initiate_stratum");
 	if (pool->sockbuf)
 	if (pool->sockbuf)
 		pool->sockbuf[0] = '\0';
 		pool->sockbuf[0] = '\0';
-	mutex_unlock(&pool->stratum_lock);
 
 
 	curl = pool->stratum_curl;
 	curl = pool->stratum_curl;
 
 
@@ -1893,23 +2022,26 @@ static bool setup_stratum_curl(struct pool *pool)
 	pool->sock = INVSOCK;
 	pool->sock = INVSOCK;
 	if (curl_easy_perform(curl)) {
 	if (curl_easy_perform(curl)) {
 		applog(LOG_INFO, "Stratum connect failed to pool %d: %s", pool->pool_no, curl_err_str);
 		applog(LOG_INFO, "Stratum connect failed to pool %d: %s", pool->pool_no, curl_err_str);
+errout:
 		curl_easy_cleanup(curl);
 		curl_easy_cleanup(curl);
 		pool->stratum_curl = NULL;
 		pool->stratum_curl = NULL;
-		return false;
+		goto out;
 	}
 	}
 	if (pool->sock == INVSOCK)
 	if (pool->sock == INVSOCK)
 	{
 	{
-		pool->stratum_curl = NULL;
-		curl_easy_cleanup(curl);
 		applog(LOG_ERR, "Stratum connect succeeded, but technical problem extracting socket (pool %u)", pool->pool_no);
 		applog(LOG_ERR, "Stratum connect succeeded, but technical problem extracting socket (pool %u)", pool->pool_no);
-		return false;
+		goto errout;
 	}
 	}
 	keep_sockalive(pool->sock);
 	keep_sockalive(pool->sock);
 
 
 	pool->cgminer_pool_stats.times_sent++;
 	pool->cgminer_pool_stats.times_sent++;
 	pool->cgminer_pool_stats.times_received++;
 	pool->cgminer_pool_stats.times_received++;
+	ret = true;
 
 
-	return true;
+out:
+	mutex_unlock(&pool->stratum_lock);
+	
+	return ret;
 }
 }
 
 
 static char *get_sessionid(json_t *val)
 static char *get_sessionid(json_t *val)
@@ -1982,7 +2114,7 @@ resend:
 			sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": [\""PACKAGE"/"VERSION"\"]}", swork_id++);
 			sprintf(s, "{\"id\": %d, \"method\": \"mining.subscribe\", \"params\": [\""PACKAGE"/"VERSION"\"]}", swork_id++);
 	}
 	}
 
 
-	if (__stratum_send(pool, s, strlen(s)) != SEND_OK) {
+	if (!_stratum_send(pool, s, strlen(s), true)) {
 		applog(LOG_DEBUG, "Failed to send s in initiate_stratum");
 		applog(LOG_DEBUG, "Failed to send s in initiate_stratum");
 		goto out;
 		goto out;
 	}
 	}
@@ -2099,6 +2231,7 @@ bool restart_stratum(struct pool *pool)
 void dev_error(struct cgpu_info *dev, enum dev_reason reason)
 void dev_error(struct cgpu_info *dev, enum dev_reason reason)
 {
 {
 	dev->device_last_not_well = time(NULL);
 	dev->device_last_not_well = time(NULL);
+	cgtime(&dev->tv_device_last_not_well);
 	dev->device_not_well_reason = reason;
 	dev->device_not_well_reason = reason;
 
 
 	switch (reason) {
 	switch (reason) {

+ 75 - 8
util.h

@@ -13,11 +13,16 @@
 #ifndef __UTIL_H__
 #ifndef __UTIL_H__
 #define __UTIL_H__
 #define __UTIL_H__
 
 
+#include <stdbool.h>
+#include <sys/time.h>
+
 #include <curl/curl.h>
 #include <curl/curl.h>
 #include <jansson.h>
 #include <jansson.h>
 
 
 #include "compat.h"
 #include "compat.h"
 
 
+#define INVALID_TIMESTAMP ((time_t)-1)
+
 #if defined(unix) || defined(__APPLE__)
 #if defined(unix) || defined(__APPLE__)
 	#include <errno.h>
 	#include <errno.h>
 	#include <sys/socket.h>
 	#include <sys/socket.h>
@@ -69,6 +74,18 @@
 #endif
 #endif
 extern char *json_dumps_ANY(json_t *, size_t flags);
 extern char *json_dumps_ANY(json_t *, size_t flags);
 
 
+static inline
+bool isCspace(int c)
+{
+	switch (c)
+	{
+		case ' ': case '\f': case '\n': case '\r': case '\t': case '\v':
+			return true;
+		default:
+			return false;
+	}
+}
+
 struct thr_info;
 struct thr_info;
 struct pool;
 struct pool;
 enum dev_reason;
 enum dev_reason;
@@ -90,7 +107,6 @@ void thr_info_freeze(struct thr_info *thr);
 void thr_info_cancel(struct thr_info *thr);
 void thr_info_cancel(struct thr_info *thr);
 void nmsleep(unsigned int msecs);
 void nmsleep(unsigned int msecs);
 void nusleep(unsigned int usecs);
 void nusleep(unsigned int usecs);
-void cgtime(struct timeval *tv);
 void subtime(struct timeval *a, struct timeval *b);
 void subtime(struct timeval *a, struct timeval *b);
 void addtime(struct timeval *a, struct timeval *b);
 void addtime(struct timeval *a, struct timeval *b);
 bool time_more(struct timeval *a, struct timeval *b);
 bool time_more(struct timeval *a, struct timeval *b);
@@ -98,7 +114,8 @@ bool time_less(struct timeval *a, struct timeval *b);
 void copy_time(struct timeval *dest, const struct timeval *src);
 void copy_time(struct timeval *dest, const struct timeval *src);
 double us_tdiff(struct timeval *end, struct timeval *start);
 double us_tdiff(struct timeval *end, struct timeval *start);
 double tdiff(struct timeval *end, struct timeval *start);
 double tdiff(struct timeval *end, struct timeval *start);
-bool stratum_send(struct pool *pool, char *s, ssize_t len);
+bool _stratum_send(struct pool *pool, char *s, ssize_t len, bool force);
+#define stratum_send(pool, s, len)  _stratum_send(pool, s, len, false)
 bool sock_full(struct pool *pool);
 bool sock_full(struct pool *pool);
 char *recv_line(struct pool *pool);
 char *recv_line(struct pool *pool);
 bool parse_method(struct pool *pool, char *s);
 bool parse_method(struct pool *pool, char *s);
@@ -209,6 +226,22 @@ void set_maxfd(int *p_maxfd, int fd)
 }
 }
 
 
 
 
+static inline
+void timer_unset(struct timeval *tvp)
+{
+	tvp->tv_sec = -1;
+}
+
+static inline
+bool timer_isset(const struct timeval *tvp)
+{
+	return tvp->tv_sec != -1;
+}
+
+extern void (*timer_set_now)(struct timeval *);
+extern void bfg_init_time();
+#define cgtime(tvp)  timer_set_now(tvp)
+
 #define TIMEVAL_USECS(usecs)  (  \
 #define TIMEVAL_USECS(usecs)  (  \
 	(struct timeval){  \
 	(struct timeval){  \
 		.tv_sec = (usecs) / 1000000,  \
 		.tv_sec = (usecs) / 1000000,  \
@@ -223,29 +256,63 @@ void set_maxfd(int *p_maxfd, int fd)
 
 
 #define timer_set_delay_from_now(tvp_timer, usecs)  do {  \
 #define timer_set_delay_from_now(tvp_timer, usecs)  do {  \
 	struct timeval tv_now;  \
 	struct timeval tv_now;  \
-	gettimeofday(&tv_now, NULL);  \
+	timer_set_now(&tv_now);  \
 	timer_set_delay(tvp_timer, &tv_now, usecs);  \
 	timer_set_delay(tvp_timer, &tv_now, usecs);  \
 } while(0)
 } while(0)
 
 
 static inline
 static inline
-bool timer_passed(struct timeval *tvp_timer, struct timeval *tvp_now)
+const struct timeval *_bfg_nullisnow(const struct timeval *tvp, struct timeval *tvp_buf)
+{
+	if (tvp)
+		return tvp;
+	cgtime(tvp_buf);
+	return tvp_buf;
+}
+
+static inline
+int timer_elapsed(const struct timeval *tvp_timer, const struct timeval *tvp_now)
+{
+	struct timeval tv;
+	const struct timeval *_tvp_now = _bfg_nullisnow(tvp_now, &tv);
+	timersub(_tvp_now, tvp_timer, &tv);
+	return tv.tv_sec;
+}
+
+static inline
+bool timer_passed(const struct timeval *tvp_timer, const struct timeval *tvp_now)
 {
 {
-	return (tvp_timer->tv_sec != -1 && timercmp(tvp_timer, tvp_now, <));
+	if (!timer_isset(tvp_timer))
+		return false;
+	
+	struct timeval tv;
+	const struct timeval *_tvp_now = _bfg_nullisnow(tvp_now, &tv);
+	
+	return timercmp(tvp_timer, _tvp_now, <);
 }
 }
 
 
+#if defined(WIN32) && !defined(HAVE_POOR_GETTIMEOFDAY)
+#define HAVE_POOR_GETTIMEOFDAY
+#endif
+
+#ifdef HAVE_POOR_GETTIMEOFDAY
+extern void bfg_gettimeofday(struct timeval *);
+#else
+#define bfg_gettimeofday(out)  gettimeofday(out, NULL)
+#endif
+
 static inline
 static inline
 void reduce_timeout_to(struct timeval *tvp_timeout, struct timeval *tvp_time)
 void reduce_timeout_to(struct timeval *tvp_timeout, struct timeval *tvp_time)
 {
 {
-	if (tvp_time->tv_sec == -1)
+	if (!timer_isset(tvp_time))
 		return;
 		return;
-	if (tvp_timeout->tv_sec == -1 /* no timeout */ || timercmp(tvp_time, tvp_timeout, <))
+	if ((!timer_isset(tvp_timeout)) || timercmp(tvp_time, tvp_timeout, <))
 		*tvp_timeout = *tvp_time;
 		*tvp_timeout = *tvp_time;
 }
 }
 
 
 static inline
 static inline
 struct timeval *select_timeout(struct timeval *tvp_timeout, struct timeval *tvp_now)
 struct timeval *select_timeout(struct timeval *tvp_timeout, struct timeval *tvp_now)
 {
 {
-	if (tvp_timeout->tv_sec == -1)
+	if (!timer_isset(tvp_timeout))
 		return NULL;
 		return NULL;
 	
 	
 	if (timercmp(tvp_timeout, tvp_now, <))
 	if (timercmp(tvp_timeout, tvp_now, <))

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