Browse Source

Merge branch 'cg_merges_20130606b' into bfgminer

Luke Dashjr 12 years ago
parent
commit
dcc630c59e
21 changed files with 422 additions and 177 deletions
  1. 2 0
      API.java
  2. 1 0
      Makefile.am
  3. 9 6
      README
  4. 69 0
      README.ASIC
  5. 9 0
      README.GPU
  6. 9 2
      adl.c
  7. 1 0
      compat.h
  8. 1 0
      debian/bfgminer.docs
  9. 13 3
      deviceapi.c
  10. 52 24
      driver-avalon.c
  11. 3 0
      driver-avalon.h
  12. 25 25
      driver-bitforce.c
  13. 5 5
      driver-cairnsmore.c
  14. 9 9
      driver-icarus.c
  15. 5 12
      driver-opencl.c
  16. 7 7
      driver-x6500.c
  17. 1 0
      make-release
  18. 161 58
      miner.c
  19. 7 3
      miner.h
  20. 32 23
      util.c
  21. 1 0
      util.h

+ 2 - 0
API.java

@@ -1,4 +1,6 @@
 /*
+ *
+ * Copyright (C) Andrew Smith 2012-2013
  *
  * Usage: java API command ip port
  *

+ 1 - 0
Makefile.am

@@ -14,6 +14,7 @@ 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 \
+		  README.ASIC \
 		  README.GPU \
                   api-example.py
 

+ 9 - 6
README

@@ -31,8 +31,8 @@ irc://irc.freenode.net/eligius
 
 License: GPLv3.  See COPYING for details.
 
-SEE ALSO README.FPGA, README.GPU, README.RPC, AND README.scrypt FOR MORE
-INFORMATION ON EACH.
+SEE ALSO README.ASIC, README.FPGA, README.GPU, README.RPC, AND README.scrypt FOR
+MORE INFORMATION ON EACH.
 
 ---
 
@@ -169,7 +169,7 @@ Options for both config file and command line:
 --compact           Use compact display without per device statistics
 --debug|-D          Enable debug output
 --debuglog          Enable debug logging
---device|-d <arg>   Select device to use, (Use repeat -d for multiple devices, default: all)
+--device|-d <arg>   Select device to use, one value, range and/or comma separated (e.g. 0-2,4) default: all
 --disable-rejecting Automatically disable pools that continually reject shares
 --expiry|-E <arg>   Upper bound on how many seconds after getting work we consider a share from it stale (w/o longpoll active) (default: 120)
 --expiry-lp <arg>   Upper bound on how many seconds after getting work we consider a share from it stale (with longpoll active) (default: 3600)
@@ -249,6 +249,7 @@ GPU only options:
 --vectors|-v <arg>  Override detected optimal vector (1, 2 or 4) - one value or comma separated list
 --worksize|-w <arg> Override detected optimal worksize - one value or comma separated list
 
+See README.GPU for more information regarding GPU mining.
 
 scrypt only options:
 
@@ -258,7 +259,6 @@ scrypt only options:
 
 See README.scrypt for more information regarding (non-bitcoin) scrypt mining.
 
-
 ASIC/FPGA mining boards (BitForce, Icarus, ModMiner, X6500, ZTEX) only options:
 
 --scan-serial|-S <arg> Serial port to probe for mining devices
@@ -295,8 +295,7 @@ programmed every power cycle, including first use. To use these devices, you
 must download the BFGMiner source archive (bfgminer-x.y.z.zip) and copy the
 "bitstreams" directory into your BFGMiner application directory.
 
-For other FPGA details see the README.FPGA
-
+See README.ASIC and README.FPGA for more information regarding these.
 
 CPU only options (not included in binaries):
 
@@ -586,6 +585,10 @@ A: No, BFGMiner keeps a database of the block it's working on to ensure it does
 not work on stale blocks, and having different blocks from two networks would
 make it invalidate the work from each other.
 
+Q: Can I configure BFGMiner to mine with different login credentials or pools
+for each separate device?
+A: No.
+
 Q: Can I put multiple pools in the config file?
 A: Yes, check the example.conf file. Alternatively, set up everything either on
 the command line or via the menu after startup and choose settings->write

+ 69 - 0
README.ASIC

@@ -0,0 +1,69 @@
+SUPPORTED DEVICES
+
+Currently supported ASIC devices include ASICMiner's Block Erupter USB miners,
+Avalon, and Butterfly Labs' SC range of devices.
+
+AVALON
+
+Currently, Avalon boards are supported only by connecting them directly (or via
+a hub) to a regular PC running BFGMiner. It is also possible to install the
+OpenWrt packages of BFGMiner to the Avalon's embedded controller, but this is
+not a simple task due to its lack of available flash space.
+
+To use the Avalon from a regular PC, you will need to specify two options:
+First, add the -S option specifying the avalon driver specifically. For example,
+
+-S avalon:\\.\COM9
+
+Next, use the --avalon-options copying the command as used by the internal
+router used by the Avalon. eg:
+
+--avalon-options 115200:24:10:45:282
+
+The values are baud : miners : asic count : timeout : frequency.
+
+Baud:
+The device is pretty much hard coded to emulate 115200 baud so you shouldn't
+change this.
+
+Miners:
+Most Avalons are 3 module devices, which come to 24 miners. 4 module devices
+would use 32 here.
+
+Asic count:
+Virtually all have 10, so don't change this.
+
+Timeout:
+This is how long the device will work on a work item before accepting new work
+to replace it. It should be changed according to the frequency (last setting).
+It is possible to set this a little lower if you are trying to tune for short
+block mining (eg p2pool) but much lower and the device will start creating
+duplicate shares.
+
+Sample settings for different frequencies (last 2 values):
+43:300
+45:282
+47:270
+50:256
+
+Frequency:
+This is the clock speed of the devices. Only specific values work, 256, 270,
+282 (default) and 300.
+
+If you use the full curses based interface with Avalons you will get this
+information:
+AVA 0: 22/ 46C  60%/2400R
+
+The values are:
+ambient temp / highest device temp  set fan % / lowest detected fan RPM.
+
+Use the API for more detailed information than this.
+
+---
+
+This code is provided entirely free of charge by the programmer in his spare
+time so donations would be greatly appreciated. Please consider donating to the
+address below.
+
+Luke-Jr <luke-jr+bfgminer@utopios.org>
+1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh

+ 9 - 0
README.GPU

@@ -450,6 +450,11 @@ Q: I change my GPU engine/memory/voltage and BFGMiner reports back no change?
 A: BFGMiner asks the GPU using the ATI Display Library to change settings, but
 the driver and hardware are free to do what it wants with that query, including
 ignoring it. Some GPUs are locked with one or more of those properties as well.
+The most common of these is that many GPUs only allow a fixed difference
+between the engine clock speed and the memory clock speed (such as the memory
+being no lower than the engine - 150). Other 3rd party tools have unofficial
+data on these devices on windows and can get the memory clock speed down
+further but BFGMiner does not have access to these means.
 
 Q: I have multiple GPUs and although many devices show up, it appears to be
 working only on one GPU splitting it up.
@@ -466,6 +471,10 @@ Q: Do I need to recompile after updating my driver/SDK?
 A: No. The software is unchanged regardless of which driver/SDK/ADL version you
 are running.
 
+Q: I do not want BFGMiner to modify my engine/clock/fanspeed?
+A: BFGMiner only modifies values if you tell it to via some parameters.
+Otherwise it will just monitor the values.
+
 Q: Should I use crossfire/SLI?
 A: It does not benefit mining at all and depending on the GPU may actually
 worsen performance.

+ 9 - 2
adl.c

@@ -501,9 +501,16 @@ void init_adl(int nDevs)
 		if (!gpus[gpu].cutofftemp)
 			gpus[gpu].cutofftemp = opt_cutofftemp;
 		if (opt_autofan) {
-			ga->autofan = true;
 			/* Set a safe starting default if we're automanaging fan speeds */
-			set_fanspeed(gpu, 50);
+			int nominal = 50;
+
+			ga->autofan = true;
+			/* Clamp fanspeed values to range provided */
+			if (nominal > gpus[gpu].gpu_fan)
+				nominal = gpus[gpu].gpu_fan;
+			if (nominal < gpus[gpu].min_fan)
+				nominal = gpus[gpu].min_fan;
+			set_fanspeed(gpu, nominal);
 		}
 		if (opt_autoengine) {
 			ga->autoengine = true;

+ 1 - 0
compat.h

@@ -159,6 +159,7 @@ typedef long suseconds_t;
 #include <pthread.h>
 #include <signal.h>
 #define pthread_cancel(pth)  pthread_kill(pth, SIGTERM)
+extern void pthread_testcancel(void);
 #ifndef PTHREAD_CANCEL_ENABLE
 #define PTHREAD_CANCEL_ENABLE  0
 #define PTHREAD_CANCEL_DISABLE 1

+ 1 - 0
debian/bfgminer.docs

@@ -9,6 +9,7 @@ example.conf
 LICENSE
 NEWS
 README
+README.ASIC
 README.Debian
 README.FPGA
 README.RPC

+ 13 - 3
deviceapi.c

@@ -153,7 +153,11 @@ void minerloop_scanhash(struct thr_info *mythr)
 	struct work *work;
 	const bool primary = (!mythr->device_thread) || mythr->primary_thread;
 	
-	while (1) {
+#ifdef HAVE_PTHREAD_CANCEL
+	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+#endif
+	
+	while (likely(!cgpu->shutdown)) {
 		mythr->work_restart = false;
 		request_work(mythr);
 		work = get_and_prepare_work(mythr);
@@ -163,9 +167,14 @@ void minerloop_scanhash(struct thr_info *mythr)
 		
 		do {
 			thread_reportin(mythr);
+			/* Only allow the mining thread to be cancelled when
+			* it is not in the driver code. */
+			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
 			gettimeofday(&tv_start, NULL);
 			hashes = api->scanhash(mythr, work, work->blk.nonce + max_nonce);
 			gettimeofday(&tv_end, NULL);
+			pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+			pthread_testcancel();
 			thread_reportin(mythr);
 			
 			timersub(&tv_end, &tv_start, &tv_hashes);
@@ -392,7 +401,7 @@ void minerloop_async(struct thr_info *mythr)
 	if (mythr->work_restart_notifier[1] == -1)
 		notifier_init(mythr->work_restart_notifier);
 	
-	while (1) {
+	while (likely(!cgpu->shutdown)) {
 		tv_timeout.tv_sec = -1;
 		gettimeofday(&tv_now, NULL);
 		for (proc = cgpu; proc; proc = proc->next_proc)
@@ -477,7 +486,7 @@ void minerloop_queue(struct thr_info *thr)
 	if (thr->work_restart_notifier[1] == -1)
 		notifier_init(thr->work_restart_notifier);
 	
-	while (1) {
+	while (likely(!cgpu->shutdown)) {
 		tv_timeout.tv_sec = -1;
 		gettimeofday(&tv_now, NULL);
 		for (proc = cgpu; proc; proc = proc->next_proc)
@@ -568,6 +577,7 @@ void *miner_thread(void *userdata)
 		drv->minerloop(mythr);
 	else
 		minerloop_scanhash(mythr);
+	cgpu->deven = DEV_DISABLED;
 
 out:
 	if (drv->thread_shutdown)

+ 52 - 24
driver-avalon.c

@@ -41,7 +41,6 @@
 #include "util.h"
 
 static int option_offset = -1;
-struct avalon_info **avalon_infos;
 struct device_drv avalon_drv;
 
 static int avalon_init_task(struct avalon_task *at,
@@ -173,7 +172,7 @@ static int avalon_send_task(int fd, const struct avalon_task *at,
 	buf[4] = tt;
 #endif
 	if (likely(avalon)) {
-		info = avalon_infos[avalon->device_id];
+		info = avalon->device_data;
 		delay = nr_len * 10 * 1000000000ULL;
 		delay = delay / info->baud;
 	}
@@ -291,7 +290,7 @@ static bool avalon_decode_nonce(struct thr_info *thr, struct avalon_result *ar,
 	if (!work)
 		return false;
 
-	info = avalon_infos[avalon->device_id];
+	info = avalon->device_data;
 	info->matching_work[work->subid]++;
 	*nonce = htole32(ar->nonce);
 	submit_nonce(thr, work, *nonce);
@@ -388,7 +387,7 @@ static void avalon_idle(struct cgpu_info *avalon)
 	struct avalon_task at;
 
 	int fd = avalon->device_fd;
-	struct avalon_info *info = avalon_infos[avalon->device_id];
+	struct avalon_info *info = avalon->device_data;
 	int avalon_get_work_count = info->miner_count;
 
 	i = 0;
@@ -544,6 +543,25 @@ static void get_options(int this_option_offset, int *baud, int *miner_count,
 	}
 }
 
+/* Non blocking clearing of anything in the buffer */
+static void avalon_clear_readbuf(int fd)
+{
+	ssize_t ret;
+
+	do {
+		struct timeval timeout;
+		char buf[AVALON_FTDI_READSIZE];
+		fd_set rd;
+
+		timeout.tv_sec = timeout.tv_usec = 0;
+		FD_ZERO(&rd);
+		FD_SET((SOCKETTYPE)fd, &rd);
+		ret = select(fd + 1, &rd, NULL, NULL, &timeout);
+		if (ret > 0)
+			ret = read(fd, buf, AVALON_FTDI_READSIZE);
+	} while (ret > 0);
+}
+
 static bool avalon_detect_one(const char *devpath)
 {
 	struct avalon_info *info;
@@ -565,6 +583,7 @@ static bool avalon_detect_one(const char *devpath)
 		applog(LOG_ERR, "Avalon Detect: Failed to open %s", devpath);
 		return false;
 	}
+	avalon_clear_readbuf(fd);
 
 	/* We have a real Avalon! */
 	avalon = calloc(1, sizeof(struct cgpu_info));
@@ -581,21 +600,13 @@ static bool avalon_detect_one(const char *devpath)
 		   * return false; */
 	}
 	
-	avalon_infos = realloc(avalon_infos,
-			       sizeof(struct avalon_info *) *
-			       (total_devices + 1));
-
 	applog(LOG_INFO, "Avalon Detect: Found at %s, mark as %d",
 	       devpath, avalon->device_id);
 
-	avalon_infos[avalon->device_id] = (struct avalon_info *)
-		malloc(sizeof(struct avalon_info));
-	if (unlikely(!(avalon_infos[avalon->device_id])))
-		quit(1, "Failed to malloc avalon_infos");
-
-	info = avalon_infos[avalon->device_id];
-
-	memset(info, 0, sizeof(struct avalon_info));
+	avalon->device_data = calloc(sizeof(struct avalon_info), 1);
+	if (unlikely(!(avalon->device_data)))
+		quit(1, "Failed to malloc avalon_info data");
+	info = avalon->device_data;
 
 	info->baud = baud;
 	info->miner_count = miner_count;
@@ -634,12 +645,12 @@ static void __avalon_init(struct cgpu_info *avalon)
 
 static void avalon_init(struct cgpu_info *avalon)
 {
+	struct avalon_info *info = avalon->device_data;
 	struct avalon_result ar;
 	int fd, ret;
 
 	avalon->device_fd = -1;
-	fd = avalon_open(avalon->device_path,
-			     avalon_infos[avalon->device_id]->baud);
+	fd = avalon_open(avalon->device_path, info->baud);
 	if (unlikely(fd == -1)) {
 		applog(LOG_ERR, "Avalon: Failed to open on %s",
 		       avalon->device_path);
@@ -659,7 +670,7 @@ static void avalon_init(struct cgpu_info *avalon)
 static bool avalon_prepare(struct thr_info *thr)
 {
 	struct cgpu_info *avalon = thr->cgpu;
-	struct avalon_info *info = avalon_infos[avalon->device_id];
+	struct avalon_info *info = avalon->device_data;
 	struct timeval now;
 
 	free(avalon->works);
@@ -689,7 +700,7 @@ static void avalon_free_work(struct thr_info *thr)
 	if (unlikely(!avalon->works))
 		return;
 	works = avalon->works;
-	info = avalon_infos[avalon->device_id];
+	info = avalon->device_data;
 
 	for (i = 0; i < info->miner_count * 4; i++) {
 		if (works[i]) {
@@ -703,7 +714,7 @@ static void do_avalon_close(struct thr_info *thr)
 {
 	struct avalon_result ar;
 	struct cgpu_info *avalon = thr->cgpu;
-	struct avalon_info *info = avalon_infos[avalon->device_id];
+	struct avalon_info *info = avalon->device_data;
 
 	avalon_free_work(thr);
 	nmsleep(1000);
@@ -765,13 +776,29 @@ static inline void adjust_fan(struct avalon_info *info)
 	}
 }
 
+static void get_avalon_statline_before(char *buf, struct cgpu_info *avalon)
+{
+	struct avalon_info *info = avalon->device_data;
+	int lowfan = 10000;
+
+	/* Find the lowest fan speed of the ASIC cooling fans. */
+	if (info->fan1 >= 0 && info->fan1 < lowfan)
+		lowfan = info->fan1;
+	if (info->fan2 >= 0 && info->fan2 < lowfan)
+		lowfan = info->fan2;
+
+	tailsprintf(buf, "%2d/%3dC %04dR | ", info->temp0, info->temp2, lowfan);
+}
+
 /* We use a replacement algorithm to only remove references to work done from
  * the buffer when we need the extra space for new work. */
 static bool avalon_fill(struct cgpu_info *avalon)
 {
-	int subid, slot, mc = avalon_infos[avalon->device_id]->miner_count;
+	struct avalon_info *info = avalon->device_data;
+	int subid, slot, mc;
 	struct work *work;
 
+	mc = info->miner_count;
 	if (avalon->queued >= mc)
 		return true;
 	work = get_queued(avalon);
@@ -816,7 +843,7 @@ static int64_t avalon_scanhash(struct thr_info *thr)
 
 	avalon = thr->cgpu;
 	works = avalon->works;
-	info = avalon_infos[avalon->device_id];
+	info = avalon->device_data;
 	avalon_get_work_count = info->miner_count;
 
 	if (unlikely(avalon->device_fd == -1)) {
@@ -969,7 +996,7 @@ static int64_t avalon_scanhash(struct thr_info *thr)
 static struct api_data *avalon_api_stats(struct cgpu_info *cgpu)
 {
 	struct api_data *root = NULL;
-	struct avalon_info *info = avalon_infos[cgpu->device_id];
+	struct avalon_info *info = cgpu->device_data;
 	int i;
 
 	root = api_add_int(root, "baud", &(info->baud), false);
@@ -1012,6 +1039,7 @@ struct device_drv avalon_drv = {
 	.queue_full = avalon_fill,
 	.scanwork = avalon_scanhash,
 	.get_api_stats = avalon_api_stats,
+	.get_statline_before = get_avalon_statline_before,
 	.reinit_device = avalon_init,
 	.thread_shutdown = avalon_shutdown,
 };

+ 3 - 0
driver-avalon.h

@@ -1,5 +1,6 @@
 /*
  * Copyright 2013 Avalon project
+ * Copyright 2013 Con Kolivas
  *
  * 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
@@ -28,6 +29,8 @@
 #define AVALON_DEFAULT_MINER_NUM 0x20
 #define AVALON_DEFAULT_ASIC_NUM 0xA
 
+#define AVALON_FTDI_READSIZE 512
+
 struct avalon_task {
 	uint8_t reset		:1;
 	uint8_t flush_fifo	:1;

+ 25 - 25
driver-bitforce.c

@@ -198,7 +198,7 @@ static bool bitforce_detect_one(const char *devpath)
 		s[0] = '\0';
 		bitforce->name = strdup(pdevbuf + 7);
 	}
-	bitforce->cgpu_data = initdata;
+	bitforce->device_data = initdata;
 
 	mutex_init(&bitforce->device_mutex);
 
@@ -242,7 +242,7 @@ static
 void bitforce_comm_error(struct thr_info *thr)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	int *p_fdDev = &bitforce->device->device_fd;
 	
 	data->noncebuf[0] = '\0';
@@ -263,7 +263,7 @@ void bitforce_comm_error(struct thr_info *thr)
 
 static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
 {
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 
 	if (data->temp[0] > 0 && data->temp[1] > 0)
 		tailsprintf(buf, "%5.1fC/%4.1fC   | ", data->temp[0], data->temp[1]);
@@ -323,7 +323,7 @@ static void bitforce_clear_buffer(struct cgpu_info *bitforce)
 
 void bitforce_reinit(struct cgpu_info *bitforce)
 {
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	struct thr_info *thr = bitforce->thr[0];
 	const char *devpath = bitforce->device_path;
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
@@ -408,7 +408,7 @@ void bitforce_reinit(struct cgpu_info *bitforce)
 
 static void bitforce_flash_led(struct cgpu_info *bitforce)
 {
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
 	int fdDev = bitforce->device->device_fd;
 
@@ -462,7 +462,7 @@ void set_float_if_gt_zero(float *var, float value)
 
 static bool bitforce_get_temp(struct cgpu_info *bitforce)
 {
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
 	int fdDev = bitforce->device->device_fd;
 	char pdevbuf[0x100];
@@ -535,7 +535,7 @@ void dbg_block_data(struct cgpu_info *bitforce)
 	if (!opt_debug)
 		return;
 	
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	char *s;
 	s = bin2hex(&data->next_work_ob[8], 44);
 	applog(LOG_DEBUG, "%"PRIpreprv": block data: %s", bitforce->proc_repr, s);
@@ -548,7 +548,7 @@ static
 bool bitforce_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused uint64_t max_nonce)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	int fdDev = bitforce->device->device_fd;
 	unsigned char *ob_ms = &data->next_work_ob[8];
 	unsigned char *ob_dt = &ob_ms[32];
@@ -610,7 +610,7 @@ bool bitforce_job_prepare(struct thr_info *thr, struct work *work, __maybe_unuse
 static
 void bitforce_change_mode(struct cgpu_info *bitforce, enum bitforce_proto proto)
 {
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	
 	if (data->proto == proto)
 		return;
@@ -667,7 +667,7 @@ static
 void bitforce_job_start(struct thr_info *thr)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
 	int fdDev = bitforce->device->device_fd;
 	unsigned char *ob = data->next_work_obs;
@@ -745,7 +745,7 @@ static
 int bitforce_zox(struct thr_info *thr, const char *cmd)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
 	int fd = bitforce->device->device_fd;
 	char *pdevbuf = &data->noncebuf[0];
@@ -803,7 +803,7 @@ static
 void bitforce_job_get_results(struct thr_info *thr, struct work *work)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	int fdDev = bitforce->device->device_fd;
 	unsigned int delay_time_ms;
 	struct timeval elapsed;
@@ -1008,7 +1008,7 @@ static
 void bitforce_process_result_nonces(struct thr_info *thr, struct work *work, char *pnoncebuf)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	uint32_t nonce;
 	
 	while (1) {
@@ -1077,7 +1077,7 @@ static
 int64_t bitforce_job_process_results(struct thr_info *thr, struct work *work, __maybe_unused bool stopping)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	char *pnoncebuf = &data->noncebuf[0];
 	int count;
 	
@@ -1140,7 +1140,7 @@ static bool bitforce_thread_init(struct thr_info *thr)
 	struct cgpu_info *bitforce = thr->cgpu;
 	unsigned int wait;
 	struct bitforce_data *data;
-	struct bitforce_init_data *initdata = bitforce->cgpu_data;
+	struct bitforce_init_data *initdata = bitforce->device_data;
 	bool sc = initdata->sc;
 	int xlink_id = 0;
 	
@@ -1157,7 +1157,7 @@ static bool bitforce_thread_init(struct thr_info *thr)
 		}
 		
 		bitforce->sleep_ms = BITFORCE_SLEEP_MS;
-		bitforce->cgpu_data = data = malloc(sizeof(*data));
+		bitforce->device_data = data = malloc(sizeof(*data));
 		*data = (struct bitforce_data){
 			.xlink_id = xlink_id,
 			.next_work_ob = ">>>>>>>>|---------- MidState ----------||-DataTail-||Nonces|>>>>>>>>",
@@ -1211,7 +1211,7 @@ static bool bitforce_thread_init(struct thr_info *thr)
 
 static struct api_data *bitforce_drv_stats(struct cgpu_info *cgpu)
 {
-	struct bitforce_data *data = cgpu->cgpu_data;
+	struct bitforce_data *data = cgpu->device_data;
 	struct api_data *root = NULL;
 
 	// Warning, access to these is not locked - but we don't really
@@ -1233,7 +1233,7 @@ static struct api_data *bitforce_drv_stats(struct cgpu_info *cgpu)
 void bitforce_poll(struct thr_info *thr)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	int poll = data->poll_func;
 	thr->tv_poll.tv_sec = -1;
 	data->poll_func = 0;
@@ -1253,7 +1253,7 @@ void bitforce_poll(struct thr_info *thr)
 static
 char *bitforce_set_device(struct cgpu_info *proc, char *option, char *setting, char *replybuf)
 {
-	struct bitforce_data *data = proc->cgpu_data;
+	struct bitforce_data *data = proc->device_data;
 	pthread_mutex_t *mutexp = &proc->device->device_mutex;
 	int fd;
 	
@@ -1316,7 +1316,7 @@ static inline
 void bitforce_set_queue_full(struct thr_info *thr)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_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);
 }
@@ -1325,7 +1325,7 @@ static
 bool bitforce_send_queue(struct thr_info *thr)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	pthread_mutex_t *mutexp = &bitforce->device->device_mutex;
 	int fd = bitforce->device->device_fd;
 	struct work *work;
@@ -1401,7 +1401,7 @@ static
 bool bitforce_queue_do_results(struct thr_info *thr)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	int fd = bitforce->device->device_fd;
 	int count;
 	char *noncebuf = &data->noncebuf[0], *buf, *end;
@@ -1518,7 +1518,7 @@ static
 bool bitforce_queue_append(struct thr_info *thr, struct work *work)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	bool rv, ndq;
 	
 	bitforce_set_queue_full(thr);
@@ -1560,7 +1560,7 @@ static
 void bitforce_queue_flush(struct thr_info *thr)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_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];
@@ -1597,7 +1597,7 @@ static
 void bitforce_queue_poll(struct thr_info *thr)
 {
 	struct cgpu_info *bitforce = thr->cgpu;
-	struct bitforce_data *data = bitforce->cgpu_data;
+	struct bitforce_data *data = bitforce->device_data;
 	unsigned long sleep_us;
 	
 	if (data->queued)

+ 5 - 5
driver-cairnsmore.c

@@ -109,7 +109,7 @@ bool cairnsmore_supports_dynclock(int fd)
 static bool cairnsmore_change_clock_func(struct thr_info *thr, int bestM)
 {
 	struct cgpu_info *cm1 = thr->cgpu;
-	struct ICARUS_INFO *info = cm1->cgpu_data;
+	struct ICARUS_INFO *info = cm1->device_data;
 
 	if (unlikely(!cairnsmore_send_cmd(cm1->device_fd, 0, bestM)))
 		return false;
@@ -126,7 +126,7 @@ static bool cairnsmore_change_clock_func(struct thr_info *thr, int bestM)
 static bool cairnsmore_init(struct thr_info *thr)
 {
 	struct cgpu_info *cm1 = thr->cgpu;
-	struct ICARUS_INFO *info = cm1->cgpu_data;
+	struct ICARUS_INFO *info = cm1->device_data;
 	struct icarus_state *state = thr->cgpu_data;
 
 	if (cairnsmore_supports_dynclock(cm1->device_fd)) {
@@ -160,7 +160,7 @@ static bool cairnsmore_init(struct thr_info *thr)
 
 void convert_icarus_to_cairnsmore(struct cgpu_info *cm1)
 {
-	struct ICARUS_INFO *info = cm1->cgpu_data;
+	struct ICARUS_INFO *info = cm1->device_data;
 	info->Hs = CAIRNSMORE1_HASH_TIME;
 	info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
 	info->timing_mode = MODE_LONG;
@@ -172,7 +172,7 @@ void convert_icarus_to_cairnsmore(struct cgpu_info *cm1)
 
 static struct api_data *cairnsmore_drv_extra_device_status(struct cgpu_info *cm1)
 {
-	struct ICARUS_INFO *info = cm1->cgpu_data;
+	struct ICARUS_INFO *info = cm1->device_data;
 	struct api_data*root = NULL;
 
 	if (info->dclk.freqM) {
@@ -185,7 +185,7 @@ static struct api_data *cairnsmore_drv_extra_device_status(struct cgpu_info *cm1
 
 static bool cairnsmore_identify(struct cgpu_info *cm1)
 {
-	struct ICARUS_INFO *info = cm1->cgpu_data;
+	struct ICARUS_INFO *info = cm1->device_data;
 	if (!info->dclk.freqM)
 		return false;
 	

+ 9 - 9
driver-icarus.c

@@ -319,7 +319,7 @@ static const char *timing_mode_str(enum timing_mode timing_mode)
 
 static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 {
-	struct ICARUS_INFO *info = icarus->cgpu_data;
+	struct ICARUS_INFO *info = icarus->device_data;
 	double Hs;
 	char buf[BUFSIZ+1];
 	char *ptr, *comma, *eq;
@@ -618,7 +618,7 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 		icarus->proc_repr,
 		baud, work_division, fpga_count);
 
-	icarus->cgpu_data = info;
+	icarus->device_data = info;
 
 	timersub(&tv_finish, &tv_start, &(info->golden_tv));
 
@@ -653,7 +653,7 @@ static void icarus_detect()
 static bool icarus_prepare(struct thr_info *thr)
 {
 	struct cgpu_info *icarus = thr->cgpu;
-	struct ICARUS_INFO *info = icarus->cgpu_data;
+	struct ICARUS_INFO *info = icarus->device_data;
 
 	struct timeval now;
 
@@ -691,7 +691,7 @@ static bool icarus_prepare(struct thr_info *thr)
 static bool icarus_init(struct thr_info *thr)
 {
 	struct cgpu_info *icarus = thr->cgpu;
-	struct ICARUS_INFO *info = icarus->cgpu_data;
+	struct ICARUS_INFO *info = icarus->device_data;
 	int fd = icarus->device_fd;
 	
 	if (!info->work_division)
@@ -741,7 +741,7 @@ static bool icarus_init(struct thr_info *thr)
 
 static bool icarus_reopen(struct cgpu_info *icarus, struct icarus_state *state, int *fdp)
 {
-	struct ICARUS_INFO *info = icarus->cgpu_data;
+	struct ICARUS_INFO *info = icarus->device_data;
 
 	// Reopen the serial port to workaround a USB-host-chipset-specific issue with the Icarus's buggy USB-UART
 	icarus_close(icarus->device_fd);
@@ -768,7 +768,7 @@ static bool icarus_start_work(struct thr_info *thr, const unsigned char *ob_bin)
 	ret = icarus_write(fd, ob_bin, 64);
 	if (ret) {
 		do_icarus_close(thr);
-		applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id);
+		applog(LOG_ERR, "%"PRIpreprv": Comms error (werr=%d)", icarus->proc_repr, ret);
 		dev_error(icarus, REASON_DEV_COMMS_ERROR);
 		return false;	/* This should never happen */
 	}
@@ -830,7 +830,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	// Wait for the previous run's result
 	fd = icarus->device_fd;
-	info = icarus->cgpu_data;
+	info = icarus->device_data;
 
 	if (!state->firstrun) {
 		if (state->changework)
@@ -851,7 +851,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 					return 0;
 				case ICA_GETS_ERROR:
 					do_icarus_close(thr);
-					applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id);
+					applog(LOG_ERR, "%"PRIpreprv": Comms error (rerr)", icarus->proc_repr);
 					dev_error(icarus, REASON_DEV_COMMS_ERROR);
 					if (!icarus_reopen(icarus, state, &fd))
 						return -1;
@@ -1094,7 +1094,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 static struct api_data *icarus_drv_stats(struct cgpu_info *cgpu)
 {
 	struct api_data *root = NULL;
-	struct ICARUS_INFO *info = cgpu->cgpu_data;
+	struct ICARUS_INFO *info = cgpu->device_data;
 
 	// Warning, access to these is not locked - but we don't really
 	// care since hashing performance is way more important than

+ 5 - 12
driver-opencl.c

@@ -459,7 +459,7 @@ char *set_kernel(char *arg)
 	char *nextptr;
 
 	if (opt_scrypt)
-		return "Cannot use sha256 kernel with scrypt";
+		return "Cannot specify a kernel with scrypt";
 	nextptr = strtok(arg, ",");
 	if (nextptr == NULL)
 		return "Invalid parameters for set kernel";
@@ -515,14 +515,6 @@ char *set_gpu_map(char *arg)
 	return NULL;
 }
 
-void get_intrange(char *arg, int *val1, int *val2)
-{
-	if (sscanf(arg, "%d-%d", val1, val2) == 1) {
-		*val2 = *val1;
-		*val1 = 0;
-	}
-}
-
 char *set_gpu_engine(char *arg)
 {
 	int i, val1 = 0, val2 = 0, device = 0;
@@ -951,6 +943,7 @@ retry:
 	wlogprint("[E]nable [D]isable [I]ntensity [R]estart GPU %s\n",adl_active ? "[C]hange settings" : "");
 
 	wlogprint("Or press any other key to continue\n");
+	logwin_update();
 	input = getch();
 
 	if (nDevs == 1)
@@ -1475,7 +1468,7 @@ static void opencl_detect()
 		
 #ifdef HAVE_SENSORS
 		cn = (c == -1) ? NULL : sensors_get_detected_chips(&cnm, &c);
-		cgpu->cgpu_data = data = malloc(sizeof(*data));
+		cgpu->device_data = data = malloc(sizeof(*data));
 		*data = (struct opencl_device_data){
 			.sensor = cn,
 		};
@@ -1496,7 +1489,7 @@ static void reinit_opencl_device(struct cgpu_info *gpu)
 static void get_opencl_statline_before(char *buf, struct cgpu_info *gpu)
 {
 #ifdef HAVE_SENSORS
-	struct opencl_device_data *data = gpu->cgpu_data;
+	struct opencl_device_data *data = gpu->device_data;
 	if (data->sensor)
 	{
 		const sensors_chip_name *cn = data->sensor;
@@ -1832,9 +1825,9 @@ static void opencl_thread_shutdown(struct thr_info *thr)
 	const int thr_id = thr->id;
 	_clState *clState = clStates[thr_id];
 
-	clReleaseCommandQueue(clState->commandQueue);
 	clReleaseKernel(clState->kernel);
 	clReleaseProgram(clState->program);
+	clReleaseCommandQueue(clState->commandQueue);
 	clReleaseContext(clState->context);
 }
 

+ 7 - 7
driver-x6500.c

@@ -134,7 +134,7 @@ static bool x6500_foundusb(libusb_device *dev, const char *product, const char *
 	x6500->procs = 2;
 	x6500->name = strdup(product);
 	x6500->cutofftemp = 85;
-	x6500->cgpu_data = dev;
+	x6500->device_data = dev;
 
 	return add_cgpu(x6500);
 }
@@ -161,7 +161,7 @@ static bool x6500_prepare(struct thr_info *thr)
 	if (x6500->proc_id)
 		return true;
 	
-	struct ft232r_device_handle *ftdi = ft232r_open(x6500->cgpu_data);
+	struct ft232r_device_handle *ftdi = ft232r_open(x6500->device_data);
 	x6500->device_ft232r = NULL;
 	if (!ftdi)
 		return false;
@@ -176,12 +176,12 @@ static bool x6500_prepare(struct thr_info *thr)
 	*pdone = 101;
 	jtag_a = (void*)(pdone + 1);
 	jtag_a->ftdi = ftdi;
-	x6500->cgpu_data = jtag_a;
+	x6500->device_data = jtag_a;
 	
 	for (struct cgpu_info *slave = x6500->next_proc; slave; slave = slave->next_proc)
 	{
 		slave->device_ft232r = x6500->device_ft232r;
-		slave->cgpu_data = x6500->cgpu_data;
+		slave->device_data = x6500->device_data;
 	}
 	
 	return true;
@@ -213,7 +213,7 @@ x6500_fpga_upload_bitstream(struct cgpu_info *x6500, struct jtag_port *jp1)
 {
 	char buf[0x100];
 	unsigned long len, flen;
-	unsigned char *pdone = (unsigned char*)x6500->cgpu_data - 1;
+	unsigned char *pdone = (unsigned char*)x6500->device_data - 1;
 	struct ft232r_device_handle *ftdi = jp1->a->ftdi;
 
 	FILE *f = open_xilinx_bitstream(x6500->drv->dname, x6500->dev_repr, X6500_BITSTREAM_FILENAME, &len);
@@ -357,7 +357,7 @@ static bool x6500_thread_init(struct thr_info *thr)
 	
 	fpga = calloc(1, sizeof(*fpga));
 	jp = &fpga->jtag;
-	jp->a = x6500->cgpu_data;
+	jp->a = x6500->device_data;
 	x6500_jtag_set(jp, pinoffset);
 	thr->cgpu_data = fpga;
 	
@@ -561,7 +561,7 @@ bool get_x6500_upload_percent(char *buf, struct cgpu_info *x6500)
 {
 	char info[18] = "               | ";
 
-	unsigned char pdone = *((unsigned char*)x6500->cgpu_data - 1);
+	unsigned char pdone = *((unsigned char*)x6500->device_data - 1);
 	if (pdone != 101) {
 		sprintf(&info[1], "%3d%%", pdone);
 		info[5] = ' ';

+ 1 - 0
make-release

@@ -63,6 +63,7 @@ docs='
 	COPYING
 	NEWS
 	README
+	README.ASIC
 	README.Debian
 	README.FPGA
 	README.RPC

+ 161 - 58
miner.c

@@ -155,7 +155,9 @@ static bool opt_nogpu;
 
 struct string_elist *scan_devices;
 bool opt_force_dev_init;
-static signed int devices_enabled;
+static bool devices_enabled[MAX_DEVICES];
+static int opt_devs_enabled;
+static bool opt_display_devs;
 static bool opt_removedisabled;
 int total_devices;
 struct cgpu_info **devices;
@@ -749,21 +751,52 @@ static char *add_serial(char *arg)
 }
 #endif
 
+void get_intrange(char *arg, int *val1, int *val2)
+{
+	if (sscanf(arg, "%d-%d", val1, val2) == 1)
+		*val2 = *val1;
+}
+
 static char *set_devices(char *arg)
 {
-	int i = strtol(arg, &arg, 0);
+	int i, val1 = 0, val2 = 0;
+	char *nextptr;
 
 	if (*arg) {
 		if (*arg == '?') {
-			devices_enabled = -1;
+			opt_display_devs = true;
 			return NULL;
 		}
-		return "Invalid device number";
+	} else
+		return "Invalid device parameters";
+
+	nextptr = strtok(arg, ",");
+	if (nextptr == NULL)
+		return "Invalid parameters for set devices";
+	get_intrange(nextptr, &val1, &val2);
+	if (val1 < 0 || val1 > MAX_DEVICES || val2 < 0 || val2 > MAX_DEVICES ||
+	    val1 > val2) {
+		return "Invalid value passed to set devices";
+	}
+
+	for (i = val1; i <= val2; i++) {
+		devices_enabled[i] = true;
+		opt_devs_enabled++;
+	}
+
+	while ((nextptr = strtok(NULL, ",")) != NULL) {
+		get_intrange(nextptr, &val1, &val2);
+		if (val1 < 0 || val1 > MAX_DEVICES || val2 < 0 || val2 > MAX_DEVICES ||
+		val1 > val2) {
+			return "Invalid value passed to set devices";
+		}
+
+		for (i = val1; i <= val2; i++) {
+			devices_enabled[i] = true;
+			opt_devs_enabled++;
+		}
 	}
 
-	if (i < 0 || i >= (int)(sizeof(devices_enabled) * 8) - 1)
-		return "Invalid device number";
-	devices_enabled |= 1 << i;
 	return NULL;
 }
 
@@ -1230,7 +1263,7 @@ static struct opt_table opt_config_table[] = {
 		     "Enable debug logging"),
 	OPT_WITH_ARG("--device|-d",
 		     set_devices, NULL, NULL,
-	             "Select device to use, (Use repeat -d for multiple devices, default: all)"),
+	             "Select device to use, one value, range and/or comma separated (e.g. 0-2,4) default: all"),
 	OPT_WITHOUT_ARG("--disable-gpu|-G",
 			opt_set_bool, &opt_nogpu,
 #ifdef HAVE_OPENCL
@@ -2094,13 +2127,19 @@ struct cgpu_info gpus[MAX_GPUDEVICES]; /* Maximum number apparently possible */
 struct cgpu_info *cpus;
 
 #ifdef HAVE_CURSES
+static bool _curses_cancel_disabled;
+static int _curses_prev_cancelstate;
+
 static inline void unlock_curses(void)
 {
 	mutex_unlock(&console_lock);
+	if (_curses_cancel_disabled)
+		pthread_setcancelstate(_curses_prev_cancelstate, &_curses_prev_cancelstate);
 }
 
 static inline void lock_curses(void)
 {
+	_curses_cancel_disabled = !pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &_curses_prev_cancelstate);
 	mutex_lock(&console_lock);
 }
 
@@ -2545,17 +2584,14 @@ static void adj_width(int var, int *length)
 
 static int dev_width;
 
-static void curses_print_devstatus(int thr_id)
+static void curses_print_devstatus(struct cgpu_info *cgpu)
 {
-	struct cgpu_info *cgpu;
 	char logline[256];
 	int ypos;
 
 	if (opt_compact)
 		return;
 
-	cgpu = get_thr_cgpu(thr_id);
-
 	/* Check this isn't out of the window size */
 	if (opt_show_procs)
 	ypos = cgpu->cgminer_id;
@@ -2640,21 +2676,22 @@ static void check_winsizes(void)
 
 static int device_line_id_count;
 
-static void switch_compact(void)
+static void switch_logsize(void)
 {
-	if (opt_compact) {
-		logstart = devcursor + 1;
-		logcursor = logstart + 1;
-	} else {
-		total_lines = (opt_show_procs ? total_devices : device_line_id_count);
-		logstart = devcursor + total_lines + 1;
-		logcursor = logstart + 1;
+	if (curses_active_locked()) {
+		if (opt_compact) {
+			logstart = devcursor + 1;
+			logcursor = logstart + 1;
+		} else {
+			total_lines = (opt_show_procs ? total_devices : device_line_id_count);
+			logstart = devcursor + total_lines + 1;
+			logcursor = logstart + 1;
+		}
+		unlock_curses();
 	}
 	check_winsizes();
 }
 
-#define change_summarywinsize  switch_compact
-
 /* For mandatory printing when mutex is already locked */
 void wlog(const char *f, ...)
 {
@@ -2707,6 +2744,15 @@ void clear_logwin(void)
 		unlock_curses();
 	}
 }
+
+void logwin_update(void)
+{
+	if (curses_active_locked()) {
+		touchwin(logwin);
+		wrefresh(logwin);
+		unlock_curses();
+	}
+}
 #endif
 
 static void enable_pool(struct pool *pool)
@@ -3484,23 +3530,37 @@ static void __kill_work(void)
 	thr = &control_thr[watchdog_thr_id];
 	thr_info_cancel(thr);
 
-	applog(LOG_DEBUG, "Stopping mining threads");
-	/* Stop the mining threads*/
+	applog(LOG_DEBUG, "Shutting down mining threads");
 	for (i = 0; i < mining_threads; i++) {
+		struct cgpu_info *cgpu;
+
 		thr = get_thread(i);
-		if (thr->cgpu->threads)
-			thr_info_freeze(thr);
-		thr->pause = true;
+		if (!thr)
+			continue;
+		cgpu = thr->cgpu;
+		if (!cgpu)
+			continue;
+		if (!cgpu->threads)
+			continue;
+
+		cgpu->shutdown = true;
+		notifier_wake(thr->notifier);
 	}
 
-	nmsleep(1000);
+	sleep(1);
 
 	applog(LOG_DEBUG, "Killing off mining threads");
 	/* Kill the mining threads*/
 	for (i = 0; i < mining_threads; i++) {
+		pthread_t *pth = NULL;
+		
 		thr = get_thread(i);
-		if (thr->cgpu->threads)
-			thr_info_cancel(thr);
+		if (!(thr && thr->cgpu->threads))
+			continue;
+		
+		applog(LOG_WARNING, "Killing %"PRIpreprv, thr->cgpu->proc_repr);
+		thr_info_cancel(thr);
+		pthread_join(thr->pth, NULL);
 	}
 
 	applog(LOG_DEBUG, "Killing off stage thread");
@@ -5193,7 +5253,7 @@ void write_config(FILE *fcfg)
 		fprintf(fcfg, ",\n\"socks-proxy\" : \"%s\"", json_escape(opt_socks_proxy));
 	
 	// We can only remove devices or disable them by default, but not both...
-	if (!(opt_removedisabled && devices_enabled))
+	if (!(opt_removedisabled && opt_devs_enabled))
 	{
 		// Don't need to remove any, so we can set defaults here
 		for (i = 0; i < total_devices; ++i)
@@ -5214,13 +5274,12 @@ void write_config(FILE *fcfg)
 			}
 	}
 	else
-	if (devices_enabled) {
+	if (opt_devs_enabled) {
 		// Mark original device params and remove-disabled
 		fprintf(fcfg, ",\n\"device\" : [");
 		bool first = true;
-		for (i = 0; i < (int)(sizeof(devices_enabled) * 8) - 1; ++i) {
-			if (devices_enabled & (1 << i))
-			{
+		for (i = 0; i < MAX_DEVICES; i++) {
+			if (devices_enabled[i]) {
 				fprintf(fcfg, "%s\n\t%d", first ? "" : ",", i);
 				first = false;
 			}
@@ -5428,6 +5487,7 @@ retry:
 	wlogprint("[A]dd pool [R]emove pool [D]isable pool [E]nable pool [P]rioritize pool\n");
 	wlogprint("[C]hange management strategy [S]witch pool [I]nformation\n");
 	wlogprint("Or press any other key to continue\n");
+	logwin_update();
 	input = getch();
 
 	if (!strncasecmp(&input, "a", 1)) {
@@ -5580,6 +5640,7 @@ retry:
 		summary_detail_level_str(),
 		opt_log_interval);
 	wlogprint("Select an option or any other key to return\n");
+	logwin_update();
 	input = getch();
 	if (!strncasecmp(&input, "q", 1)) {
 		opt_quiet ^= true;
@@ -5601,7 +5662,7 @@ retry:
 		devsummaryYOffset = 0;
 		want_per_device_stats = false;
 		wlogprint("Output mode reset to normal\n");
-		switch_compact();
+		switch_logsize();
 		goto retry;
 	} else if (!strncasecmp(&input, "d", 1)) {
 		opt_debug = true;
@@ -5624,7 +5685,7 @@ retry:
 			devsummaryYOffset = 0;
 		}
 		wlogprint("su[M]mary detail level changed to: %s\n", summary_detail_level_str());
-		switch_compact();
+		switch_logsize();
 		goto retry;
 	} else if (!strncasecmp(&input, "p", 1)) {
 		want_per_device_stats ^= true;
@@ -5697,6 +5758,7 @@ retry:
 		  "[W]rite config file\n[B]FGMiner restart\n",
 		opt_queue, opt_scantime, opt_expiry, opt_retries);
 	wlogprint("Select an option or any other key to return\n");
+	logwin_update();
 	input = getch();
 
 	if (!strncasecmp(&input, "q", 1)) {
@@ -5821,8 +5883,8 @@ static void *input_thread(void __maybe_unused *userdata)
 			++devsummaryYOffset;
 			if (curses_active_locked()) {
 				int i;
-				for (i = 0; i < mining_threads; i++)
-					curses_print_devstatus(i);
+				for (i = 0; i < total_devices; i++)
+					curses_print_devstatus(get_devices(i));
 				touchwin(statuswin);
 				wrefresh(statuswin);
 				unlock_curses();
@@ -6090,10 +6152,35 @@ fishy:
 	mutex_unlock(&sshare_lock);
 
 	if (!sshare) {
-		if (json_is_true(res_val))
+		double pool_diff;
+
+		/* Since the share is untracked, we can only guess at what the
+		 * work difficulty is based on the current pool diff. */
+		cg_rlock(&pool->data_lock);
+		pool_diff = pool->swork.diff;
+		cg_runlock(&pool->data_lock);
+
+		if (json_is_true(res_val)) {
 			applog(LOG_NOTICE, "Accepted untracked stratum share from pool %d", pool->pool_no);
-		else
+
+			/* We don't know what device this came from so we can't
+			 * attribute the work to the relevant cgpu */
+			mutex_lock(&stats_lock);
+			total_accepted++;
+			pool->accepted++;
+			total_diff_accepted += pool_diff;
+			pool->diff_accepted += pool_diff;
+			mutex_unlock(&stats_lock);
+		} else {
 			applog(LOG_NOTICE, "Rejected untracked stratum share from pool %d", pool->pool_no);
+
+			mutex_lock(&stats_lock);
+			total_rejected++;
+			pool->rejected++;
+			total_diff_rejected += pool_diff;
+			pool->diff_rejected += pool_diff;
+			mutex_unlock(&stats_lock);
+		}
 		goto out;
 	}
 	else {
@@ -6229,6 +6316,9 @@ static bool cnx_needed(struct pool *pool)
 {
 	struct pool *cp;
 
+	if (pool->enabled != POOL_ENABLED)
+		return false;
+
 	/* Balance strategies need all pools online */
 	if (pool_strategy == POOL_BALANCE)
 		return true;
@@ -6963,7 +7053,7 @@ void _submit_work_async(struct work *work)
 	notifier_wake(submit_waiting_notifier);
 }
 
-void submit_work_async(struct work *work_in, struct timeval *tv_work_found)
+static void submit_work_async(struct work *work_in, struct timeval *tv_work_found)
 {
 	struct work *work = copy_work(work_in);
 
@@ -7016,12 +7106,16 @@ enum test_nonce2_result _test_nonce2(struct work *work, uint32_t nonce, bool che
 	return hashtest2(work, checktarget);
 }
 
-void submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
+/* Returns true if nonce for work was a valid share */
+bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
 {
 	uint32_t *work_nonce = (uint32_t *)(work->data + 64 + 12);
 	uint32_t bak_nonce = *work_nonce;
 	struct timeval tv_work_found;
 	enum test_nonce2_result res;
+	bool ret = true;
+
+	thread_reportout(thr);
 
 	cgtime(&tv_work_found);
 	*work_nonce = htole32(nonce);
@@ -7042,6 +7136,7 @@ void submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
 			applog(LOG_WARNING, "%"PRIpreprv": invalid nonce - HW error",
 			       cgpu->proc_repr);
 			inc_hw_errors(thr);
+			ret = false;
 			goto out;
 		}
 	
@@ -7061,6 +7156,9 @@ void submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
 	submit_work_async(work, &tv_work_found);
 out:
 	*work_nonce = bak_nonce;
+	thread_reportin(thr);
+
+	return ret;
 }
 
 bool abandon_work(struct work *work, struct timeval *wdiff, uint64_t hashes)
@@ -7232,7 +7330,7 @@ void hash_queued_work(struct thr_info *mythr)
 	const int thr_id = mythr->id;
 	int64_t hashes_done = 0;
 
-	while (42) {
+	while (likely(!cgpu->shutdown)) {
 		struct timeval diff;
 		int64_t hashes;
 
@@ -7267,6 +7365,7 @@ void hash_queued_work(struct thr_info *mythr)
 				drv->flush_work(cgpu);
 		}
 	}
+	// cgpu->deven = DEV_DISABLED; set in miner_thread
 }
 
 void mt_disable_finish(struct thr_info *mythr)
@@ -7372,7 +7471,9 @@ static void wait_lpcurrent(struct pool *pool)
 	if (cnx_needed(pool))
 		return;
 
-	while (pool != current_pool() && pool_strategy != POOL_LOADBALANCE && pool_strategy != POOL_BALANCE) {
+	while (pool->enabled == POOL_DISABLED ||
+	       (pool != current_pool() && pool_strategy != POOL_LOADBALANCE &&
+	       pool_strategy != POOL_BALANCE)) {
 		mutex_lock(&lp_lock);
 		pthread_cond_wait(&lp_cond, &lp_lock);
 		mutex_unlock(&lp_lock);
@@ -7705,8 +7806,8 @@ static void *watchdog_thread(void __maybe_unused *userdata)
 		if (curses_active_locked()) {
 			change_logwinsize();
 			curses_print_status();
-			for (i = 0; i < mining_threads; i++)
-				curses_print_devstatus(i);
+			for (i = 0; i < total_devices; i++)
+				curses_print_devstatus(get_devices(i));
 			touchwin(statuswin);
 			wrefresh(statuswin);
 			touchwin(logwin);
@@ -8559,7 +8660,7 @@ int main(int argc, char *argv[])
 #endif
 
 #ifdef HAVE_CURSES
-	if (opt_realquiet || devices_enabled == -1)
+	if (opt_realquiet || opt_display_devs)
 		use_curses = false;
 
 	if (use_curses)
@@ -8650,11 +8751,6 @@ int main(int argc, char *argv[])
 	}
 #endif
 
-#ifdef USE_AVALON
-	if (!opt_scrypt)
-		avalon_drv.drv_detect();
-#endif
-
 #ifdef USE_BITFORCE
 	if (!opt_scrypt)
 		bitforce_drv.drv_detect();
@@ -8675,6 +8771,13 @@ int main(int argc, char *argv[])
 		ztex_drv.drv_detect();
 #endif
 
+	/* Detect avalon last since it will try to claim the device regardless
+	 * as detection is unreliable. */
+#ifdef USE_AVALON
+	if (!opt_scrypt)
+		avalon_drv.drv_detect();
+#endif
+
 #ifdef WANT_CPUMINE
 	cpu_drv.drv_detect();
 #endif
@@ -8687,7 +8790,7 @@ int main(int argc, char *argv[])
 		if (!devices[i]->devtype)
 			devices[i]->devtype = "PGA";
 
-	if (devices_enabled == -1) {
+	if (opt_display_devs) {
 		applog(LOG_ERR, "Devices detected:");
 		for (i = 0; i < total_devices; ++i) {
 			struct cgpu_info *cgpu = devices[i];
@@ -8700,9 +8803,9 @@ int main(int argc, char *argv[])
 	}
 
 	mining_threads = 0;
-	if (devices_enabled) {
-		for (i = 0; i < (int)(sizeof(devices_enabled) * 8) - 1; ++i) {
-			if (devices_enabled & (1 << i)) {
+	if (opt_devs_enabled) {
+		for (i = 0; i < MAX_DEVICES; i++) {
+			if (devices_enabled[i]) {
 				if (i >= total_devices)
 					quit (1, "Command line options set a device that doesn't exist");
 				register_device(devices[i]);
@@ -8738,7 +8841,7 @@ int main(int argc, char *argv[])
 		devices[i]->cgminer_stats.getwork_wait_min.tv_sec = MIN_SEC_UNSET;
 
 #ifdef HAVE_CURSES
-	change_summarywinsize();
+	switch_logsize();
 #endif
 
 	if (!total_pools) {

+ 7 - 3
miner.h

@@ -437,7 +437,7 @@ struct cgpu_info {
 	struct cgpu_info *next_proc;
 	
 	const char *device_path;
-	FILE *device_file;
+	void *device_data;
 	union {
 #ifdef USE_ZTEX
 		struct libztex_device *device_ztex;
@@ -465,7 +465,6 @@ struct cgpu_info {
 #if defined(USE_BITFORCE) || defined(USE_ICARUS)
 	bool flash_led;
 #endif
-	void *cgpu_data;
 	pthread_mutex_t		device_mutex;
 	pthread_cond_t	device_cond;
 
@@ -554,6 +553,8 @@ struct cgpu_info {
 	pthread_rwlock_t qlock;
 	struct work *queued_work;
 	unsigned int queued_count;
+
+	bool shutdown;
 };
 
 extern void renumber_cgpu(struct cgpu_info *);
@@ -921,12 +922,14 @@ extern void api(int thr_id);
 
 extern struct pool *current_pool(void);
 extern int enabled_pools;
+extern void get_intrange(char *arg, int *val1, int *val2);
 extern bool detect_stratum(struct pool *pool, char *url);
 extern void print_summary(void);
 extern struct pool *add_pool(void);
 extern bool add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass);
 
 #define MAX_GPUDEVICES 16
+#define MAX_DEVICES 4096
 
 #define MIN_INTENSITY -10
 #define _MIN_INTENSITY_STR "-10"
@@ -1243,7 +1246,7 @@ enum test_nonce2_result {
 extern enum test_nonce2_result _test_nonce2(struct work *, uint32_t nonce, bool checktarget);
 #define test_nonce(work, nonce, checktarget)  (_test_nonce2(work, nonce, checktarget) == TNR_GOOD)
 #define test_nonce2(work, nonce)  (_test_nonce2(work, nonce, true))
-extern void submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
+extern bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
 extern struct work *get_queued(struct cgpu_info *cgpu);
 extern struct work *__find_work_bymidstate(struct work *que, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen);
 extern struct work *find_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen);
@@ -1266,6 +1269,7 @@ extern void zero_stats(void);
 extern void default_save_file(char *filename);
 extern bool log_curses_only(int prio, const char *f, va_list ap) FORMAT_SYNTAX_CHECK(printf, 2, 0);
 extern void clear_logwin(void);
+extern void logwin_update(void);
 extern bool pool_tclear(struct pool *pool, bool *var);
 extern struct thread_q *tq_new(void);
 extern void tq_free(struct thread_q *tq);

+ 32 - 23
util.c

@@ -1004,6 +1004,13 @@ void sighandler_pthread_cancel(int sig)
 	do_pthread_cancel_exit(flags);
 }
 
+void pthread_testcancel(void)
+{
+	int flags = (int)pthread_getspecific(key_pcwm);
+	if (flags & PCWM_CANCELLED && !(flags & PCWM_DISABLED))
+		do_pthread_cancel_exit(flags);
+}
+
 int pthread_setcancelstate(int state, int *oldstate)
 {
 	int flags = (int)pthread_getspecific(key_pcwm);
@@ -1075,6 +1082,29 @@ void nmsleep(unsigned int msecs)
 #endif
 }
 
+/* Same for usecs */
+void nusleep(unsigned int usecs)
+{
+	struct timespec twait, tleft;
+	int ret;
+	ldiv_t d;
+
+#ifdef WIN32
+	timeBeginPeriod(1);
+#endif
+	d = ldiv(usecs, 1000000);
+	tleft.tv_sec = d.quot;
+	tleft.tv_nsec = d.rem * 1000;
+	do {
+		twait.tv_sec = tleft.tv_sec;
+		twait.tv_nsec = tleft.tv_nsec;
+		ret = nanosleep(&twait, &tleft);
+	} while (ret == -1 && errno == EINTR);
+#ifdef WIN32
+	timeEndPeriod(1);
+#endif
+}
+
 /* This is a cgminer gettimeofday wrapper. Since we always call gettimeofday
  * with tz set to NULL, and windows' default resolution is only 15ms, this
  * gives us higher resolution times on windows. */
@@ -1317,12 +1347,6 @@ static void recalloc_sock(struct pool *pool, size_t len)
 	pool->sockbuf_size = new;
 }
 
-enum recv_ret {
-	RECV_OK,
-	RECV_CLOSED,
-	RECV_RECVFAIL
-};
-
 /* Peeks at a socket to find the first end of line and then reads just that
  * from the socket and returns that as a malloced char */
 char *recv_line(struct pool *pool)
@@ -1331,7 +1355,6 @@ char *recv_line(struct pool *pool)
 	char *tok, *sret = NULL;
 
 	if (!strstr(pool->sockbuf, "\n")) {
-		enum recv_ret ret = RECV_OK;
 		struct timeval rstart, now;
 
 		cgtime(&rstart);
@@ -1340,7 +1363,6 @@ char *recv_line(struct pool *pool)
 			goto out;
 		}
 
-		mutex_lock(&pool->stratum_lock);
 		do {
 			char s[RBUFSIZE];
 			size_t slen;
@@ -1349,12 +1371,12 @@ char *recv_line(struct pool *pool)
 			memset(s, 0, RBUFSIZE);
 			n = recv(pool->sock, s, RECVSIZE, 0);
 			if (!n) {
-				ret = RECV_CLOSED;
+				applog(LOG_DEBUG, "Socket closed waiting in recv_line");
 				break;
 			}
 			if (n < 0) {
 				if (!sock_blocks() || !socket_full(pool, false)) {
-					ret = RECV_RECVFAIL;
+					applog(LOG_DEBUG, "Failed to recv sock in recv_line");
 					break;
 				}
 			} else {
@@ -1364,19 +1386,6 @@ char *recv_line(struct pool *pool)
 			}
 			cgtime(&now);
 		} while (tdiff(&now, &rstart) < 60 && !strstr(pool->sockbuf, "\n"));
-		mutex_unlock(&pool->stratum_lock);
-
-		switch (ret) {
-			default:
-			case RECV_OK:
-				break;
-			case RECV_CLOSED:
-				applog(LOG_DEBUG, "Socket closed waiting in recv_line");
-				goto out;
-			case RECV_RECVFAIL:
-				applog(LOG_DEBUG, "Failed to recv sock in recv_line");
-				goto out;
-		}
 	}
 
 	buflen = strlen(pool->sockbuf);

+ 1 - 0
util.h

@@ -88,6 +88,7 @@ int thr_info_create(struct thr_info *thr, pthread_attr_t *attr, void *(*start) (
 void thr_info_freeze(struct thr_info *thr);
 void thr_info_cancel(struct thr_info *thr);
 void nmsleep(unsigned int msecs);
+void nusleep(unsigned int usecs);
 void cgtime(struct timeval *tv);
 void subtime(struct timeval *a, struct timeval *b);
 void addtime(struct timeval *a, struct timeval *b);