Browse Source

Merge tag 'bfgminer-3.1.0' into bigpic

BFGMiner version 3.1.0
Luke Dashjr 12 years ago
parent
commit
6c14772c5b
26 changed files with 1090 additions and 423 deletions
  1. 6 0
      .gitmodules
  2. BIN
      API.class
  3. 0 166
      API.java
  4. 37 12
      Makefile.am
  5. 529 0
      NEWS
  6. 1 1
      README
  7. 0 6
      README.RPC
  8. 1 1
      api.c
  9. 1 0
      bitstreams/src/X6000_ztex_comm4
  10. 1 0
      bitstreams/src/ZtexBTCMiner
  11. 6 5
      configure.ac
  12. 0 1
      debian/bfgminer.docs
  13. 16 4
      deviceapi.c
  14. 55 67
      driver-avalon.c
  15. 3 0
      driver-avalon.h
  16. 316 43
      driver-bitforce.c
  17. 9 6
      driver-icarus.c
  18. 13 22
      driver-ztex.c
  19. 2 0
      fpgautils.h
  20. 19 21
      libztex.c
  21. 0 22
      libztex.h
  22. 4 6
      make-release
  23. 65 34
      miner.c
  24. 3 0
      miner.h
  25. 1 4
      ocl.c
  26. 2 2
      openwrt/bfgminer/Makefile

+ 6 - 0
.gitmodules

@@ -1,3 +1,9 @@
 [submodule "libblkmaker"]
 [submodule "libblkmaker"]
 	path = libblkmaker
 	path = libblkmaker
 	url = git://gitorious.org/bitcoin/libblkmaker.git
 	url = git://gitorious.org/bitcoin/libblkmaker.git
+[submodule "bitstream/X6000_ztex_comm4"]
+	path = bitstreams/src/X6000_ztex_comm4
+	url = git://github.com/luke-jr/X6000_ztex_comm4.git
+[submodule "bitstream/ZtexBTCMiner"]
+	path = bitstreams/src/ZtexBTCMiner
+	url = git://github.com/luke-jr/ZtexBTCMiner.git

BIN
API.class


+ 0 - 166
API.java

@@ -1,166 +0,0 @@
-/*
- *
- * Copyright (C) Andrew Smith 2012-2013
- *
- * Usage: java API command ip port
- *
- * If any are missing or blank they use the defaults:
- *
- *	command = 'summary'
- *	ip	= '127.0.0.1'
- *	port	= '4028'
- *
- */
-
-import java.net.*;
-import java.io.*;
-
-class API
-{
-	static private final int MAXRECEIVESIZE = 65535;
-
-	static private Socket socket = null;
-
-	private void closeAll() throws Exception
-	{
-		if (socket != null)
-		{
-			socket.close();
-			socket = null;
-		}
-	}
-
-	public void display(String result) throws Exception
-	{
-		String value;
-		String name;
-		String[] sections = result.split("\\|", 0);
-
-		for (int i = 0; i < sections.length; i++)
-		{
-			if (sections[i].trim().length() > 0)
-			{
-				String[] data = sections[i].split(",", 0);
-
-				for (int j = 0; j < data.length; j++)
-				{
-					String[] nameval = data[j].split("=", 2);
-
-					if (j == 0)
-					{
-						if (nameval.length > 1
-						&&  Character.isDigit(nameval[1].charAt(0)))
-							name = nameval[0] + nameval[1];
-						else
-							name = nameval[0];
-
-						System.out.println("[" + name + "] =>");
-						System.out.println("(");
-					}
-
-					if (nameval.length > 1)
-					{
-						name = nameval[0];
-						value = nameval[1];
-					}
-					else
-					{
-						name = "" + j;
-						value = nameval[0];
-					}
-
-					System.out.println("   ["+name+"] => "+value);
-				}
-				System.out.println(")");
-			}
-		}
-	}
-
-	public void process(String cmd, InetAddress ip, int port) throws Exception
-	{
-		StringBuffer sb = new StringBuffer();
-		char buf[] = new char[MAXRECEIVESIZE];
-		int len = 0;
-
-System.out.println("Attempting to send '"+cmd+"' to "+ip.getHostAddress()+":"+port);
-
-		try
-		{
-			socket = new Socket(ip, port);
-			PrintStream ps = new PrintStream(socket.getOutputStream());
-			ps.print(cmd.toLowerCase().toCharArray());
-			ps.flush();
-
-			InputStreamReader isr = new InputStreamReader(socket.getInputStream());
-			while (0x80085 > 0)
-			{
-				len = isr.read(buf, 0, MAXRECEIVESIZE);
-				if (len < 1)
-					break;
-				sb.append(buf, 0, len);
-				if (buf[len-1] == '\0')
-					break;
-			}
-
-			closeAll();
-		}
-		catch (IOException ioe)
-		{
-			System.err.println(ioe.toString());
-			closeAll();
-			return;
-		}
-
-		String result = sb.toString();
-
-		System.out.println("Answer='"+result+"'");
-
-		display(result);
-	}
-
-	public API(String command, String _ip, String _port) throws Exception
-	{
-		InetAddress ip;
-		int port;
-
-		try
-		{
-			ip = InetAddress.getByName(_ip);
-		}
-		catch (UnknownHostException uhe)
-		{
-			System.err.println("Unknown host " + _ip + ": " + uhe);
-			return;
-		}
-
-		try
-		{
-			port = Integer.parseInt(_port);
-		}
-		catch (NumberFormatException nfe)
-		{
-			System.err.println("Invalid port " + _port + ": " + nfe);
-			return;
-		}
-
-		process(command, ip, port);
-	}
-
-	public static void main(String[] params) throws Exception
-	{
-		String command = "summary";
-		String ip = "127.0.0.1";
-		String port = "4028";
-
-		if (params.length > 0 && params[0].trim().length() > 0)
-			command = params[0].trim();
-
-		if (params.length > 1 && params[1].trim().length() > 0)
-			ip = params[1].trim();
-
-		if (params.length > 2 && params[2].trim().length() > 0)
-			port = params[2].trim();
-
-		new API(command, ip, port);
-	}
-}

+ 37 - 12
Makefile.am

@@ -10,12 +10,24 @@
 
 
 ACLOCAL_AMFLAGS = -I m4
 ACLOCAL_AMFLAGS = -I m4
 
 
-EXTRA_DIST	= example.conf m4/gnulib-cache.m4 linux-usb-bfgminer \
-		  api-example.php miner.php	\
-		  API.class API.java api-example.c windows-build.txt \
-		  bitstreams/* README.FPGA README.RPC README.scrypt \
+EXTRA_DIST	= \
+	m4/gnulib-cache.m4 \
+	linux-usb-bfgminer \
+	windows-build.txt
+
+dist_doc_DATA = \
+		  AUTHORS COPYING HACKING NEWS README \
+		  example.conf \
 		  README.ASIC \
 		  README.ASIC \
+		  README.FPGA \
 		  README.GPU \
 		  README.GPU \
+		  README.RPC \
+		  README.scrypt
+
+rpcexamplesdir = $(docdir)/rpc-examples
+dist_rpcexamples_DATA = \
+		  api-example.php miner.php \
+		  api-example.c \
                   api-example.py
                   api-example.py
 
 
 SUBDIRS		= lib ccan
 SUBDIRS		= lib ccan
@@ -24,8 +36,6 @@ INCLUDES	= -fno-strict-aliasing
 
 
 bin_PROGRAMS	= bfgminer
 bin_PROGRAMS	= bfgminer
 
 
-bin_SCRIPTS	= $(top_srcdir)/*.cl
-
 bfgminer_LDFLAGS	= $(PTHREAD_FLAGS)
 bfgminer_LDFLAGS	= $(PTHREAD_FLAGS)
 bfgminer_LDADD	= $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
 bfgminer_LDADD	= $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
 		  @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \
 		  @NCURSES_LIBS@ @PDCURSES_LIBS@ @WS2_LIBS@ \
@@ -33,6 +43,8 @@ bfgminer_LDADD	= $(DLOPEN_FLAGS) @LIBCURL_LIBS@ @JANSSON_LIBS@ @PTHREAD_LIBS@ \
 		  @MATH_LIBS@ lib/libgnu.a ccan/libccan.a
 		  @MATH_LIBS@ lib/libgnu.a ccan/libccan.a
 bfgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @LIBUSB_CFLAGS@ @LIBCURL_CFLAGS@
 bfgminer_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib @LIBUSB_CFLAGS@ @LIBCURL_CFLAGS@
 
 
+bfgminer_CPPFLAGS += -DCGMINER_PREFIX='"$(pkgdatadir)"'
+
 bfgminer_CPPFLAGS += @JANSSON_CFLAGS@
 bfgminer_CPPFLAGS += @JANSSON_CFLAGS@
 bfgminer_CPPFLAGS += $(PTHREAD_FLAGS)
 bfgminer_CPPFLAGS += $(PTHREAD_FLAGS)
 bfgminer_CPPFLAGS += $(NCURSES_CPPFLAGS)
 bfgminer_CPPFLAGS += $(NCURSES_CPPFLAGS)
@@ -50,6 +62,9 @@ bfgminer_SOURCES	+= miner.h compat.h bench_block.h	\
 		   sha2.c sha2.h api.c
 		   sha2.c sha2.h api.c
 bfgminer_DEPENDENCIES =
 bfgminer_DEPENDENCIES =
 
 
+bitstreamsdir = $(pkgdatadir)/bitstreams
+dist_bitstreams_DATA =
+
 if NEED_LIBBLKMAKER
 if NEED_LIBBLKMAKER
 SUBDIRS           += libblkmaker
 SUBDIRS           += libblkmaker
 
 
@@ -64,19 +79,28 @@ endif
 
 
 bfgminer_SOURCES	+= logging.c
 bfgminer_SOURCES	+= logging.c
 
 
+
 # GPU sources, TODO: make them selectable
 # GPU sources, TODO: make them selectable
 # the GPU portion extracted from original main.c
 # the GPU portion extracted from original main.c
 bfgminer_SOURCES += driver-opencl.h driver-opencl.c
 bfgminer_SOURCES += driver-opencl.h driver-opencl.c
 
 
+if HAVE_OPENCL
+
 # the original GPU related sources, unchanged
 # the original GPU related sources, unchanged
 bfgminer_SOURCES += ocl.c ocl.h findnonce.c findnonce.h
 bfgminer_SOURCES += ocl.c ocl.h findnonce.c findnonce.h
 bfgminer_SOURCES += adl.c adl.h adl_functions.h
 bfgminer_SOURCES += adl.c adl.h adl_functions.h
 bfgminer_SOURCES += *.cl
 bfgminer_SOURCES += *.cl
 
 
+kernelsdir = $(pkgdatadir)/opencl
+dist_kernels_DATA = $(top_srcdir)/*.cl
+
 if HAVE_SENSORS
 if HAVE_SENSORS
 bfgminer_LDADD += $(sensors_LIBS)
 bfgminer_LDADD += $(sensors_LIBS)
 endif
 endif
 
 
+endif
+
+
 if HAS_SCRYPT
 if HAS_SCRYPT
 bfgminer_SOURCES += scrypt.c scrypt.h
 bfgminer_SOURCES += scrypt.c scrypt.h
 endif
 endif
@@ -149,20 +173,21 @@ endif
 
 
 if HAS_MODMINER
 if HAS_MODMINER
 bfgminer_SOURCES += driver-modminer.c
 bfgminer_SOURCES += driver-modminer.c
-bitstreamsdir = $(bindir)/bitstreams
-dist_bitstreams_DATA = $(top_srcdir)/bitstreams/*
 endif
 endif
 
 
 if HAS_X6500
 if HAS_X6500
 bfgminer_SOURCES += driver-x6500.c ft232r.c ft232r.h jtag.c jtag.h
 bfgminer_SOURCES += driver-x6500.c ft232r.c ft232r.h jtag.c jtag.h
-bitstreamsdir = $(bindir)/bitstreams
-dist_bitstreams_DATA = $(top_srcdir)/bitstreams/*
+endif
+
+if NEED_BITSTREAM_FPGAMINER
+dist_bitstreams_DATA += $(top_srcdir)/bitstreams/fpgaminer*.bit
+dist_doc_DATA += $(top_srcdir)/bitstreams/COPYING_fpgaminer
 endif
 endif
 
 
 if HAS_ZTEX
 if HAS_ZTEX
 bfgminer_SOURCES += driver-ztex.c libztex.c libztex.h
 bfgminer_SOURCES += driver-ztex.c libztex.c libztex.h
-bitstreamsdir = $(bindir)/bitstreams
-dist_bitstreams_DATA = $(top_srcdir)/bitstreams/*
+dist_bitstreams_DATA += $(top_srcdir)/bitstreams/ztex_*.bi?
+dist_doc_DATA += $(top_srcdir)/bitstreams/COPYING_ztex
 endif
 endif
 
 
 bin_PROGRAMS += bfgminer-rpc
 bin_PROGRAMS += bfgminer-rpc

+ 529 - 0
NEWS

@@ -1,3 +1,532 @@
+BFGMiner Version 3.1.0 - June 13, 2013
+- Bugfix: openwrt: Expect fixed bitstream path for input
+- Improve Makefile organization and fix "make install"
+- icarus: Upgrade work division autodetection probe to be faster and also detect
+8 core
+- Calculate rejection percentage based on weighed shares, not absolute counts
+- Count weighed discarded (stale) shares per cgpu
+- Bugfix: Cleanly count discarded (stale) shares without overlapping
+devices/sshare locks within clear_stratum_shares
+- configure: Enable Avalon support by default now that it behaves reasonably
+- avalon: Since detection is not really implemented, only probe devices when the
+driver is specified to -S by name (eg, "avalon:/dev/ttyUSB0")
+- Bugfix: bitforce_queue: Never try to reinitialize a slave processor
+- Bugfix: bitforce_queue: Use work_list_del everywhere we remove from work_list
+to ensure work gets freed properly when done
+- Reduce HW error logging to debug level, so it doesn't clutter the TUI log by
+default
+- DevAPI: When a device has more than 26 processors, represent them as aa-zz
+- bitforce: bitforce: Fix TUI display of slave processors on parallelized boards
+- bitforce: Only display temperature in TUI for the first chip on parallelized
+boards
+- Bugfix: bitforce: Set temperature for all processors on the board
+- Bugfix: bitforce_queue: Initialize proc->device_data to board data for
+parallelized chip processors
+- Bugfix: bitforce_queue: Defer nonce count check until after thiswork has been
+identified (or handled as NULL)
+- avalon: avalon_clear_readbuf can simply wait for a single read timeout on
+Windows to avoid select
+- avalon: Simplify avalon_get_result by using avalon_gets
+- avalon: Go back to good old serial timeouts for gets, since select() is for
+sockets (only, on Windows)
+- Updated api.c to return the hashrate with 3 decimal places
+- Change hashrate display to never display 3 fractional digits, because it looks
+a bit ugly
+- bitforce: Credit hashrate to the correct chip on parallelized devices
+- Re-set work thr_id on share submissions, to ensure the result gets credited to
+the correct device in case of shared job queues (as in BitForce long boards)
+- bitforce: Turn parallelization into separate logical processors for more
+details on each, including working with XLink
+- bitforce_queue: Implement job sanity checks using new "ZqX" for devices using
+parallelization
+- bitforce_queue: Minimal support for parallelization
+- Add --device-protocol-dump option to debuglog low-level bitforce protocol
+details
+- When shutting down, set work restart flag (and trigger notifier) to help
+mining threads escape to their main minerloop (and check for shutdown)
+- Document and check for uthash version 1.9.2+
+- Bugfix: Don't report failure for graceful mining thread shutdown
+- Name devices in mining thread failures
+- Warn about killing mining threads
+- Bugfix: Wake up mining threads when asking them to shutdown
+- Disable pthread cancel within curses locking
+- Shorten the avalon statline to fit in the curses interface and show the lowest
+speed fan cooling the asic devices.
+- Change switch_compact function name to switch_logsize to be used for other
+changes.
+- Only adjust cursor positions with curses locked.
+- devs display - fix GPU duplicate bug
+- basic copyright statement in API.java
+- Change the --device parameter parsing and configuration to accept ranges and
+comma separated values.
+- Modify scrypt kernel message.
+- Check for pool_disabled in wait_lp_current
+- Check for pool enabled in cnx_needed.
+- Add README.ASIC to debian packaging and make-release
+- Document avalon options in ASIC-README
+- Create README.ASIC with basic summary of supported ASIC devices.
+- Do avalon driver detection last as it will try to claim any similar device and
+they are not reliably detected.
+- Set the fanspeed to the nominal chosen for GPUs.
+- Clamp initial GPU fanspeed to within user specified range.
+- Avalon fan factor is already multiplied into the info values.
+- Get rid of zeros which corrupt display.
+- Logic fail on minimum fanspeed reporting.
+- Provide a workaround for fan0 sensor not being used on avalon and pad fan RPM
+with zeros.
+- Add ambient temp and lowest fan RPM information to avalon statline.
+- Display max temperature and fanspeed data for avalon.
+- Set devices to disabled after they exit the hashing loops to prevent the
+watchdog thread from trying to act on them.
+- Scanhash functions perform driver shutdown so don't repeat it.
+- Change the opencl shutdown sequence.
+- Send the shutdown message to threads and do the thread shutdown functions
+before more forcefully sending pthread_cancel to threads.
+- Icarus report data direction with comms errors
+- Execute driver shutdown sequence during kill_work.
+- Provide an nusleep equivalent function to nmsleep.
+- Set avalon_info to device data void struct.
+- Make submit_nonce return a bool for whether it's a valid share or not.
+- Do a non-blocking read of anything in the avalon buffer after opening the
+device.
+- Assign the avalon info data to the device_data in cgpu_info.
+- Rename cgpu_data to use new device_data
+- miner.h remove unused device_file and add device_data
+- Must unlock curses as well in logwin_update.
+- icarus report usb write error information
+- Make mining threads report out during work submission.
+- submit_work_async is no longer used directly by driver code.
+- Create a logwin_update function which mandatorily updates the logwin and use
+it when input is expected to prevent display refresh delays.
+- All stratum calls to recv_line are serialised from the one place so there is
+no need to use locking around recv().
+- Only allow the mining thread to be cancelled when it is not within driver
+code, making for cleaner shutdown and allowing us to pthread_join the miner
+threads on kill_work().
+- Implement pthread_testcancel replacement for BIONIC
+- Attribute whatever stats we can get on untracked stratum shares based on
+current pool diff.
+- Downgrade OpenCL headers to 1.0, which work fine for our purposes and are more
+compatible
+- icarus: If work_division autodetect fails, just use the old default of 2
+- avalonhost-raminst script to help with installing to RAM on Avalon-host
+routers
+- Attempt to probe /dev/cu.usb* for fallback "-S all"
+- openwrt: Download uthash dependency
+- Bugfix: openwrt: Always build with libsensors support disabled
+- configure: Check for uthash headers
+- Bugfix: ztex: Only destroy libztex device after the last handle to it has been
+released
+- ztex: Remove libztex slave device interface, simply passing fpgaNum to
+selectFpga
+- Bugfix: cpu: Fix yasm and sse2 detection
+- cpu: Check for SSE2 support independently from yasm
+- Bugfix: cpu: Make sure to link libsse2cpuminer.a before x86_32/libx8632.a
+- Bugfix: cpu: Only build libsse2cpuminer iff yasm is available and targetting
+x86_32
+- Bugfix: Free work only after deleting it from list
+- Remove embedded uthash.h and utlist.h from Makefile
+- windows-build.txt: Update for system uthash
+- Remove embedded uthash (and add dependency on system uthash)
+- Replace elist.h with utlist.h
+- Bugfix: Fix build with CPU mining and *without* yasm
+- cpu: Be explicit about size of sha256_init address
+- cpu: Add --algo fastauto (new default) to detect a usable algorithm without
+taking over a minute
+- cpu: Default to --algo auto
+- cpu: Support all platform-applicable assembly algorithms, even if used CFLAGS
+don't support them
+- Ubuntu: Updated changelog, added scrypt support.
+- cpu: Set fixed symbol names for stuff shared with assembly
+- cpu: Create Mach-O asm binaries on Darwin-based systems
+- Bugfix: cpu: Use COFF yasm binfmt on Cygwin
+- Bugfix: cpu: Get correct nonce from data, where the CPU sub-drivers leave it
+- Remove redundant "Reject ratio" in exit-time summary
+- Apply "R+S(%)" formatting to long-form statistics
+- Group stale shares in with rejects (but still distinctly counted) and make the
+percentage be (reject+stale)/total
+- Include rejected shares as a percentage
+- Move Utility and Best Share to status line
+- Remove LW from status line, since it is basically useless
+- ztex: Clean up a lot of ugly casting
+- Bugfix: Correctly avoid SIGPIPE on Mac
+- Make set_work_target a function to set a specified char as target for use
+elsewhere.
+- Minor typo.
+- Support more shares to be returned for scrypt mining.
+- Set all stratum sockets to nonblocking to avoid trying to use MSG_DONTWAIT on
+windows.
+- Only use MSG_NOSIGNAL for !win32 since it doesn't exist on windows.
+- Use MSG_NOSIGNAL on stratum send()
+- Set TCP_NODELAY for !linux for raw sockets.
+- Use TCP_NODELAY with raw sockets if !opt_delaynet
+- Recheck select succeeds on EWOULDBLOCK for stratum.
+- Don't use TCP_NODELAY if opt_delaynet is enabled with stratum.
+- Fix warnings in avalon driver.
+- correct applog typing
+- Simplify the many lines passed as API data in the avalon driver now that the
+API does not need persistent storage for the name.
+- Duplicate the name string always in api_add_data_full to not need persistent
+storage for names passed to it.
+- Add extra matching work count data in API for Avalon with 4 modules.
+- Clean up summary slightly better on exit.
+- opencl: Disable using binary kernels on Apple by default
+- Use sock_blocks in api.c
+- Fix build and distdir.
+- compile on win32
+- Update README.scrypt with improved hashrates for 7970.
+- Use copy_time helper throughout miner.c
+- Provide wrappers for commonly used timer routines with API stats.
+- Use flip32 function instead of open coding it in gen_stratum_work.
+- Move util.c exports to util.h
+- Replace gettimeofday usage with cgtime
+- Adopt gettimeofday wrapper from cgminer (cgtime) that is always called with tz
+set to NULL and increases the resolution on windows.
+- Add high resolution to nmsleep wrapper on windows.
+- Bugfix: Export stats_lock for deviceapi
+- Set default ocl work size for scrypt to 256.
+- fliter out the wrong result from adjust fan code
+- Set last device valid work on adding device.
+- Make scrypt submission use the submit_nonce code, with nonces matching
+endianness.
+- Increment hardware error count from the one site.
+- compile avalon driver on win32 and win64
+- build out of source dir
+- Rename scrypt regenhash function for consistency.
+- Add Mac FAQ.
+- Further driver FAQs.
+- Check for work restart after disable in the hash queued work loop since it may
+be a long time before we re-enable a device.
+- Unconditionally test for many wrong results on avalon and reset to avoid
+passing a corrupt avalon result to temperature code.
+- Only reset an avalon device with no results when there are no results
+consecutively.
+- More FAQs.
+- Avoid applog in recalloc_sock.
+- Avoid applog under cg_wlock.
+- Put spacing around locking code for clarity.
+- Avoid applog under pool_lock.
+- Avoid more recursive locks.
+- Avoid applog while ch_lock is held.
+- Avoid recursive locks in fill_queue.
+- Variable is already initialised in global scope.
+- More GPU FAQs.
+- More README faqs.
+- Yet more README faqs.
+- Add more FAQs to README.
+- Wrap result wrong tests in avalon scanhash in unlikely() and only consider a
+hash count of zero wrong if a restart wasn't issued.
+- avalon: if result_wrong >= get_work_count jump out the read loop
+- Fix warning on 32bit.
+- fix the fan control on max temp2/3
+- for some reason network down. one simple bfgminer command:   "bfgminer -o
+127.0.0.1:8888 -O fa:ke --avalon-options 115200:32:10:50:256" can idle the
+avalon for safe power and protect chip
+- if hash_count == 0; reinit avalon, fix the 0MHS bug use the max value of temp1
+and temp2 for fan control
+- Reinstate the matching_work_count per subdevice on avalon based on the work
+subid.
+- Rationalise and simplify the share diff and block solve detection to a common
+site.
+- subid field for devices that do not yet support the distinct device/processor
+interface
+- Make the avalon array size a macro.
+- Use replacement of work items in the avalon buffer as needed instead of
+flushing them.
+- Reinstate wrong work count to reset avalon regardless and display number of
+wrong results.
+- select() on serial usb in avalon does not work properly with zero timeout.
+- Use no timeout on further reads in avalon_gets
+- Do sequential reads in avalon_get_reset to cope with partial reads.
+- Show read discrepancy in avalon_get_reset.
+- Reuse avalon_get_work_count variable.
+- Check for AVA_GETS_RESTART when deciding if avalon has messed up.
+- Make the detection of all wrong results on avalon much more conservative to
+avoid false positives on work restarts.
+- Show error codes on select and read fail in avalon.
+- If we get a restart message in avalon_gets still check if there's a receive
+message to parse first without a timeout before returning AVA_GETS_RESTART.
+- avalon_gets is always called from the one call site so inline it.
+- The read_count is unused by the avalon get result code and no longer required
+for avalon reset so simplify code removing it.
+- Use a separate avalon_get_reset function for resetting avalon instead of using
+avalon_get_result.
+- The current hash count returned by avalon scanhash is just an obfuscated
+utility counter so make it explicit.
+- Check for a restart before a timeout in message parsing code in avalon.
+- We should check for a restart message before checking for a timeout in avalon
+scanhash.
+- Store the subid for the work item in avalon.
+- Fix record_temp_fan function in avalon driver.
+- Remove inappropriate memset of struct avalon result which was corrupting fan
+values.
+- Only do_avalon_close once on multiple errors.
+- Reset the result_wrong count on block change in avalon scanhash to prevent
+false positives for all nonces failed.
+- Small timeouts on select() instead of instant timeout increase reliability of
+socket reads and writes.
+- Rotate the avalon work array and free work on AVA_SEND_BUFFER_EMPTY as well.
+- Only get extra work in fill_queue if we don't have any unqueued work in the
+list.
+- Don't get any work if our queue is already full in avalon_fill.
+- Free avalon->works in the event we call avalon_prepare on failure to
+initialise.
+- Fix warnings.
+- Create an array of 4 lots of work for avalon and cycle through them.
+- Remove unused per unit matching work count for avalon.
+- Rename the confusing avalon_info pointer.
+- Simplify avalon scanhash code using the new find_queued_work_bymidstate
+function.
+- Members of cgpu_info for avalon are not meant to be in the union.
+- Use correct struct device_drv for avalon_drv.
+- Check enough work is queued before queueing more in avalon_fill.
+- Actually put the work in the avalon queue.
+- Rename avalon_api to avalon_drv.
+- First draft of port of avalon driver to new cgminer queued infrastructure.
+- Minor README updates.
+- README.GPU: Properly warn about overclocking damage
+- Add example 7970 tuning for scrypt in readme.
+- Update driver recommendations.
+- Add extensive GPU FAQs for the flood of new Scrypt miners.
+- Bugfix: Expect bitstreams and kernels to be in the srcdir, not build dir
+- cpu: Prefer sse4_64 algorithm if supported
+- cpu: sse2_32: Force bare symbols for cross-asm/C symbols
+- Compile CPU mining for win32 and win64
+- configure: Check for pthread in -lwinpthread
+- Use has_pth flag instead of trying to mess with pthread internals
+- configure: Explicitly check for nanosleep
+- configure: Include "no" response in BFG_PTHREAD_FLAG_CHECK
+- miner.h missing extern
+- Update links and recommended SDKs.
+- Bugfix: README.GPU: Fix some typos
+- Update README to match changes to display.
+- Remove increasingly irrelevant discarded work from status lines.
+- Remove increasingly irrelevant GW value from status.
+- README.GPU: Correct terminology
+- Update README about intensity.
+- Bugfix: Restore always autodetecting stratum as non-scrypt
+- icarus: Replace default of 2 work_division/fpga_count with autodetection of 1,
+2, or 4
+- Update scrypt readme with newer information and to match changes in code.
+- Set default GPU threads to 1 for scrypt.
+- Connect backup stratum pools if the primary pool cannot deliver work.
+- Use a new algorithm for choosing a thread concurrency when none or no shader
+value is specified for scrypt.
+- Do not round up the bufsize to the maximum allocable with scrypt.
+- Remove the rounding-up of the scrypt padbuffer which was not effectual and
+counter-productive on devices with lots of ram, limiting thread concurrencies
+and intensities.
+- Make pool adding while running asynchronous, using the pool test thread
+functionality.
+- Only curl easy cleanup a stratum curl if it exists.
+- Add intermediate variants of cglocks that can be up or downgraded to read or
+write locks and use them for stratum work generation.
+- Move the stratum data to be protected under a new cg_lock data_lock.
+- Convert the ch_lock to cg_lock.
+- Convert the control_lock to a cg_lock.
+- Remove unused qd_lock.
+- Implement cg_lock write biased rwlocks.
+- Don't start testing any pools with the watchpool thread if any of the test
+threads are still active.
+- Set sockd to false should curl setup fail on stratum.
+- Reopen the socket whenever we're retrying stratum.
+- Set pool died on failed testing to allow idle flag and time to be set.
+- Remove unused pthread_t typedefs from struct pool.
+- Perform pool_resus on all pools that are found alive with the test pool
+threads.
+- Use pool_unworkable in select_balanced as well.
+- Differentiate pool_unusable from pool_unworkable.
+- Keep a connection open on higher priority stratum pools to fail back to them.
+- Set the wrong bool in pool_active
+- Only bypass unusable pools if they're not the selected ones.
+- Find the first usable pool in preference to the current pool in select_pool
+for work.
+- Add a pool_unusable function which checks if a pool is stratum but not active
+to use within switch_pools.
+- API no longer ignore send() status
+- API make the main socket non-static
+- Start the stratum thread only if we successfully init and authorise it,
+otherwise unset the init flag.
+- Make the initialisation of the stratum thread more robust allowing the
+watchpool thread safe access to it after the stratum thread is started.
+- Shorten the time before keepalive probes are sent out and how frequently
+they're sent with stratum curls.
+- Display select return value on select fail in stratum thread.
+- Clear the socket of anything in the receive buffer if we're going to retry
+connecting.
+- Perform pool resus on pools that were not set as the initial pool at startup.
+- Allow pools to be resuscitated on first startup by the watchpool thread.
+- Check all pools simultaneously at startup switching to the first alive one to
+speed up startup.
+- Close any sockets opened if we fail to initiate stratum but have opened the
+socket.
+- API use control_lock when switching pools
+- Clear last pool work on switching pools if the current pool supports local
+work generation or we are in failover only mode.
+- make rw locks: mining_thr_lock and devices_lock
+- work queues - remove new but unnecessary functions
+- functions for handling work queues
+- find_work() to find work in devices work queue
+- Add a get_queued function for devices to use to retrieve work items from the
+queued hashtable.
+- Add the choice of hash loop to the device driver, defaulting to hash_sole_work
+if none is specified.
+- Add a driver specific flush_work for queued devices that may have work items
+already queued to abort working on them on the device and discard them.
+- Flush queued work on a restart from the hash database and discard the work
+structs.
+- Create a central point for removal of work items completed by queued device
+drivers.
+- Create a fill_queue function that creates hashtables of as many work items as
+is required by the device driver till it flags the queue full.
+- Create the hash queued work variant for use with devices that are fast enough
+to require a queue.
+- Make sure to do full avalon_init if the device_fd is invalid.
+- Document extra zero byte in avalon_reset.
+- Microoptimise likely paths in avalon_gets.
+- Make sure to set timeout to 100ms instead of 1ms in avalon read loop for
+select.
+- Make sure to get time of first response in avalon read loop.
+- Use select for a reliable timeout in avalon read and don't read 1 byte at a
+time, optimising read loop.
+- We should break on the loop on a work restart in avalon, and only consider all
+errors if we actually have gotten some results.
+- Avalon init on comms error as well.
+- Reinit avalon device in case of FPGA controller mess up.
+- Increase reliability of avalon startup by only opening and resetting the
+device once, looking for the id sequence offset by one byte as well, and still
+ignoring if it's wrong, assuming it is an avalon.
+- Nest avalon_decode functions to avoid doing unnecessary lookups once we have
+found the nonce.
+- Use htole32 wrapper for nonce encoding in avalon.
+- Remove unused rev8 function from avalon driver.
+- Remove const qualifier from driver structs
+- rename device_api -> device_drv and all related api -> drv
+- rename get_proc_by_id() to get_devices()
+- Wrap access to devices array under a mutex
+- Provide wrappers for grabbing of thr value under the mining_thr_lock.
+- mutex all access to mining_thr
+- Split thr_info array into control_thr and mining_thr pointers so more mining
+threads can be added later
+- Update the hashmeter at most 5 times per second.
+- Speed up watchdog interval and therefore display updates to 2 seconds.
+- Add README.GPU to EXTRA_DIST.
+- Split out the GPU specific information from the README into a README.GPU file.
+- Update docs and reorder README to show executive summary near top.
+- Add more FAQs about crossfire.
+- Convert error getting device IDs in ocl code to info log level only since
+multiple platforms may be installed and the error is harmless there.
+- Unnecessary extra array in ocl code.
+- Cope with the highest opencl platform not having usable devices.
+- Update kernel file names signifying changes.
+- Use constants from the array of __constants throughout the diablo kernel.
+- Create a __constant array for use within diablo kernel.
+- Use global constant arrays for all other constants used in scrypt kernel.
+- Use global __constants for sha functions in scrypt kernel.
+- Use constants for endian swap macros.
+- Revise scrypt kernel copyright notice.
+- Separate out additions in scrypt kernel.
+- Reuse some Vals[] variables that can be assigned to constants earlier in the
+poclbm kernel, making for fewer ops.
+- Put all constants used in poclbm kernel into __const memory array to speed up
+concurrent reads on the wavefront.
+- opencl: Support for reading temperature from free software radeon drivers via
+libsensors
+
+
+BFGMiner Version 3.0.3 - June 13, 2013
+
+- make-release: Include all submodules, recursively
+- Remove API.java example (no copyright license)
+- Minimally fix "make install" to ignore bitstream sources
+- Add submodule for ZtexBTCMiner (aka ztex_ufm1_*)
+- Add submodule for X6000_ztex_comm4 (aka x6500-overclocker-0402)
+- ztex: Use standard file header/comment formatting, and update license to GPLv3
+- bitforce: Allow a longer timeout (1250ms) for ZCX (Device Information)
+commands
+- Bugfix: pdcurses doesn't like changing logwin size without clearing it also,
+so do that in display options
+- -S all: Start QueryDosDevices probe with 256-byte buffer
+- Use common code to ensure the prefix of -S *:all remains in all
+implementations of it (/dev glob was removing prefixes)
+- bitforce_queue: Ensure comma following nonce count is there, to error cleanly
+- bitforce: Report queue send failures, and count as hw errors
+- Bugfix: bitforce_queue: Don't try to send ready-to-queue work to device, when
+there is no ready-to-queue work
+- Bugfix: bitforce: Clear want_to_send_queue flag when flushing queue, since we
+can't send an empty queue
+- bitforce: Include new total queued count in flush debugging
+- Bugfix: bitforce_queue: Implement a minimum wait time of 10ms
+- README: Document serial device format for Mac OS X
+- Bugfix: cairnsmore1: Enable building with libudev autodetection even if only
+icarus drivers are enabled
+- Bugfix: sysfs autodetect: Continue searching even after finding one tty (fixes
+multiple ttys per device, such as some Cairnsmore1s)
+- Bugfix: ztex: Avoid destroying libztex device in case other processors are
+still in use (fixes crash when 1.15y becomes unavailable)
+- Update windows-build.txt
+- ccan: Add missing copyright comment headers
+- Remove obsolete mknsis.sh
+- Add missing copyright sections to files that may need them
+- Standard copyright format (including year) for adl_functions.h
+- Bugfix: When disabling device, ensure its prev_work (if any) gets freed
+properly
+- Check stratum socket exists and is writable before even considering whether
+the sessionid is the same or not
+- Bugfix: Check that the stratum_share struct for a failed submission is still
+in the submission hashtable before trying to delete it
+- README: Add missing documentation for CPU algorithms cryptopp_asm32, sse2_32,
+and altivec_4way
+- Bugfix: icarus: Check work restart before timeout
+- Bugfix: icarus: Debuglog the correct read timeout (and omit from work restart
+since there's no trivial way to get it)
+- README: Update links
+- Bugfix: cpu: Fix warning on Win64
+- Bugfix: avalon: Strict formatting
+- Bugfix: Cleanup trivial warnings
+- Bugfix: bitforce: Seek to end of nonce counter to find nonces, in case there
+are more than 9
+- Bugfix: Build hexdump.c into the project normally like everything else
+- Bugfix: Really fix device entries in saved config file
+- Update the write config to properly record device entries and remove disabled
+option.
+- avalon: Really fix applog formatting
+- va_copy is meant to be matched by a va_end in log_generic.
+- Further fix distdir for hexdump.c
+- Fulltest is true if value is <= target.
+- Fix warning with no curses built in.
+- Bugfix: configure: Check NEED_FPGAUTILS correctly
+- configure: Better grammar for --enable-cpumining help
+- Bugfix: Check for SSE 4.1 support before building sse4_64 asm CPU miner (uses
+MOVNTDQA instruction)
+- Bugfix: elist: Use uintptr_t for member offset
+- Bugfix: opencl/adl: Fix format string
+- Bugfix: opencl: Correct usage of formatted prints
+- Increase fd limits as much as possible at startup
+- Bugfix: bitforce: bulk queue: Cleanly retry for high temperature recovery
+- Fixed deps for raring, which has newer libudev1.
+- bitforce: debuglog actual result data
+- Bugfix: Missing 'else' can result in null pointer dereference in race
+- Minor grammo in avalon driver.
+- Make avalon temperature reading LOG_INFO level.
+- Fix the problem of seting up termio of ttyUSB0 for icarus. the CSIZE is the
+mask of CS2/4/8
+- bufsize is an unsigned integer, make it so for debug.
+- Bugfix: bitforce: Include get_api_stats in BQUEUE mode
+- Bugfix: Always compile support for commandline --temp-target and
+--temp-cutoff, and write them in the config for all devices
+- Bugfix: Ensure cURL timers get set correctly in submission thread
+- Bugfix: modminer: Remove unused parameter to sprintf
+- Bugfix: modminer: Use correct format for bytes left in bitstream upload
+message
+- Bugfix: Access strategy name string directly instead of accidentally
+- Add printf-format syntax checks to more functions that should use it
+- AUTHORS: Add more contributors
+- Support configure flag --with-system-libblkmaker to allow building without the
+bundled copy
+- Bugfix: Use HTTP/1.1 compatible product token for User-Agent header
+
+
 BFGMiner Version 3.0.2 - April 28, 2013
 BFGMiner Version 3.0.2 - April 28, 2013
 
 
 - Receive failures in recv_line should unconditionally fail.
 - Receive failures in recv_line should unconditionally fail.

+ 1 - 1
README

@@ -112,7 +112,7 @@ Optional Dependencies:
 
 
 
 
 BFGMiner specific configuration options:
 BFGMiner specific configuration options:
-	--enable-avalon         Compile support for Avalon (default disabled)
+	--disable-avalon        Compile support for Avalon (default enabled)
 	--enable-cpumining      Build with cpu mining support(default disabled)
 	--enable-cpumining      Build with cpu mining support(default disabled)
 	--disable-opencl        Build without support for OpenCL (default enabled)
 	--disable-opencl        Build without support for OpenCL (default enabled)
 	--disable-adl           Build without ADL monitoring (default enabled)
 	--disable-adl           Build without ADL monitoring (default enabled)

+ 0 - 6
README.RPC

@@ -390,12 +390,6 @@ api-example.php - a PHP script to access the API
  You must modify the line "$socket = getsock('127.0.0.1', 4028);" at the
  You must modify the line "$socket = getsock('127.0.0.1', 4028);" at the
  beginning of "function request($cmd)" to change where it looks for BFGMiner
  beginning of "function request($cmd)" to change where it looks for BFGMiner
 
 
-API.java/API.class
- a java program to access the API (with source code)
-  usage is: java API command address port
- Any missing or blank parameters are replaced as if you entered:
-  java API summary 127.0.0.1 4028
-
 api-example.c - a 'C' program to access the API (with source code)
 api-example.c - a 'C' program to access the API (with source code)
   usage: api-example [command [ip/host [port]]]
   usage: api-example [command [ip/host [port]]]
  again, as above, missing or blank parameters are replaced as if you entered:
  again, as above, missing or blank parameters are replaced as if you entered:

+ 1 - 1
api.c

@@ -1108,7 +1108,7 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
 			case API_UTILITY:
 			case API_UTILITY:
 			case API_FREQ:
 			case API_FREQ:
 			case API_MHS:
 			case API_MHS:
-				sprintf(buf, "%.2f", *((double *)(root->data)));
+				sprintf(buf, "%.3f", *((double *)(root->data)));
 				break;
 				break;
 			case API_VOLTS:
 			case API_VOLTS:
 				sprintf(buf, "%.3f", *((float *)(root->data)));
 				sprintf(buf, "%.3f", *((float *)(root->data)));

+ 1 - 0
bitstreams/src/X6000_ztex_comm4

@@ -0,0 +1 @@
+Subproject commit 90b2acba70d2476597f90479bcee65141559dd55

+ 1 - 0
bitstreams/src/ZtexBTCMiner

@@ -0,0 +1 @@
+Subproject commit de68be0121c70a51e6c64344e0d5ae502d61ce52

+ 6 - 5
configure.ac

@@ -13,8 +13,8 @@ dnl * any later version.  See COPYING for more details.
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [3])
 m4_define([v_maj], [3])
-m4_define([v_min], [0])
-m4_define([v_mic], [99])
+m4_define([v_min], [1])
+m4_define([v_mic], [0])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([lt_rev], m4_eval(v_maj + v_min))
 m4_define([lt_rev], m4_eval(v_maj + v_min))
@@ -327,8 +327,9 @@ AM_CONDITIONAL([HAS_ICARUS], [test x$icarus = xyes])
 avalon="no"
 avalon="no"
 
 
 AC_ARG_ENABLE([avalon],
 AC_ARG_ENABLE([avalon],
-	[AC_HELP_STRING([--enable-avalon],[Compile support for Avalon (default disabled)])],
-	[avalon=$enableval]
+	[AC_HELP_STRING([--disable-avalon],[Compile support for Avalon (default enabled)])],
+	[avalon=$enableval],
+	[avalon=yes]
 	)
 	)
 if test "x$avalon" = xyes; then
 if test "x$avalon" = xyes; then
 	AC_DEFINE([USE_AVALON], [1], [Defined to 1 if Avalon support is wanted])
 	AC_DEFINE([USE_AVALON], [1], [Defined to 1 if Avalon support is wanted])
@@ -825,7 +826,7 @@ if test "x$prefix" = xNONE; then
 	prefix=/usr/local
 	prefix=/usr/local
 fi
 fi
 
 
-AC_DEFINE_UNQUOTED([CGMINER_PREFIX], ["$prefix/bin"], [Path to bfgminer install])
+AM_CONDITIONAL([NEED_BITSTREAM_FPGAMINER], [test x$modminer$x6500 != xnono])
 
 
 AC_DEFINE_UNQUOTED([PHATK_KERNNAME], ["phatk121016"], [Filename for phatk kernel])
 AC_DEFINE_UNQUOTED([PHATK_KERNNAME], ["phatk121016"], [Filename for phatk kernel])
 AC_DEFINE_UNQUOTED([POCLBM_KERNNAME], ["poclbm130302"], [Filename for poclbm kernel])
 AC_DEFINE_UNQUOTED([POCLBM_KERNNAME], ["poclbm130302"], [Filename for poclbm kernel])

+ 0 - 1
debian/bfgminer.docs

@@ -1,4 +1,3 @@
-API.java
 api-example.c
 api-example.c
 api-example.php
 api-example.php
 api-example.py
 api-example.py

+ 16 - 4
deviceapi.c

@@ -618,11 +618,13 @@ bool add_cgpu(struct cgpu_info *cgpu)
 		int ns;
 		int ns;
 		int tpp = cgpu->threads / lpcount;
 		int tpp = cgpu->threads / lpcount;
 		struct cgpu_info **nlp_p, *slave;
 		struct cgpu_info **nlp_p, *slave;
+		const bool manylp = (lpcount > 26);
+		const char *as = (manylp ? "aa" : "a");
 		
 		
 		// Note, strcpy instead of assigning a byte to get the \0 too
 		// Note, strcpy instead of assigning a byte to get the \0 too
-		strcpy(&cgpu->proc_repr[5], "a");
+		strcpy(&cgpu->proc_repr[5], as);
 		ns = strlen(cgpu->proc_repr_ns);
 		ns = strlen(cgpu->proc_repr_ns);
-		strcpy(&cgpu->proc_repr_ns[ns], "a");
+		strcpy(&cgpu->proc_repr_ns[ns], as);
 		
 		
 		nlp_p = &cgpu->next_proc;
 		nlp_p = &cgpu->next_proc;
 		for (int i = 1; i < lpcount; ++i)
 		for (int i = 1; i < lpcount; ++i)
@@ -630,8 +632,18 @@ bool add_cgpu(struct cgpu_info *cgpu)
 			slave = malloc(sizeof(*slave));
 			slave = malloc(sizeof(*slave));
 			*slave = *cgpu;
 			*slave = *cgpu;
 			slave->proc_id = i;
 			slave->proc_id = i;
-			slave->proc_repr[5] += i;
-			slave->proc_repr_ns[ns] += i;
+			if (manylp)
+			{
+				slave->proc_repr[5] += i / 26;
+				slave->proc_repr[6] += i % 26;
+				slave->proc_repr_ns[ns    ] += i / 26;
+				slave->proc_repr_ns[ns + 1] += i % 26;
+			}
+			else
+			{
+				slave->proc_repr[5] += i;
+				slave->proc_repr_ns[ns] += i;
+			}
 			slave->threads = tpp;
 			slave->threads = tpp;
 			devices[total_devices++] = slave;
 			devices[total_devices++] = slave;
 			*nlp_p = slave;
 			*nlp_p = slave;

+ 55 - 67
driver-avalon.c

@@ -202,66 +202,71 @@ static int avalon_send_task(int fd, const struct avalon_task *at,
 	return AVA_SEND_BUFFER_EMPTY;
 	return AVA_SEND_BUFFER_EMPTY;
 }
 }
 
 
-static inline int avalon_gets(int fd, uint8_t *buf, struct thr_info *thr,
-		       struct timeval *tv_finish)
+static inline int avalon_gets(int fd, uint8_t *buf, int read_count,
+		       struct thr_info *thr, struct timeval *tv_finish)
 {
 {
+	ssize_t ret = 0;
+	int rc = 0;
 	int read_amount = AVALON_READ_SIZE;
 	int read_amount = AVALON_READ_SIZE;
 	bool first = true;
 	bool first = true;
-	ssize_t ret = 0;
 
 
+	/* Read reply 1 byte at a time to get earliest tv_finish */
 	while (true) {
 	while (true) {
-		struct timeval timeout;
-		fd_set rd;
-
-		if (unlikely(thr->work_restart)) {
-			applog(LOG_DEBUG, "Avalon: Work restart");
-			return AVA_GETS_RESTART;
+		ret = read(fd, buf, 1);
+		if (ret < 0)
+		{
+			applog(LOG_ERR, "Avalon: Error %d on read in avalon_gets", errno);
+			return AVA_GETS_ERROR;
 		}
 		}
 
 
-		timeout.tv_sec = 0;
-		timeout.tv_usec = 100000;
+		if (first && likely(tv_finish))
+			cgtime(tv_finish);
 
 
-		FD_ZERO(&rd);
-		FD_SET(fd, &rd);
-		ret = select(fd + 1, &rd, NULL, NULL, &timeout);
-		if (unlikely(ret < 0)) {
-			applog(LOG_ERR, "Avalon: Error %d on select in avalon_gets", errno);
-			return AVA_GETS_ERROR;
-		}
-		if (ret) {
-			ret = read(fd, buf, read_amount);
-			if (unlikely(ret < 0)) {
-				applog(LOG_ERR, "Avalon: Error %d on read in avalon_gets", errno);
-				return AVA_GETS_ERROR;
-			}
-			if (likely(first)) {
-				cgtime(tv_finish);
-				first = false;
-			}
-			if (likely(ret >= read_amount))
-				return AVA_GETS_OK;
+		if (ret >= read_amount)
+			return AVA_GETS_OK;
+
+		if (ret > 0) {
 			buf += ret;
 			buf += ret;
 			read_amount -= ret;
 			read_amount -= ret;
+			first = false;
 			continue;
 			continue;
 		}
 		}
 
 
-		if (unlikely(thr->work_restart)) {
-			applog(LOG_DEBUG, "Avalon: Work restart");
+		if (thr && thr->work_restart) {
+			if (opt_debug) {
+				applog(LOG_WARNING,
+				       "Avalon: Work restart at %.2f seconds",
+				       (float)(rc)/(float)AVALON_TIME_FACTOR);
+			}
 			return AVA_GETS_RESTART;
 			return AVA_GETS_RESTART;
 		}
 		}
 
 
-		return AVA_GETS_TIMEOUT;
+		rc++;
+		if (rc >= read_count) {
+			if (opt_debug) {
+				applog(LOG_WARNING,
+				       "Avalon: No data in %.2f seconds",
+				       (float)rc/(float)AVALON_TIME_FACTOR);
+			}
+			return AVA_GETS_TIMEOUT;
+		}
 	}
 	}
 }
 }
 
 
 static int avalon_get_result(int fd, struct avalon_result *ar,
 static int avalon_get_result(int fd, struct avalon_result *ar,
 			     struct thr_info *thr, struct timeval *tv_finish)
 			     struct thr_info *thr, struct timeval *tv_finish)
 {
 {
+	struct cgpu_info *avalon;
+	struct avalon_info *info;
 	uint8_t result[AVALON_READ_SIZE];
 	uint8_t result[AVALON_READ_SIZE];
-	int ret;
+	int ret, read_count;
+
+	avalon = thr->cgpu;
+	info = avalon->device_data;
+	read_count = info->read_count;
 
 
 	memset(result, 0, AVALON_READ_SIZE);
 	memset(result, 0, AVALON_READ_SIZE);
-	ret = avalon_gets(fd, result, thr, tv_finish);
+	ret = avalon_gets(fd, result, read_count, thr, tv_finish);
 
 
 	if (ret == AVA_GETS_OK) {
 	if (ret == AVA_GETS_OK) {
 		if (opt_debug) {
 		if (opt_debug) {
@@ -300,39 +305,16 @@ static bool avalon_decode_nonce(struct thr_info *thr, struct avalon_result *ar,
 
 
 static void avalon_get_reset(int fd, struct avalon_result *ar)
 static void avalon_get_reset(int fd, struct avalon_result *ar)
 {
 {
-	int read_amount = AVALON_READ_SIZE;
-	uint8_t result[AVALON_READ_SIZE];
-	struct timeval timeout = {1, 0};
-	ssize_t ret = 0, offset = 0;
-	fd_set rd;
-
-	memset(result, 0, AVALON_READ_SIZE);
+	int ret;
+	const int read_count = AVALON_RESET_FAULT_DECISECONDS * AVALON_TIME_FACTOR;
+	
 	memset(ar, 0, AVALON_READ_SIZE);
 	memset(ar, 0, AVALON_READ_SIZE);
-	FD_ZERO(&rd);
-	FD_SET(fd, &rd);
-	ret = select(fd + 1, &rd, NULL, NULL, &timeout);
-	if (unlikely(ret < 0)) {
-		applog(LOG_WARNING, "Avalon: Error %d on select in avalon_get_reset", errno);
-		return;
-	}
-	if (!ret) {
-		applog(LOG_WARNING, "Avalon: Timeout on select in avalon_get_reset");
-		return;
-	}
-	do {
-		ret = read(fd, result + offset, read_amount);
-		if (unlikely(ret < 0)) {
-			applog(LOG_WARNING, "Avalon: Error %d on read in avalon_get_reset", errno);
-			return;
-		}
-		read_amount -= ret;
-		offset += ret;
-	} while (read_amount > 0);
-	if (opt_debug) {
+	ret = avalon_gets(fd, (uint8_t*)ar, read_count, NULL, NULL);
+	
+	if (ret == AVA_GETS_OK && opt_debug) {
 		applog(LOG_DEBUG, "Avalon: get:");
 		applog(LOG_DEBUG, "Avalon: get:");
-		hexdump((uint8_t *)result, AVALON_READ_SIZE);
+		hexdump((uint8_t *)ar, AVALON_READ_SIZE);
 	}
 	}
-	memcpy((uint8_t *)ar, result, AVALON_READ_SIZE);
 }
 }
 
 
 static int avalon_reset(int fd, struct avalon_result *ar)
 static int avalon_reset(int fd, struct avalon_result *ar)
@@ -549,8 +531,9 @@ static void avalon_clear_readbuf(int fd)
 	ssize_t ret;
 	ssize_t ret;
 
 
 	do {
 	do {
-		struct timeval timeout;
 		char buf[AVALON_FTDI_READSIZE];
 		char buf[AVALON_FTDI_READSIZE];
+#ifndef WIN32
+		struct timeval timeout;
 		fd_set rd;
 		fd_set rd;
 
 
 		timeout.tv_sec = timeout.tv_usec = 0;
 		timeout.tv_sec = timeout.tv_usec = 0;
@@ -558,6 +541,8 @@ static void avalon_clear_readbuf(int fd)
 		FD_SET((SOCKETTYPE)fd, &rd);
 		FD_SET((SOCKETTYPE)fd, &rd);
 		ret = select(fd + 1, &rd, NULL, NULL, &timeout);
 		ret = select(fd + 1, &rd, NULL, NULL, &timeout);
 		if (ret > 0)
 		if (ret > 0)
+#endif
+			// Relies on serial timeout for Windows
 			ret = read(fd, buf, AVALON_FTDI_READSIZE);
 			ret = read(fd, buf, AVALON_FTDI_READSIZE);
 	} while (ret > 0);
 	} while (ret > 0);
 }
 }
@@ -612,6 +597,8 @@ static bool avalon_detect_one(const char *devpath)
 	info->miner_count = miner_count;
 	info->miner_count = miner_count;
 	info->asic_count = asic_count;
 	info->asic_count = asic_count;
 	info->timeout = timeout;
 	info->timeout = timeout;
+	info->read_count = ((float)info->timeout * AVALON_HASH_TIME_FACTOR *
+			    AVALON_TIME_FACTOR) / (float)info->miner_count;
 
 
 	info->fan_pwm = AVALON_DEFAULT_FAN_MIN_PWM;
 	info->fan_pwm = AVALON_DEFAULT_FAN_MIN_PWM;
 	info->temp_max = 0;
 	info->temp_max = 0;
@@ -635,7 +622,7 @@ static bool avalon_detect_one(const char *devpath)
 
 
 static inline void avalon_detect()
 static inline void avalon_detect()
 {
 {
-	serial_detect(&avalon_drv, avalon_detect_one);
+	serial_detect_byname(&avalon_drv, avalon_detect_one);
 }
 }
 
 
 static void __avalon_init(struct cgpu_info *avalon)
 static void __avalon_init(struct cgpu_info *avalon)
@@ -1002,6 +989,7 @@ static struct api_data *avalon_api_stats(struct cgpu_info *cgpu)
 	root = api_add_int(root, "baud", &(info->baud), false);
 	root = api_add_int(root, "baud", &(info->baud), false);
 	root = api_add_int(root, "miner_count", &(info->miner_count),false);
 	root = api_add_int(root, "miner_count", &(info->miner_count),false);
 	root = api_add_int(root, "asic_count", &(info->asic_count), false);
 	root = api_add_int(root, "asic_count", &(info->asic_count), false);
+	root = api_add_int(root, "read_count", &(info->read_count), false);
 	root = api_add_int(root, "timeout", &(info->timeout), false);
 	root = api_add_int(root, "timeout", &(info->timeout), false);
 	root = api_add_int(root, "frequency", &(info->frequency), false);
 	root = api_add_int(root, "frequency", &(info->frequency), false);
 
 

+ 3 - 0
driver-avalon.h

@@ -13,6 +13,7 @@
 
 
 #ifdef USE_AVALON
 #ifdef USE_AVALON
 
 
+#define AVALON_TIME_FACTOR 10
 #define AVALON_RESET_FAULT_DECISECONDS 1
 #define AVALON_RESET_FAULT_DECISECONDS 1
 #define AVALON_MINER_THREADS 1
 #define AVALON_MINER_THREADS 1
 
 
@@ -75,6 +76,8 @@ struct avalon_result {
 } __attribute__((packed, aligned(4)));
 } __attribute__((packed, aligned(4)));
 
 
 struct avalon_info {
 struct avalon_info {
+	int read_count;
+
 	int baud;
 	int baud;
 	int miner_count;
 	int miner_count;
 	int asic_count;
 	int asic_count;

+ 316 - 43
driver-bitforce.c

@@ -35,9 +35,10 @@
 #define tv_to_ms(tval) ((unsigned long)(tval.tv_sec * 1000 + tval.tv_usec / 1000))
 #define tv_to_ms(tval) ((unsigned long)(tval.tv_sec * 1000 + tval.tv_usec / 1000))
 #define TIME_AVG_CONSTANT 8
 #define TIME_AVG_CONSTANT 8
 #define BITFORCE_QRESULT_LINE_LEN 165
 #define BITFORCE_QRESULT_LINE_LEN 165
-#define BITFORCE_MAX_QUEUED 10
-#define BITFORCE_MAX_QRESULTS 10
-#define BITFORCE_GOAL_QRESULTS (BITFORCE_MAX_QRESULTS / 2)
+#define BITFORCE_MAX_QUEUED_MAX 40
+#define BITFORCE_MIN_QUEUED_MAX 10
+#define BITFORCE_MAX_QRESULTS 40
+#define BITFORCE_GOAL_QRESULTS 5
 #define BITFORCE_MIN_QRESULT_WAIT BITFORCE_CHECK_INTERVAL_MS
 #define BITFORCE_MIN_QRESULT_WAIT BITFORCE_CHECK_INTERVAL_MS
 #define BITFORCE_MAX_QRESULT_WAIT 1000
 #define BITFORCE_MAX_QRESULT_WAIT 1000
 #define BITFORCE_MAX_BQUEUE_AT_ONCE 5
 #define BITFORCE_MAX_BQUEUE_AT_ONCE 5
@@ -64,12 +65,16 @@ struct device_drv bitforce_queue_api;
 
 
 static void BFgets(char *buf, size_t bufLen, int fd)
 static void BFgets(char *buf, size_t bufLen, int fd)
 {
 {
+	char *obuf = buf;
 	do {
 	do {
 		buf[0] = '\0';
 		buf[0] = '\0';
 		--bufLen;
 		--bufLen;
 	} while (likely(bufLen && read(fd, buf, 1) == 1 && (buf++)[0] != '\n'));
 	} while (likely(bufLen && read(fd, buf, 1) == 1 && (buf++)[0] != '\n'));
 
 
 	buf[0] = '\0';
 	buf[0] = '\0';
+	
+	if (unlikely(opt_dev_protocol))
+		applog(LOG_DEBUG, "DEVPROTO: GETS (fd=%d): %s", fd, obuf);
 }
 }
 
 
 static ssize_t BFwrite(int fd, const void *buf, ssize_t bufLen)
 static ssize_t BFwrite(int fd, const void *buf, ssize_t bufLen)
@@ -109,6 +114,9 @@ static ssize_t bitforce_send(int fd, int procid, const void *buf, ssize_t bufLen
 static
 static
 void bitforce_cmd1(int fd, int procid, void *buf, size_t bufsz, const char *cmd)
 void bitforce_cmd1(int fd, int procid, void *buf, size_t bufsz, const char *cmd)
 {
 {
+	if (unlikely(opt_dev_protocol))
+		applog(LOG_DEBUG, "DEVPROTO: CMD1 (fd=%d xlink=%d): %s", fd, procid, cmd);
+	
 	bitforce_send(fd, procid, cmd, 3);
 	bitforce_send(fd, procid, cmd, 3);
 	BFgets(buf, bufsz, fd);
 	BFgets(buf, bufsz, fd);
 }
 }
@@ -119,6 +127,14 @@ void bitforce_cmd2(int fd, int procid, void *buf, size_t bufsz, const char *cmd,
 	bitforce_cmd1(fd, procid, buf, bufsz, cmd);
 	bitforce_cmd1(fd, procid, buf, bufsz, cmd);
 	if (strncasecmp(buf, "OK", 2))
 	if (strncasecmp(buf, "OK", 2))
 		return;
 		return;
+	
+	if (unlikely(opt_dev_protocol))
+	{
+		char *hex = bin2hex(data, datasz);
+		applog(LOG_DEBUG, "DEVPROTO: CMD2 (fd=%d xlink=%d): %s", fd, procid, hex);
+		free(hex);
+	}
+	
 	bitforce_send(fd, procid, data, datasz);
 	bitforce_send(fd, procid, data, datasz);
 	BFgets(buf, bufsz, fd);
 	BFgets(buf, bufsz, fd);
 }
 }
@@ -128,6 +144,7 @@ void bitforce_cmd2(int fd, int procid, void *buf, size_t bufsz, const char *cmd,
 struct bitforce_init_data {
 struct bitforce_init_data {
 	bool sc;
 	bool sc;
 	long devmask;
 	long devmask;
+	int *parallels;
 };
 };
 
 
 static bool bitforce_detect_one(const char *devpath)
 static bool bitforce_detect_one(const char *devpath)
@@ -137,7 +154,7 @@ static bool bitforce_detect_one(const char *devpath)
 	char pdevbuf[0x100];
 	char pdevbuf[0x100];
 	size_t pdevbuf_len;
 	size_t pdevbuf_len;
 	char *s;
 	char *s;
-	int procs = 1;
+	int procs = 1, parallel = 1;
 	struct bitforce_init_data *initdata;
 	struct bitforce_init_data *initdata;
 
 
 	applog(LOG_DEBUG, "BFL: Attempting to open %s", devpath);
 	applog(LOG_DEBUG, "BFL: Attempting to open %s", devpath);
@@ -164,7 +181,10 @@ static bool bitforce_detect_one(const char *devpath)
 	*initdata = (struct bitforce_init_data){
 	*initdata = (struct bitforce_init_data){
 		.sc = false,
 		.sc = false,
 	};
 	};
-	for ( bitforce_cmd1(fdDev, 0, pdevbuf, sizeof(pdevbuf), "ZCX");
+	bitforce_cmd1(fdDev, 0, pdevbuf, sizeof(pdevbuf), "ZCX");
+	for (int i = 0; (!pdevbuf[0]) && i < 4; ++i)
+		BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
+	for ( ;
 	      strncasecmp(pdevbuf, "OK", 2);
 	      strncasecmp(pdevbuf, "OK", 2);
 	      BFgets(pdevbuf, sizeof(pdevbuf), fdDev) )
 	      BFgets(pdevbuf, sizeof(pdevbuf), fdDev) )
 	{
 	{
@@ -172,7 +192,9 @@ static bool bitforce_detect_one(const char *devpath)
 		if (unlikely(!pdevbuf_len))
 		if (unlikely(!pdevbuf_len))
 			continue;
 			continue;
 		pdevbuf[pdevbuf_len-1] = '\0';  // trim newline
 		pdevbuf[pdevbuf_len-1] = '\0';  // trim newline
+		
 		applog(LOG_DEBUG, "  %s", pdevbuf);
 		applog(LOG_DEBUG, "  %s", pdevbuf);
+		
 		if (!strncasecmp(pdevbuf, "DEVICES IN CHAIN:", 17))
 		if (!strncasecmp(pdevbuf, "DEVICES IN CHAIN:", 17))
 			procs = atoi(&pdevbuf[17]);
 			procs = atoi(&pdevbuf[17]);
 		else
 		else
@@ -181,9 +203,44 @@ static bool bitforce_detect_one(const char *devpath)
 		else
 		else
 		if (!strncasecmp(pdevbuf, "DEVICE:", 7) && strstr(pdevbuf, "SC"))
 		if (!strncasecmp(pdevbuf, "DEVICE:", 7) && strstr(pdevbuf, "SC"))
 			initdata->sc = true;
 			initdata->sc = true;
+		else
+		if (!strncasecmp(pdevbuf, "CHIP PARALLELIZATION: YES @", 27))
+			parallel = atoi(&pdevbuf[27]);
+	}
+	initdata->parallels = malloc(sizeof(initdata->parallels[0]) * procs);
+	initdata->parallels[0] = parallel;
+	for (int proc = 1; proc < procs; ++proc)
+	{
+		applog(LOG_DEBUG, "Slave board %d:", proc);
+		initdata->parallels[proc] = 1;
+		bitforce_cmd1(fdDev, 0, pdevbuf, sizeof(pdevbuf), "ZCX");
+		for (int i = 0; (!pdevbuf[0]) && i < 4; ++i)
+			BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
+		for ( ;
+		      strncasecmp(pdevbuf, "OK", 2);
+		      BFgets(pdevbuf, sizeof(pdevbuf), fdDev) )
+		{
+			pdevbuf_len = strlen(pdevbuf);
+			if (unlikely(!pdevbuf_len))
+				continue;
+			pdevbuf[pdevbuf_len-1] = '\0';  // trim newline
+			
+			applog(LOG_DEBUG, "  %s", pdevbuf);
+			
+			if (!strncasecmp(pdevbuf, "CHIP PARALLELIZATION: YES @", 27))
+				initdata->parallels[proc] = atoi(&pdevbuf[27]);
+		}
+		parallel += initdata->parallels[proc];
 	}
 	}
 	BFclose(fdDev);
 	BFclose(fdDev);
 	
 	
+	if (unlikely(procs < parallel && !initdata->sc))
+	{
+		// Only bitforce_queue supports parallelization, so force SC mode and hope for the best
+		applog(LOG_WARNING, "Chip parallelization detected with non-SC device; this is not supported!");
+		initdata->sc = true;
+	}
+	
 	// We have a real BitForce!
 	// We have a real BitForce!
 	bitforce = calloc(1, sizeof(*bitforce));
 	bitforce = calloc(1, sizeof(*bitforce));
 	bitforce->drv = &bitforce_drv;
 	bitforce->drv = &bitforce_drv;
@@ -191,7 +248,7 @@ static bool bitforce_detect_one(const char *devpath)
 		bitforce->drv = &bitforce_queue_api;
 		bitforce->drv = &bitforce_queue_api;
 	bitforce->device_path = strdup(devpath);
 	bitforce->device_path = strdup(devpath);
 	bitforce->deven = DEV_ENABLED;
 	bitforce->deven = DEV_ENABLED;
-	bitforce->procs = procs;
+	bitforce->procs = parallel;
 	bitforce->threads = 1;
 	bitforce->threads = 1;
 
 
 	if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
 	if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
@@ -226,6 +283,8 @@ struct bitforce_data {
 	enum bitforce_proto proto;
 	enum bitforce_proto proto;
 	bool sc;
 	bool sc;
 	int queued;
 	int queued;
+	int queued_max;
+	int parallel;
 	bool already_have_results;
 	bool already_have_results;
 	bool just_flushed;
 	bool just_flushed;
 	int ready_to_queue;
 	int ready_to_queue;
@@ -236,6 +295,11 @@ struct bitforce_data {
 	float temp[2];
 	float temp[2];
 };
 };
 
 
+struct bitforce_proc_data {
+	struct cgpu_info *cgpu;
+	bool handles_board;  // The first processor handles the queue for the entire board
+};
+
 static void bitforce_clear_buffer(struct cgpu_info *);
 static void bitforce_clear_buffer(struct cgpu_info *);
 
 
 static
 static
@@ -264,6 +328,10 @@ void bitforce_comm_error(struct thr_info *thr)
 static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
 static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
 {
 {
 	struct bitforce_data *data = bitforce->device_data;
 	struct bitforce_data *data = bitforce->device_data;
+	struct bitforce_proc_data *procdata = bitforce->thr[0]->cgpu_data;
+	
+	if (!procdata->handles_board)
+		goto nostats;
 
 
 	if (data->temp[0] > 0 && data->temp[1] > 0)
 	if (data->temp[0] > 0 && data->temp[1] > 0)
 		tailsprintf(buf, "%5.1fC/%4.1fC   | ", data->temp[0], data->temp[1]);
 		tailsprintf(buf, "%5.1fC/%4.1fC   | ", data->temp[0], data->temp[1]);
@@ -271,6 +339,7 @@ static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
 	if (bitforce->temp > 0)
 	if (bitforce->temp > 0)
 		tailsprintf(buf, "%5.1fC         | ", bitforce->temp);
 		tailsprintf(buf, "%5.1fC         | ", bitforce->temp);
 	else
 	else
+nostats:
 		tailsprintf(buf, "               | ");
 		tailsprintf(buf, "               | ");
 }
 }
 
 
@@ -321,16 +390,22 @@ static void bitforce_clear_buffer(struct cgpu_info *bitforce)
 	mutex_unlock(mutexp);
 	mutex_unlock(mutexp);
 }
 }
 
 
+void work_list_del(struct work **head, struct work *);
+
 void bitforce_reinit(struct cgpu_info *bitforce)
 void bitforce_reinit(struct cgpu_info *bitforce)
 {
 {
 	struct bitforce_data *data = bitforce->device_data;
 	struct bitforce_data *data = bitforce->device_data;
 	struct thr_info *thr = bitforce->thr[0];
 	struct thr_info *thr = bitforce->thr[0];
+	struct bitforce_proc_data *procdata = thr->cgpu_data;
 	const char *devpath = bitforce->device_path;
 	const char *devpath = bitforce->device_path;
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
 	int *p_fdDev = &bitforce->device->device_fd;
 	int *p_fdDev = &bitforce->device->device_fd;
 	int fdDev, retries = 0;
 	int fdDev, retries = 0;
 	char pdevbuf[0x100];
 	char pdevbuf[0x100];
 	char *s;
 	char *s;
+	
+	if (!procdata->handles_board)
+		return;
 
 
 	mutex_lock(mutexp);
 	mutex_lock(mutexp);
 	fdDev = *p_fdDev;
 	fdDev = *p_fdDev;
@@ -391,10 +466,7 @@ void bitforce_reinit(struct cgpu_info *bitforce)
 		
 		
 		bitforce_cmd1(fdDev, data->xlink_id, pdevbuf, sizeof(pdevbuf), "ZQX");
 		bitforce_cmd1(fdDev, data->xlink_id, pdevbuf, sizeof(pdevbuf), "ZQX");
 		DL_FOREACH_SAFE(thr->work_list, work, tmp)
 		DL_FOREACH_SAFE(thr->work_list, work, tmp)
-		{
-			DL_DELETE(thr->work_list, work);
-			free_work(work);
-		}
+			work_list_del(&thr->work_list, work);
 		data->queued = 0;
 		data->queued = 0;
 		data->ready_to_queue = 0;
 		data->ready_to_queue = 0;
 		data->already_have_results = false;
 		data->already_have_results = false;
@@ -467,6 +539,7 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
 	int fdDev = bitforce->device->device_fd;
 	int fdDev = bitforce->device->device_fd;
 	char pdevbuf[0x100];
 	char pdevbuf[0x100];
 	char *s;
 	char *s;
+	struct cgpu_info *chip_cgpu;
 
 
 	if (!fdDev)
 	if (!fdDev)
 		return false;
 		return false;
@@ -512,7 +585,12 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
 			}
 			}
 		}
 		}
 
 
-		set_float_if_gt_zero(&bitforce->temp, temp);
+		if (temp > 0)
+		{
+			chip_cgpu = bitforce;
+			for (int i = 0; i < data->parallel; ++i, (chip_cgpu = chip_cgpu->next_proc))
+				chip_cgpu->temp = temp;
+		}
 	} else {
 	} else {
 		/* Use the temperature monitor as a kind of watchdog for when
 		/* Use the temperature monitor as a kind of watchdog for when
 		 * our responses are out of sync and flush the buffer to
 		 * our responses are out of sync and flush the buffer to
@@ -1126,6 +1204,10 @@ static void biforce_thread_enable(struct thr_info *thr)
 
 
 static bool bitforce_get_stats(struct cgpu_info *bitforce)
 static bool bitforce_get_stats(struct cgpu_info *bitforce)
 {
 {
+	struct bitforce_proc_data *procdata = bitforce->thr[0]->cgpu_data;
+	
+	if (!procdata->handles_board)
+		return true;
 	return bitforce_get_temp(bitforce);
 	return bitforce_get_temp(bitforce);
 }
 }
 
 
@@ -1140,9 +1222,11 @@ static bool bitforce_thread_init(struct thr_info *thr)
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct cgpu_info *bitforce = thr->cgpu;
 	unsigned int wait;
 	unsigned int wait;
 	struct bitforce_data *data;
 	struct bitforce_data *data;
+	struct bitforce_proc_data *procdata;
 	struct bitforce_init_data *initdata = bitforce->device_data;
 	struct bitforce_init_data *initdata = bitforce->device_data;
 	bool sc = initdata->sc;
 	bool sc = initdata->sc;
-	int xlink_id = 0;
+	int xlink_id = 0, boardno = 0;
+	struct bitforce_proc_data *first_on_this_board;
 	
 	
 	for ( ; bitforce; bitforce = bitforce->next_proc)
 	for ( ; bitforce; bitforce = bitforce->next_proc)
 	{
 	{
@@ -1164,6 +1248,12 @@ static bool bitforce_thread_init(struct thr_info *thr)
 			.proto = BFP_RANGE,
 			.proto = BFP_RANGE,
 			.sc = sc,
 			.sc = sc,
 			.sleep_ms_default = BITFORCE_SLEEP_MS,
 			.sleep_ms_default = BITFORCE_SLEEP_MS,
+			.parallel = initdata->parallels[boardno],
+		};
+		thr->cgpu_data = procdata = malloc(sizeof(*procdata));
+		*procdata = (struct bitforce_proc_data){
+			.handles_board = true,
+			.cgpu = bitforce,
 		};
 		};
 		if (sc)
 		if (sc)
 		{
 		{
@@ -1176,6 +1266,11 @@ static bool bitforce_thread_init(struct thr_info *thr)
 				bitforce_change_mode(bitforce, BFP_BQUEUE);
 				bitforce_change_mode(bitforce, 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;
+				if (data->queued_max < BITFORCE_MIN_QUEUED_MAX)
+					data->queued_max = BITFORCE_MIN_QUEUED_MAX;
+				if (data->queued_max > BITFORCE_MAX_QUEUED_MAX)
+					data->queued_max = BITFORCE_MAX_QUEUED_MAX;
 			}
 			}
 			else
 			else
 				bitforce_change_mode(bitforce, BFP_QUEUE);
 				bitforce_change_mode(bitforce, BFP_QUEUE);
@@ -1192,12 +1287,29 @@ static bool bitforce_thread_init(struct thr_info *thr)
 				bitforce_change_mode(bitforce, BFP_RANGE);
 				bitforce_change_mode(bitforce, BFP_RANGE);
 		}
 		}
 		
 		
+		first_on_this_board = procdata;
+		for (int proc = 1; proc < data->parallel; ++proc)
+		{
+			bitforce = bitforce->next_proc;
+			assert(bitforce);
+			thr = bitforce->thr[0];
+			
+			thr->queue_full = true;
+			thr->cgpu_data = procdata = malloc(sizeof(*procdata));
+			*procdata = *first_on_this_board;
+			procdata->handles_board = false;
+			procdata->cgpu = bitforce;
+			bitforce->device_data = data;
+		}
+		applog(LOG_DEBUG, "%s: Board %d: %"PRIpreprv"-%"PRIpreprv, bitforce->dev_repr, boardno, first_on_this_board->cgpu->proc_repr, bitforce->proc_repr);
+		
 		while (xlink_id < 31 && !(initdata->devmask & (1 << ++xlink_id)))
 		while (xlink_id < 31 && !(initdata->devmask & (1 << ++xlink_id)))
 		{}
 		{}
 	}
 	}
 	
 	
 	bitforce = thr->cgpu;
 	bitforce = thr->cgpu;
 
 
+	free(initdata->parallels);
 	free(initdata);
 	free(initdata);
 
 
 	/* Pause each new thread at least 100ms between initialising
 	/* Pause each new thread at least 100ms between initialising
@@ -1318,7 +1430,7 @@ void bitforce_set_queue_full(struct thr_info *thr)
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct bitforce_data *data = bitforce->device_data;
 	struct bitforce_data *data = bitforce->device_data;
 	
 	
-	thr->queue_full = (data->queued + data->ready_to_queue >= BITFORCE_MAX_QUEUED) || (data->ready_to_queue >= BITFORCE_MAX_BQUEUE_AT_ONCE);
+	thr->queue_full = (data->queued + data->ready_to_queue >= data->queued_max) || (data->ready_to_queue >= BITFORCE_MAX_BQUEUE_AT_ONCE);
 }
 }
 
 
 static
 static
@@ -1408,6 +1520,10 @@ bool bitforce_queue_do_results(struct thr_info *thr)
 	unsigned char midstate[32], datatail[12];
 	unsigned char midstate[32], datatail[12];
 	struct work *work, *tmpwork, *thiswork;
 	struct work *work, *tmpwork, *thiswork;
 	struct timeval tv_now, tv_elapsed;
 	struct timeval tv_now, tv_elapsed;
+	long chipno = 0;  // Initialized value is used for non-parallelized boards
+	struct cgpu_info *chip_cgpu;
+	struct thr_info *chip_thr;
+	int counts[data->parallel];
 	
 	
 	if (unlikely(!fd))
 	if (unlikely(!fd))
 		return false;
 		return false;
@@ -1428,15 +1544,9 @@ bool bitforce_queue_do_results(struct thr_info *thr)
 		return false;
 		return false;
 	}
 	}
 	
 	
-	if (unlikely(!thr->work_list))
-	{
-		applog(LOG_ERR, "%"PRIpreprv": Received %d queued results when there was no queue", bitforce->proc_repr, count);
-		++bitforce->hw_errors;
-		++hw_errors;
-		return true;
-	}
-	
 	count = 0;
 	count = 0;
+	for (int i = 0; i < data->parallel; ++i)
+		counts[i] = 0;
 	noncebuf = next_line(noncebuf);
 	noncebuf = next_line(noncebuf);
 	while ((buf = noncebuf)[0])
 	while ((buf = noncebuf)[0])
 	{
 	{
@@ -1449,8 +1559,6 @@ bool bitforce_queue_do_results(struct thr_info *thr)
 			continue;
 			continue;
 		}
 		}
 		
 		
-		applog(LOG_DEBUG, "%"PRIpreprv": Queue result: %s", bitforce->proc_repr, buf);
-		
 		hex2bin(midstate, buf, 32);
 		hex2bin(midstate, buf, 32);
 		hex2bin(datatail, &buf[65], 12);
 		hex2bin(datatail, &buf[65], 12);
 		
 		
@@ -1464,34 +1572,79 @@ bool bitforce_queue_do_results(struct thr_info *thr)
 			thiswork = work;
 			thiswork = work;
 			break;
 			break;
 		}
 		}
+		
+		end = &buf[89];
+		chip_cgpu = bitforce;
+		if (data->parallel > 1)
+		{
+			chipno = strtol(&end[1], &end, 16);
+			if (chipno >= data->parallel)
+			{
+				applog(LOG_ERR, "%"PRIpreprv": Chip number out of range for queue result: %s", chip_cgpu->proc_repr, buf);
+				chipno = 0;
+			}
+			for (int i = 0; i < chipno; ++i)
+				chip_cgpu = chip_cgpu->next_proc;
+		}
+		chip_thr = chip_cgpu->thr[0];
+		
+		applog(LOG_DEBUG, "%"PRIpreprv": Queue result: %s", chip_cgpu->proc_repr, buf);
+		
 		if (unlikely(!thiswork))
 		if (unlikely(!thiswork))
 		{
 		{
-			applog(LOG_ERR, "%"PRIpreprv": Failed to find work for queue results", bitforce->proc_repr);
-			++bitforce->hw_errors;
+			applog(LOG_ERR, "%"PRIpreprv": Failed to find work for queue results: %s", chip_cgpu->proc_repr, buf);
+			++chip_cgpu->hw_errors;
 			++hw_errors;
 			++hw_errors;
 			goto next_qline;
 			goto next_qline;
 		}
 		}
 		
 		
+		if (unlikely(!end[0]))
+		{
+			applog(LOG_ERR, "%"PRIpreprv": Missing nonce count in queue results: %s", chip_cgpu->proc_repr, buf);
+			goto finishresult;
+		}
+		if (strtol(&end[1], &end, 10))
+		{
+			if (unlikely(!end[0]))
+			{
+				applog(LOG_ERR, "%"PRIpreprv": Missing nonces in queue results: %s", chip_cgpu->proc_repr, buf);
+				goto finishresult;
+			}
+			bitforce_process_result_nonces(chip_thr, work, &end[1]);
+		}
 		++count;
 		++count;
-		if (strtol(&buf[90], &end, 10))
-			bitforce_process_result_nonces(thr, work, &end[1]);
+		++counts[chipno];
 		
 		
+finishresult:
+		if (data->parallel == 1)
+		{
+
 		// Queue results are in order, so anything queued prior this is lost
 		// Queue results are in order, so anything queued prior this is lost
 		// Delete all queued work up to, and including, this one
 		// Delete all queued work up to, and including, this one
 		DL_FOREACH_SAFE(thr->work_list, work, tmpwork)
 		DL_FOREACH_SAFE(thr->work_list, work, tmpwork)
 		{
 		{
-			DL_DELETE(thr->work_list, work);
+			work_list_del(&thr->work_list, work);
 			--data->queued;
 			--data->queued;
 			if (work == thiswork)
 			if (work == thiswork)
 				break;
 				break;
 		}
 		}
+
+		}
+		else
+		{
+			// Parallel processors means the results might not be in order
+			// This could leak if jobs get lost, hence the sanity checks using "ZqX"
+			work_list_del(&thr->work_list, thiswork);
+			--data->queued;
+		}
 next_qline: (void)0;
 next_qline: (void)0;
 	}
 	}
 	
 	
 	bitforce_set_queue_full(thr);
 	bitforce_set_queue_full(thr);
 	
 	
-	if ((count < BITFORCE_GOAL_QRESULTS && bitforce->sleep_ms < BITFORCE_MAX_QRESULT_WAIT && data->queued > 1)
-	 || (count > BITFORCE_GOAL_QRESULTS && bitforce->sleep_ms > BITFORCE_MIN_QRESULT_WAIT))
+	if (data->parallel == 1 && (
+	        (count < BITFORCE_GOAL_QRESULTS && bitforce->sleep_ms < BITFORCE_MAX_QRESULT_WAIT && data->queued > 1)
+	     || (count > BITFORCE_GOAL_QRESULTS && bitforce->sleep_ms > BITFORCE_MIN_QRESULT_WAIT)  ))
 	{
 	{
 		unsigned int old_sleep_ms = bitforce->sleep_ms;
 		unsigned int old_sleep_ms = bitforce->sleep_ms;
 		bitforce->sleep_ms = (uint32_t)bitforce->sleep_ms * BITFORCE_GOAL_QRESULTS / (count ?: 1);
 		bitforce->sleep_ms = (uint32_t)bitforce->sleep_ms * BITFORCE_GOAL_QRESULTS / (count ?: 1);
@@ -1508,7 +1661,12 @@ next_qline: (void)0;
 	
 	
 	cgtime(&tv_now);
 	cgtime(&tv_now);
 	timersub(&tv_now, &data->tv_hashmeter_start, &tv_elapsed);
 	timersub(&tv_now, &data->tv_hashmeter_start, &tv_elapsed);
-	hashes_done(thr, (uint64_t)bitforce->nonces * count, &tv_elapsed, NULL);
+	chip_cgpu = bitforce;
+	for (int i = 0; i < data->parallel; ++i, (chip_cgpu = chip_cgpu->next_proc))
+	{
+		chip_thr = chip_cgpu->thr[0];
+		hashes_done(chip_thr, (uint64_t)bitforce->nonces * counts[i], &tv_elapsed, NULL);
+	}
 	data->tv_hashmeter_start = tv_now;
 	data->tv_hashmeter_start = tv_now;
 	
 	
 	return true;
 	return true;
@@ -1529,7 +1687,7 @@ bool bitforce_queue_append(struct thr_info *thr, struct work *work)
 		++data->ready_to_queue;
 		++data->ready_to_queue;
 		applog(LOG_DEBUG, "%"PRIpreprv": Appending to driver queue (max=%u, ready=%d, queued<=%d)",
 		applog(LOG_DEBUG, "%"PRIpreprv": Appending to driver queue (max=%u, ready=%d, queued<=%d)",
 		       bitforce->proc_repr,
 		       bitforce->proc_repr,
-		       (unsigned)BITFORCE_MAX_QUEUED, data->ready_to_queue, data->queued);
+		       (unsigned)data->queued_max, data->ready_to_queue, data->queued);
 		bitforce_set_queue_full(thr);
 		bitforce_set_queue_full(thr);
 	}
 	}
 	else
 	else
@@ -1556,26 +1714,47 @@ bool bitforce_queue_append(struct thr_info *thr, struct work *work)
 	return rv;
 	return rv;
 }
 }
 
 
+struct _jobinfo {
+	uint8_t key[32+12];
+	int instances;
+	UT_hash_handle hh;
+};
+
 static
 static
 void bitforce_queue_flush(struct thr_info *thr)
 void bitforce_queue_flush(struct thr_info *thr)
 {
 {
+	struct bitforce_proc_data *procdata = thr->cgpu_data;
+	if (!procdata->handles_board)
+		return;
+	
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct cgpu_info *bitforce = thr->cgpu;
 	struct bitforce_data *data = bitforce->device_data;
 	struct bitforce_data *data = bitforce->device_data;
-	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
-	int fd = bitforce->device->device_fd;
-	char buf[100];
+	char *buf = &data->noncebuf[0], *buf2;
+	const char *cmd = "ZqX";
 	unsigned flushed;
 	unsigned flushed;
-	
-	mutex_lock(mutexp);
-	bitforce_cmd1(fd, data->xlink_id, buf, sizeof(buf), "ZQX");
-	mutex_unlock(mutexp);
-	if (unlikely(strncasecmp(buf, "OK:FLUSHED", 10)))
+	struct _jobinfo *processing = NULL, *item, *this;
+	
+	if (data->parallel == 1)
+		// Pre-parallelization neither needs nor supports "ZqX"
+		cmd = "ZQX";
+	// TODO: Call "ZQX" most of the time: don't need to do sanity checks so often
+	bitforce_zox(thr, cmd);
+	if (!strncasecmp(buf, "OK:FLUSHED", 10))
+	{
+		flushed = atoi(&buf[10]);
+		buf2 = NULL;
+	}
+	else
+	if ((!strncasecmp(buf, "COUNT:", 6)) && (buf2 = strstr(buf, "FLUSHED:")) )
+	{
+		flushed = atoi(&buf2[8]);
+		buf2 = next_line(buf2);
+	}
+	else
 	{
 	{
 		applog(LOG_DEBUG, "%"PRIpreprv": Failed to flush device queue: %s", bitforce->proc_repr, buf);
 		applog(LOG_DEBUG, "%"PRIpreprv": Failed to flush device queue: %s", bitforce->proc_repr, buf);
 		flushed = 0;
 		flushed = 0;
 	}
 	}
-	else
-		flushed = atoi(&buf[10]);
 	
 	
 	data->queued -= flushed;
 	data->queued -= flushed;
 	
 	
@@ -1590,7 +1769,71 @@ void bitforce_queue_flush(struct thr_info *thr)
 	data->just_flushed = true;
 	data->just_flushed = true;
 	data->want_to_send_queue = false;
 	data->want_to_send_queue = false;
 	
 	
+	// "ZqX" returns jobs in progress, allowing us to sanity check
+	// NOTE: Must process buffer into hash table BEFORE calling bitforce_queue_do_results, which clobbers it
+	// NOTE: Must do actual sanity check AFTER calling bitforce_queue_do_results, to ensure we don't delete completed jobs
+	if (buf2)
+	{
+		// First, turn buf2 into a hash
+		for ( ; buf2[0]; buf2 = next_line(buf2))
+		{
+			this = malloc(sizeof(*this));
+			hex2bin(&this->key[ 0], &buf2[ 0], 32);
+			hex2bin(&this->key[32], &buf2[65], 12);
+			HASH_FIND(hh, processing, &this->key[0], sizeof(this->key), item);
+			if (likely(!item))
+			{
+				this->instances = 1;
+				HASH_ADD(hh, processing, key, sizeof(this->key), this);
+			}
+			else
+			{
+				// This should really only happen in testing/benchmarking...
+				++item->instances;
+				free(this);
+			}
+		}
+	}
+	
 	bitforce_queue_do_results(thr);
 	bitforce_queue_do_results(thr);
+	
+	if (buf2)
+	{
+		struct work *work, *tmp;
+		uint8_t key[32+12];
+		
+		// Now iterate over the work_list and delete anything not in the hash
+		DL_FOREACH_SAFE(thr->work_list, work, tmp)
+		{
+			memcpy(&key[ 0],  work->midstate, 32);
+			memcpy(&key[32], &work->data[64], 12);
+			HASH_FIND(hh, processing, &key[0], sizeof(key), item);
+			if (unlikely(!item))
+			{
+				char *hex = bin2hex(key, 32+12);
+				applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device is missing queued job! %s", bitforce->proc_repr, hex);
+				free(hex);
+				work_list_del(&thr->work_list, work);
+				continue;
+			}
+			if (likely(!--item->instances))
+			{
+				HASH_DEL(processing, item);
+				free(item);
+			}
+		}
+		if (unlikely( (flushed = HASH_COUNT(processing)) ))
+		{
+			//applog(LOG_WARNING, "%"PRIpreprv": Sanity check: Device is working on %d unknown jobs!", bitforce->proc_repr, flushed);
+			// FIXME: Probably these were jobs finished after ZqX, included in the result check we just did
+			// NOTE: We need to do that result check first to avoid deleting work_list items for things just solved
+			HASH_ITER(hh, processing, item, this)
+			{
+				HASH_DEL(processing, item);
+				free(item);
+			}
+		}
+	}
 }
 }
 
 
 static
 static
@@ -1617,6 +1860,35 @@ void bitforce_queue_poll(struct thr_info *thr)
 	timer_set_delay_from_now(&thr->tv_poll, sleep_us);
 	timer_set_delay_from_now(&thr->tv_poll, sleep_us);
 }
 }
 
 
+static void bitforce_queue_thread_deven(struct thr_info *thr)
+{
+	struct cgpu_info *bitforce = thr->cgpu, *thisbf;
+	struct bitforce_data *data = bitforce->device_data;
+	struct thr_info *thisthr;
+	
+	for (thisbf = bitforce; thisbf && thisbf->device_data == data; thisbf = thisbf->next_proc)
+	{
+		thisthr = bitforce->thr[0];
+		
+		thisthr->pause = thr->pause;
+		thisbf->deven = bitforce->deven;
+	}
+}
+
+static void bitforce_queue_thread_disable(struct thr_info *thr)
+{
+	// Disable other threads sharing the same queue
+	bitforce_queue_thread_deven(thr);
+}
+
+static void bitforce_queue_thread_enable(struct thr_info *thr)
+{
+	// TODO: Maybe reinit?
+	
+	// Enable other threads sharing the same queue
+	bitforce_queue_thread_deven(thr);
+}
+
 struct device_drv bitforce_queue_api = {
 struct device_drv bitforce_queue_api = {
 	.dname = "bitforce_queue",
 	.dname = "bitforce_queue",
 	.name = "BFL",
 	.name = "BFL",
@@ -1633,5 +1905,6 @@ struct device_drv bitforce_queue_api = {
 	.queue_flush = bitforce_queue_flush,
 	.queue_flush = bitforce_queue_flush,
 	.poll = bitforce_queue_poll,
 	.poll = bitforce_queue_poll,
 	.thread_shutdown = bitforce_shutdown,
 	.thread_shutdown = bitforce_shutdown,
-	.thread_enable = biforce_thread_enable
+	.thread_disable = bitforce_queue_thread_disable,
+	.thread_enable = bitforce_queue_thread_enable,
 };
 };

+ 9 - 6
driver-icarus.c

@@ -703,10 +703,10 @@ static bool icarus_init(struct thr_info *thr)
 		
 		
 		// Special packet to probe work_division
 		// Special packet to probe work_division
 		unsigned char pkt[64] =
 		unsigned char pkt[64] =
-			"\x6C\x0E\x85\x6F\xD5\xB7\x0D\x39\xB3\xEB\xCF\x26\x21\x22\xD5\x1F"
-			"\x7E\x89\x6B\x26\x92\x2A\xD8\xFC\x66\xDF\x8C\x66\xB8\x2C\x37\x7C"
+			"\x2e\x4c\x8f\x91\xfd\x59\x5d\x2d\x7e\xa2\x0a\xaa\xcb\x64\xa2\xa0"
+			"\x43\x82\x86\x02\x77\xcf\x26\xb6\xa1\xee\x04\xc5\x6a\x5b\x50\x4a"
 			"BFGMiner Probe\0\0"
 			"BFGMiner Probe\0\0"
-			"BFG\0\xE9\x7F\x01\x1A\x3B\xE1\x91\x51\xD3\x58\xC5\xFF";
+			"BFG\0\x64\x61\x01\x1a\xc9\x06\xa9\x51\xfb\x9b\x3c\x73";
 		
 		
 		icarus_write(fd, pkt, sizeof(pkt));
 		icarus_write(fd, pkt, sizeof(pkt));
 		if (ICA_GETS_OK == icarus_gets((unsigned char*)&res, fd, &tv_finish, NULL, info->read_count))
 		if (ICA_GETS_OK == icarus_gets((unsigned char*)&res, fd, &tv_finish, NULL, info->read_count))
@@ -715,15 +715,18 @@ static bool icarus_init(struct thr_info *thr)
 			res = 0;
 			res = 0;
 		
 		
 		switch (res) {
 		switch (res) {
-			case 0x06448360:
+			case 0x04C0FDB4:
 				info->work_division = 1;
 				info->work_division = 1;
 				break;
 				break;
-			case 0x85C55B5B:
+			case 0x82540E46:
 				info->work_division = 2;
 				info->work_division = 2;
 				break;
 				break;
-			case 0xC0DC6008:
+			case 0x417C0F36:
 				info->work_division = 4;
 				info->work_division = 4;
 				break;
 				break;
+			case 0x60C994D5:
+				info->work_division = 8;
+				break;
 			default:
 			default:
 				applog(LOG_ERR, "%"PRIpreprv": Work division autodetection failed (assuming 2): got %08x", icarus->proc_repr, res);
 				applog(LOG_ERR, "%"PRIpreprv": Work division autodetection failed (assuming 2): got %08x", icarus->proc_repr, res);
 				info->work_division = 2;
 				info->work_division = 2;

+ 13 - 22
driver-ztex.c

@@ -1,27 +1,18 @@
-/**
- *   ztex.c - BFGMiner worker for Ztex 1.15x/y fpga board
+/*
+ * Copyright 2012 nelisky
+ * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2013 Denis Ahrens
+ * Copyright 2012 Xiangfu
  *
  *
- *   Copyright 2012 nelisky
- *   Copyright 2012-2013 Luke Dashjr
- *   Copyright 2012-2013 Denis Ahrens
- *   Copyright 2012 Xiangfu
+ * This work is based upon the Java SDK provided by ztex which is
+ * Copyright (C) 2009-2011 ZTEX GmbH.
+ * http://www.ztex.de
  *
  *
- *   This work is based upon the Java SDK provided by ztex which is
- *   Copyright (C) 2009-2011 ZTEX GmbH.
- *   http://www.ztex.de
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2 as
- *   published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- *   General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, see http://www.gnu.org/licenses/.
-**/
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
 
 
 #include "config.h"
 #include "config.h"
 
 

+ 2 - 0
fpgautils.h

@@ -21,6 +21,8 @@ extern int _serial_detect(struct device_drv *api, detectone_func_t, autoscan_fun
 	_serial_detect(api, detectone, autoscan, 2)
 	_serial_detect(api, detectone, autoscan, 2)
 #define serial_detect(api, detectone)  \
 #define serial_detect(api, detectone)  \
 	_serial_detect(api, detectone,     NULL, 0)
 	_serial_detect(api, detectone,     NULL, 0)
+#define serial_detect_byname(api, detectone)  \
+	_serial_detect(api, detectone,     NULL, 2)
 #define noserial_detect(api, autoscan)  \
 #define noserial_detect(api, autoscan)  \
 	_serial_detect(api, NULL     , autoscan, 0)
 	_serial_detect(api, NULL     , autoscan, 0)
 extern int _serial_autodetect(detectone_func_t, ...);
 extern int _serial_autodetect(detectone_func_t, ...);

+ 19 - 21
libztex.c

@@ -1,27 +1,25 @@
-/**
- *   libztex.c - Ztex 1.15x/1.15y fpga board support library
+/*
+ * Copyright 2012 nelisky
+ * Copyright 2012-2013 Luke Dashjr
+ * Copyright 2012-2013 Denis Ahrens~
+ * Copyright 2012 Peter Stuge~
  *
  *
- *   Copyright 2012 nelisky
- *   Copyright 2012-2013 Luke Dashjr
- *   Copyright 2012-2013 Denis Ahrens
- *   Copyright 2012 Peter Stuge
+ * This work is based upon the Java SDK provided by ztex which is
+ * Copyright (C) 2009-2011 ZTEX GmbH.
+ * http://www.ztex.de
  *
  *
- *   This work is based upon the Java SDK provided by ztex which is
- *   Copyright (C) 2009-2011 ZTEX GmbH.
- *   http://www.ztex.de
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
  *
  *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2 as
- *   published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- *   General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, see http://www.gnu.org/licenses/.
-**/
+ * The copyright status of some of this code is currently a bit confused. They
+ * were initially released under a license (GPLv2 only) incompatible with the
+ * rest of the program at the time (GPLv3 or newer), and I haven't had luck
+ * getting in touch with some later contributors (denoted above with a tilde) to
+ * clarify it. Since their modifications would have been a license violation,
+ * I'm assuming it was just an innocent mistake on their part.
+ */
 
 
 #define _GNU_SOURCE
 #define _GNU_SOURCE
 
 

+ 0 - 22
libztex.h

@@ -1,25 +1,3 @@
-/**
- *   libztex.h - headers for Ztex 1.15x fpga board support library
- *
- *   Copyright 2012 nelisky
- *   Copyright 2012 Luke Dashjr
- *
- *   This work is based upon the Java SDK provided by ztex which is
- *   Copyright (C) 2009-2011 ZTEX GmbH.
- *   http://www.ztex.de
- *
- *   This program is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License version 2 as
- *   published by the Free Software Foundation.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- *   General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, see http://www.gnu.org/licenses/.
-**/
 #ifndef __LIBZTEX_H__
 #ifndef __LIBZTEX_H__
 #define __LIBZTEX_H__
 #define __LIBZTEX_H__
 
 

+ 4 - 6
make-release

@@ -34,11 +34,10 @@ git clone . "$TMPDIR" -b TMP --depth 1
 git branch -D TMP
 git branch -D TMP
 cd "$TMPDIR"
 cd "$TMPDIR"
 git submodule update --init
 git submodule update --init
-git archive --prefix "$sw"/ --format tar "$tag" | tar xvp
-(
-	cd libblkmaker
-	git archive --prefix "libblkmaker/" --format tar HEAD | tar -C "../$sw" -xvp
-)
+{
+	git archive --prefix "$sw"/ --format tar "$tag"
+	git submodule --quiet foreach --recursive 'git archive --prefix "'"$sw"'/$path/" --format tar HEAD'
+} | tar -xivp
 cd "$sw"
 cd "$sw"
 NOSUBMODULES=1 \
 NOSUBMODULES=1 \
 NOCONFIGURE=1 \
 NOCONFIGURE=1 \
@@ -113,7 +112,6 @@ for build in "${builds[@]}"; do
 		*.cl \
 		*.cl \
 		example.conf \
 		example.conf \
 		windows-build.txt \
 		windows-build.txt \
-		API.class \
 		miner.php \
 		miner.php \
 		"$PKGDIR/"
 		"$PKGDIR/"
 	make clean
 	make clean

+ 65 - 34
miner.c

@@ -95,6 +95,7 @@ struct strategies strategies[] = {
 static char packagename[256];
 static char packagename[256];
 
 
 bool opt_protocol;
 bool opt_protocol;
+bool opt_dev_protocol;
 static bool opt_benchmark;
 static bool opt_benchmark;
 static bool want_longpoll = true;
 static bool want_longpoll = true;
 static bool want_gbt = true;
 static bool want_gbt = true;
@@ -639,6 +640,11 @@ char *set_request_diff(const char *arg, float *p)
 
 
 static
 static
 char* add_serial_all(char*arg, char*p) {
 char* add_serial_all(char*arg, char*p) {
+	size_t pLen = p - arg;
+	char dev[pLen + PATH_MAX];
+	memcpy(dev, arg, pLen);
+	char *devp = &dev[pLen];
+
 #ifdef HAVE_LIBUDEV
 #ifdef HAVE_LIBUDEV
 
 
 	struct udev *udev = udev_new();
 	struct udev *udev = udev_new();
@@ -658,11 +664,7 @@ char* add_serial_all(char*arg, char*p) {
 
 
 		const char *devpath = udev_device_get_devnode(device);
 		const char *devpath = udev_device_get_devnode(device);
 		if (devpath) {
 		if (devpath) {
-			size_t pLen = p - arg;
-			size_t dLen = strlen(devpath) + 1;
-			char dev[dLen + pLen];
-			memcpy(dev, arg, pLen);
-			memcpy(&dev[pLen], devpath, dLen);
+			strcpy(devp, devpath);
 			applog(LOG_DEBUG, "scan-serial: libudev all-adding %s", dev);
 			applog(LOG_DEBUG, "scan-serial: libudev all-adding %s", dev);
 			string_elist_add(dev, &scan_devices);
 			string_elist_add(dev, &scan_devices);
 		}
 		}
@@ -671,11 +673,10 @@ char* add_serial_all(char*arg, char*p) {
 	}
 	}
 	udev_enumerate_unref(enumerate);
 	udev_enumerate_unref(enumerate);
 	udev_unref(udev);
 	udev_unref(udev);
-	return NULL;
 
 
 #elif defined(WIN32)
 #elif defined(WIN32)
 
 
-	size_t bufLen = 0x10;  // temp!
+	size_t bufLen = 0x100;
 tryagain: ;
 tryagain: ;
 	char buf[bufLen];
 	char buf[bufLen];
 	if (!QueryDosDevice(NULL, buf, bufLen)) {
 	if (!QueryDosDevice(NULL, buf, bufLen)) {
@@ -686,11 +687,9 @@ tryagain: ;
 		}
 		}
 		return "scan-serial: Error occurred trying to enumerate COM ports with QueryDosDevice";
 		return "scan-serial: Error occurred trying to enumerate COM ports with QueryDosDevice";
 	}
 	}
-	size_t tLen = p - arg;
-	char dev[12 + tLen];
-	memcpy(dev, arg, tLen);
-	memcpy(&dev[tLen], "\\\\.\\", 4);
-	char *devp = &dev[tLen + 4];
+	size_t tLen;
+	memcpy(devp, "\\\\.\\", 4);
+	devp = &devp[4];
 	for (char *t = buf; *t; t += tLen) {
 	for (char *t = buf; *t; t += tLen) {
 		tLen = strlen(t) + 1;
 		tLen = strlen(t) + 1;
 		if (strncmp("COM", t, 3))
 		if (strncmp("COM", t, 3))
@@ -699,7 +698,6 @@ tryagain: ;
 		applog(LOG_DEBUG, "scan-serial: QueryDosDevice all-adding %s", dev);
 		applog(LOG_DEBUG, "scan-serial: QueryDosDevice all-adding %s", dev);
 		string_elist_add(dev, &scan_devices);
 		string_elist_add(dev, &scan_devices);
 	}
 	}
-	return NULL;
 
 
 #else
 #else
 
 
@@ -707,7 +705,7 @@ tryagain: ;
 	struct dirent *de;
 	struct dirent *de;
 	const char devdir[] = "/dev";
 	const char devdir[] = "/dev";
 	const size_t devdirlen = sizeof(devdir) - 1;
 	const size_t devdirlen = sizeof(devdir) - 1;
-	char devpath[sizeof(devdir) + NAME_MAX];
+	char *devpath = devp;
 	char *devfile = devpath + devdirlen + 1;
 	char *devfile = devpath + devdirlen + 1;
 	
 	
 	D = opendir(devdir);
 	D = opendir(devdir);
@@ -725,14 +723,16 @@ tryagain: ;
 		
 		
 trydev:
 trydev:
 		strcpy(devfile, de->d_name);
 		strcpy(devfile, de->d_name);
-		applog(LOG_DEBUG, "scan-serial: /dev glob all-adding %s", devpath);
-		string_elist_add(devpath, &scan_devices);
+		applog(LOG_DEBUG, "scan-serial: /dev glob all-adding %s", dev);
+		string_elist_add(dev, &scan_devices);
 	}
 	}
 	closedir(D);
 	closedir(D);
 	
 	
 	return NULL;
 	return NULL;
 
 
 #endif
 #endif
+
+	return NULL;
 }
 }
 
 
 static char *add_serial(char *arg)
 static char *add_serial(char *arg)
@@ -1261,6 +1261,9 @@ static struct opt_table opt_config_table[] = {
 	OPT_WITHOUT_ARG("--debuglog",
 	OPT_WITHOUT_ARG("--debuglog",
 		     opt_set_bool, &opt_debug,
 		     opt_set_bool, &opt_debug,
 		     "Enable debug logging"),
 		     "Enable debug logging"),
+	OPT_WITHOUT_ARG("--device-protocol-dump",
+			opt_set_bool, &opt_dev_protocol,
+			"Verbose dump of device protocol-level activities"),
 	OPT_WITH_ARG("--device|-d",
 	OPT_WITH_ARG("--device|-d",
 		     set_devices, NULL, NULL,
 		     set_devices, NULL, NULL,
 	             "Select device to use, one value, range and/or comma separated (e.g. 0-2,4) default: all"),
 	             "Select device to use, one value, range and/or comma separated (e.g. 0-2,4) default: all"),
@@ -2296,10 +2299,7 @@ hashrate_to_bufstr(char*buf, float hashrate, signed char unitin, enum h2bs_fmt f
 	if (hashrate >= 100 || unit < 2)
 	if (hashrate >= 100 || unit < 2)
 		prec = 1;
 		prec = 1;
 	else
 	else
-	if (hashrate >= 10)
 		prec = 2;
 		prec = 2;
-	else
-		prec = 3;
 	ucp = (fmt == H2B_NOUNIT ? '\0' : buf[5]);
 	ucp = (fmt == H2B_NOUNIT ? '\0' : buf[5]);
 	sprintf(buf, "%5.*f", prec, hashrate);
 	sprintf(buf, "%5.*f", prec, hashrate);
 	buf[5] = ucp;
 	buf[5] = ucp;
@@ -2321,20 +2321,20 @@ ti_hashrate_bufstr(char**out, float current, float average, float sharebased, en
 }
 }
 
 
 static const char *
 static const char *
-percentf(unsigned p, unsigned t, char *buf)
+percentf(double p, double t, char *buf)
 {
 {
 	if (!p)
 	if (!p)
 		return "none";
 		return "none";
 	if (!t)
 	if (!t)
 		return "100%";
 		return "100%";
-	p = p * 10000 / (p + t);
-	if (p < 100)
-		sprintf(buf, ".%02u%%", p);  // ".01%"
+	p /= p + t;
+	if (p < 0.01)
+		sprintf(buf, ".%02.0f%%", p * 10000);  // ".01%"
 	else
 	else
-	if (p < 1000)
-		sprintf(buf, "%u.%u%%", p / 100, (p % 100) / 10);  // "9.1%"
+	if (p < 0.1)
+		sprintf(buf, "%.1f%%", p * 100);  // "9.1%"
 	else
 	else
-		sprintf(buf, " %2u%%", p / 100);  // " 99%"
+		sprintf(buf, "%3.0f%%", p * 100);  // " 99%"
 	return buf;
 	return buf;
 }
 }
 
 
@@ -2367,6 +2367,8 @@ static void get_statline2(char *buf, struct cgpu_info *cgpu, bool for_curses)
 	int accepted = cgpu->accepted;
 	int accepted = cgpu->accepted;
 	int rejected = cgpu->rejected;
 	int rejected = cgpu->rejected;
 	int stale = cgpu->stale;
 	int stale = cgpu->stale;
+	double waccepted = cgpu->diff_accepted;
+	double wnotaccepted = cgpu->diff_rejected + cgpu->diff_stale;
 	int hwerrs = cgpu->hw_errors;
 	int hwerrs = cgpu->hw_errors;
 	
 	
 	if (!opt_show_procs)
 	if (!opt_show_procs)
@@ -2381,6 +2383,8 @@ static void get_statline2(char *buf, struct cgpu_info *cgpu, bool for_curses)
 			accepted += slave->accepted;
 			accepted += slave->accepted;
 			rejected += slave->rejected;
 			rejected += slave->rejected;
 			stale += slave->stale;
 			stale += slave->stale;
+			waccepted += slave->diff_accepted;
+			wnotaccepted += slave->diff_rejected + slave->diff_stale;
 			hwerrs += slave->hw_errors;
 			hwerrs += slave->hw_errors;
 		}
 		}
 	
 	
@@ -2467,7 +2471,7 @@ static void get_statline2(char *buf, struct cgpu_info *cgpu, bool for_curses)
 		            awidth, accepted,
 		            awidth, accepted,
 		            rwidth, rejected,
 		            rwidth, rejected,
 		            swidth, stale,
 		            swidth, stale,
-		            percentf(rejected + stale, accepted, rejpcbuf),
+		            percentf(wnotaccepted, waccepted, rejpcbuf),
 		            hwwidth, hwerrs
 		            hwwidth, hwerrs
 		);
 		);
 	}
 	}
@@ -2480,7 +2484,7 @@ static void get_statline2(char *buf, struct cgpu_info *cgpu, bool for_curses)
 			accepted,
 			accepted,
 			rejected,
 			rejected,
 			stale,
 			stale,
-			percentf(rejected + stale, accepted, rejpcbuf),
+			percentf(wnotaccepted, waccepted, rejpcbuf),
 			hwerrs);
 			hwerrs);
 	}
 	}
 	
 	
@@ -3544,7 +3548,9 @@ static void __kill_work(void)
 			continue;
 			continue;
 
 
 		cgpu->shutdown = true;
 		cgpu->shutdown = true;
+		thr->work_restart = true;
 		notifier_wake(thr->notifier);
 		notifier_wake(thr->notifier);
+		notifier_wake(thr->work_restart_notifier);
 	}
 	}
 
 
 	sleep(1);
 	sleep(1);
@@ -4037,6 +4043,7 @@ static void submit_discard_share2(const char *reason, struct work *work)
 	++cgpu->stale;
 	++cgpu->stale;
 	++(work->pool->stale_shares);
 	++(work->pool->stale_shares);
 	total_diff_stale += work->work_difficulty;
 	total_diff_stale += work->work_difficulty;
+	cgpu->diff_stale += work->work_difficulty;
 	work->pool->diff_stale += work->work_difficulty;
 	work->pool->diff_stale += work->work_difficulty;
 	mutex_unlock(&stats_lock);
 	mutex_unlock(&stats_lock);
 }
 }
@@ -5625,8 +5632,8 @@ static void display_options(void)
 
 
 	opt_loginput = true;
 	opt_loginput = true;
 	immedok(logwin, true);
 	immedok(logwin, true);
-	clear_logwin();
 retry:
 retry:
+	clear_logwin();
 	wlogprint("[N]ormal [C]lear [S]ilent mode (disable all output)\n");
 	wlogprint("[N]ormal [C]lear [S]ilent mode (disable all output)\n");
 	wlogprint("[D]ebug:%s\n[P]er-device:%s\n[Q]uiet:%s\n[V]erbose:%s\n"
 	wlogprint("[D]ebug:%s\n[P]er-device:%s\n[Q]uiet:%s\n[V]erbose:%s\n"
 		  "[R]PC debug:%s\n[W]orkTime details:%s\nsu[M]mary detail level:%s\n"
 		  "[R]PC debug:%s\n[W]orkTime details:%s\nsu[M]mary detail level:%s\n"
@@ -6034,7 +6041,7 @@ static void hashmeter(int thr_id, struct timeval *diff,
 		total_accepted,
 		total_accepted,
 		total_rejected,
 		total_rejected,
 		total_stale,
 		total_stale,
-		percentf(total_rejected + total_stale, total_accepted, rejpcbuf),
+		percentf(total_diff_rejected + total_diff_stale, total_diff_accepted, rejpcbuf),
 		hw_errors);
 		hw_errors);
 
 
 
 
@@ -6215,23 +6222,33 @@ static void shutdown_stratum(struct pool *pool)
 
 
 void clear_stratum_shares(struct pool *pool)
 void clear_stratum_shares(struct pool *pool)
 {
 {
+	int my_mining_threads = mining_threads;  // Cached outside of locking
 	struct stratum_share *sshare, *tmpshare;
 	struct stratum_share *sshare, *tmpshare;
 	struct work *work;
 	struct work *work;
 	struct cgpu_info *cgpu;
 	struct cgpu_info *cgpu;
 	double diff_cleared = 0;
 	double diff_cleared = 0;
+	double thr_diff_cleared[my_mining_threads];
 	int cleared = 0;
 	int cleared = 0;
+	int thr_cleared[my_mining_threads];
+	
+	// NOTE: This is per-thread rather than per-device to avoid getting devices lock in stratum_shares loop
+	for (int i = 0; i < my_mining_threads; ++i)
+	{
+		thr_diff_cleared[i] = 0;
+		thr_cleared[i] = 0;
+	}
 
 
 	mutex_lock(&sshare_lock);
 	mutex_lock(&sshare_lock);
 	HASH_ITER(hh, stratum_shares, sshare, tmpshare) {
 	HASH_ITER(hh, stratum_shares, sshare, tmpshare) {
-		if (sshare->work->pool == pool) {
+		if (sshare->work->pool == pool && work->thr_id < my_mining_threads) {
 			HASH_DEL(stratum_shares, sshare);
 			HASH_DEL(stratum_shares, sshare);
 			
 			
 			work = sshare->work;
 			work = sshare->work;
 			sharelog("disconnect", work);
 			sharelog("disconnect", work);
 			
 			
-			cgpu = get_thr_cgpu(work->thr_id);
-			++cgpu->stale;
 			diff_cleared += sshare->work->work_difficulty;
 			diff_cleared += sshare->work->work_difficulty;
+			thr_diff_cleared[work->thr_id] += work->work_difficulty;
+			++thr_cleared[work->thr_id];
 			free_work(sshare->work);
 			free_work(sshare->work);
 			free(sshare);
 			free(sshare);
 			cleared++;
 			cleared++;
@@ -6246,6 +6263,13 @@ void clear_stratum_shares(struct pool *pool)
 		total_stale += cleared;
 		total_stale += cleared;
 		pool->diff_stale += diff_cleared;
 		pool->diff_stale += diff_cleared;
 		total_diff_stale += diff_cleared;
 		total_diff_stale += diff_cleared;
+		for (int i = 0; i < my_mining_threads; ++i)
+			if (thr_cleared[i])
+			{
+				cgpu = get_thr_cgpu(i);
+				cgpu->diff_stale += thr_diff_cleared[i];
+				cgpu->stale += thr_cleared[i];
+			}
 		mutex_unlock(&stats_lock);
 		mutex_unlock(&stats_lock);
 
 
 		mutex_lock(&submitting_lock);
 		mutex_lock(&submitting_lock);
@@ -7119,6 +7143,7 @@ bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
 
 
 	cgtime(&tv_work_found);
 	cgtime(&tv_work_found);
 	*work_nonce = htole32(nonce);
 	*work_nonce = htole32(nonce);
+	work->thr_id = thr->id;
 
 
 	mutex_lock(&stats_lock);
 	mutex_lock(&stats_lock);
 	total_diff1++;
 	total_diff1++;
@@ -7133,7 +7158,7 @@ bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
 	if (unlikely(res == TNR_BAD))
 	if (unlikely(res == TNR_BAD))
 		{
 		{
 			struct cgpu_info *cgpu = thr->cgpu;
 			struct cgpu_info *cgpu = thr->cgpu;
-			applog(LOG_WARNING, "%"PRIpreprv": invalid nonce - HW error",
+			applog(LOG_DEBUG, "%"PRIpreprv": invalid nonce - HW error",
 			       cgpu->proc_repr);
 			       cgpu->proc_repr);
 			inc_hw_errors(thr);
 			inc_hw_errors(thr);
 			ret = false;
 			ret = false;
@@ -7183,6 +7208,12 @@ void __thr_being_msg(int prio, struct thr_info *thr, const char *being)
 
 
 void mt_disable_start(struct thr_info *mythr)
 void mt_disable_start(struct thr_info *mythr)
 {
 {
+	struct cgpu_info *cgpu = mythr->cgpu;
+	struct device_drv *drv = cgpu->drv;
+	
+	if (drv->thread_disable)
+		drv->thread_disable(mythr);
+	
 	hashmeter2(mythr);
 	hashmeter2(mythr);
 	if (mythr->prev_work)
 	if (mythr->prev_work)
 		free_work(mythr->prev_work);
 		free_work(mythr->prev_work);

+ 3 - 0
miner.h

@@ -314,6 +314,7 @@ struct device_drv {
 
 
 	void (*hw_error)(struct thr_info *);
 	void (*hw_error)(struct thr_info *);
 	void (*thread_shutdown)(struct thr_info *);
 	void (*thread_shutdown)(struct thr_info *);
+	void (*thread_disable)(struct thr_info *);
 	void (*thread_enable)(struct thr_info *);
 	void (*thread_enable)(struct thr_info *);
 
 
 	// Can be used per-thread or per-processor (only with minerloop async or queue!)
 	// Can be used per-thread or per-processor (only with minerloop async or queue!)
@@ -528,6 +529,7 @@ struct cgpu_info {
 	int diff1;
 	int diff1;
 	double diff_accepted;
 	double diff_accepted;
 	double diff_rejected;
 	double diff_rejected;
+	double diff_stale;
 	int last_share_pool;
 	int last_share_pool;
 	time_t last_share_pool_time;
 	time_t last_share_pool_time;
 	double last_share_diff;
 	double last_share_diff;
@@ -834,6 +836,7 @@ static inline void cg_wunlock(cglock_t *lock)
 struct pool;
 struct pool;
 
 
 extern bool opt_protocol;
 extern bool opt_protocol;
+extern bool opt_dev_protocol;
 extern char *opt_coinbase_sig;
 extern char *opt_coinbase_sig;
 extern bool have_longpoll;
 extern bool have_longpoll;
 extern int opt_skip_checks;
 extern int opt_skip_checks;

+ 1 - 4
ocl.c

@@ -225,11 +225,8 @@ char *file_contents(const char *filename, int *length)
 	void *buffer;
 	void *buffer;
 	FILE *f;
 	FILE *f;
 
 
-	strcpy(fullpath, opt_kernel_path);
-	strcat(fullpath, filename);
-
 	/* Try in the optional kernel path or installed prefix first */
 	/* Try in the optional kernel path or installed prefix first */
-	f = fopen(fullpath, "rb");
+	f = open_bitstream("opencl", filename);
 	if (!f) {
 	if (!f) {
 		/* Then try from the path BFGMiner was called */
 		/* Then try from the path BFGMiner was called */
 		strcpy(fullpath, cgminer_path);
 		strcpy(fullpath, cgminer_path);

+ 2 - 2
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:=9999
+PKG_VERSION:=3.1.0
 PKG_RELEASE:=1
 PKG_RELEASE:=1
 
 
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tbz2
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tbz2
@@ -127,7 +127,7 @@ endef
 
 
 define Package/$(PKG_NAME)-bitstream-$(1)/install
 define Package/$(PKG_NAME)-bitstream-$(1)/install
 	$(INSTALL_DIR) $$(1)/usr/share/$(PKG_NAME)/bitstreams
 	$(INSTALL_DIR) $$(1)/usr/share/$(PKG_NAME)/bitstreams
-	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/bitstreams/$(subst -,_,$(1))* $$(1)/usr/share/$(PKG_NAME)/bitstreams
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/share/$(PKG_NAME)/bitstreams/$(subst -,_,$(1))* $$(1)/usr/share/$(PKG_NAME)/bitstreams
 endef
 endef
 
 
 ALL_$(PKG_NAME)_PACKAGES += $(PKG_NAME)-bitstream-$(1)
 ALL_$(PKG_NAME)_PACKAGES += $(PKG_NAME)-bitstream-$(1)