Browse Source

Merge branch 'icarus_ms' into bfgminer

Luke Dashjr 11 years ago
parent
commit
7c069fe5ac
9 changed files with 240 additions and 139 deletions
  1. 61 5
      driver-antminer.c
  2. 4 5
      driver-cairnsmore.c
  3. 5 5
      driver-dualminer.c
  4. 146 105
      driver-icarus.c
  5. 5 10
      driver-icarus.h
  6. 3 3
      driver-zeusminer.c
  7. 4 4
      lowl-vcom.c
  8. 2 1
      lowl-vcom.h
  9. 10 1
      util.h

+ 61 - 5
driver-antminer.c

@@ -27,6 +27,7 @@
 #include "util.h"
 
 #define ANTMINER_IO_SPEED 115200
+// ANTMINER_HASH_TIME is for U1/U2 only
 #define ANTMINER_HASH_TIME 0.0000000004761
 
 #define ANTMINER_STATUS_LEN 5
@@ -52,8 +53,10 @@ bool antminer_detect_one(const char *devpath)
 	*info = (struct ICARUS_INFO){
 		.baud = ANTMINER_IO_SPEED,
 		.Hs = ANTMINER_HASH_TIME,
-		.timing_mode = MODE_DEFAULT,
+		.timing_mode = MODE_LONG,
+		.do_icarus_timing = true,
 		.read_size = 5,
+		.reopen_mode = IRM_NEVER,
 	};
 	
 	struct cgpu_info * const dev = icarus_detect_custom(devpath, drv, info);
@@ -64,7 +67,7 @@ bool antminer_detect_one(const char *devpath)
 	}
 	
 	dev->set_device_funcs = antminer_set_device_funcs;
-	info->read_count = 15;
+	info->read_timeout_ms = 75;
 	
 	return true;
 }
@@ -75,6 +78,8 @@ bool antminer_lowl_probe(const struct lowlevel_device_info * const info)
 	return vcom_lowl_probe_wrapper(info, antminer_detect_one);
 }
 
+// Not used for anything, and needs to read a result for every chip
+#if 0
 static
 char *antminer_get_clock(struct cgpu_info *cgpu, char *replybuf)
 {
@@ -82,6 +87,7 @@ char *antminer_get_clock(struct cgpu_info *cgpu, char *replybuf)
 	unsigned char rebuf[ANTMINER_STATUS_LEN] = {0};
 	
 	struct timeval tv_now;
+	struct timeval tv_timeout, tv_finish;
 	
 	rdreg_buf[0] = 4;
 	rdreg_buf[0] |= 0x80;
@@ -103,7 +109,8 @@ char *antminer_get_clock(struct cgpu_info *cgpu, char *replybuf)
 	applog(LOG_DEBUG, "%"PRIpreprv": Get clock: OK", cgpu->proc_repr);
 	
 	memset(rebuf, 0, sizeof(rebuf));
-	err = icarus_gets(cgpu->proc_repr, rebuf, cgpu->device_fd, &tv_now, NULL, 10, ANTMINER_STATUS_LEN);
+	timer_set_delay(&tv_timeout, &tv_now, 1000000);
+	err = icarus_read(cgpu->proc_repr, rebuf, cgpu->device_fd, &tv_finish, NULL, &tv_timeout, &tv_now, ANTMINER_STATUS_LEN);
 	
 	// Timeout is ok - checking specifically for an error here
 	if (err == ICA_GETS_ERROR)
@@ -116,6 +123,7 @@ char *antminer_get_clock(struct cgpu_info *cgpu, char *replybuf)
 	
 	return NULL;
 }
+#endif
 
 static
 const char *antminer_set_clock(struct cgpu_info * const cgpu, const char * const optname, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const out_success)
@@ -165,8 +173,55 @@ const char *antminer_set_clock(struct cgpu_info * const cgpu, const char * const
 	
 	// This is confirmed required in order for the clock change to "take"
 	cgsleep_ms(500);
-		
-	return antminer_get_clock(cgpu, replybuf);
+	
+	return NULL;
+}
+
+static
+const char *antminer_set_voltage(struct cgpu_info * const proc, const char * const optname, const char * const newvalue, char * const replybuf, enum bfg_set_device_replytype * const out_success)
+{
+	if (!(newvalue && *newvalue))
+		return "Missing voltage value";
+	
+	// For now we only allow hex values that use BITMAINtech's lookup table
+	// This means values should be prefixed with an x so that later we can
+	// accept and distinguish decimal values
+	if (newvalue[0] != 'x' || strlen(newvalue) != 4)
+invalid_voltage:
+		return "Only raw voltage configurations are currently supported using 'x' followed by 3 hexadecimal digits";
+	
+	char voltagecfg_hex[5];
+	voltagecfg_hex[0] = '0';
+	memcpy(&voltagecfg_hex[1], &newvalue[1], 3);
+	voltagecfg_hex[4] = '\0';
+	
+	uint8_t cmd[4];
+	if (!hex2bin(&cmd[1], voltagecfg_hex, 2))
+		goto invalid_voltage;
+	cmd[0] = 0xaa;
+	cmd[1] |= 0xb0;
+	cmd[3] = 0;
+	cmd[3] = crc5usb(cmd, (4 * 8) - 5);
+	cmd[3] |= 0xc0;
+	
+	if (opt_debug)
+	{
+		char hex[(4 * 2) + 1];
+		bin2hex(hex, cmd, 4);
+		applog(LOG_DEBUG, "%"PRIpreprv": Set voltage: %s", proc->proc_repr, hex);
+	}
+	
+	const int err = icarus_write(proc->proc_repr, proc->device_fd, cmd, sizeof(cmd));
+	
+	if (err)
+	{
+		sprintf(replybuf, "Error sending set voltage (err=%d)", err);
+		return replybuf;
+	}
+	
+	applog(LOG_DEBUG, "%"PRIpreprv": Set voltage: OK", proc->proc_repr);
+	
+	return NULL;
 }
 
 static
@@ -205,6 +260,7 @@ const struct bfg_set_device_definition antminer_set_device_funcs[] = {
 	{"reopen"       , icarus_set_reopen       , "how often to reopen device: never, timeout, cycle, (or now for a one-shot reopen)"},
 	{"timing"       , icarus_set_timing       , "timing of device; see README.FPGA"},
 	{"clock", antminer_set_clock, "clock frequency"},
+	{"voltage", antminer_set_voltage, "voltage ('x' followed by 3 digit hex code)"},
 	{NULL},
 };
 

+ 4 - 5
driver-cairnsmore.c

@@ -87,12 +87,11 @@ bool cairnsmore_supports_dynclock(const char * const repr, const int fd)
 
 	uint32_t nonce = 0;
 	{
+		struct timeval tv_now, tv_timeout;
 		struct timeval tv_finish;
-		struct thr_info dummy = {
-			.work_restart = false,
-			.work_restart_notifier = {-1, -1},
-		};
-		icarus_gets(repr, (unsigned char*)&nonce, fd, &tv_finish, &dummy, 1, ICARUS_DEFAULT_READ_SIZE);
+		timer_set_now(&tv_now);
+		timer_set_delay(&tv_timeout, &tv_now, 100000);
+		icarus_read(repr, (uint8_t *)&nonce, fd, &tv_finish, NULL, &tv_timeout, &tv_now, ICARUS_DEFAULT_READ_SIZE);
 	}
 	applog(LOG_DEBUG, "Cairnsmore dynclock detection... Got %08x", nonce);
 	switch (nonce) {

+ 5 - 5
driver-dualminer.c

@@ -1,5 +1,5 @@
 /*
- * Copyright 2013-2014 Luke Dashjr
+ * Copyright 2013-2015 Luke Dashjr
  * Copyright 2014 Nate Woolls
  * Copyright 2014 Dualminer Team
  *
@@ -39,8 +39,8 @@
 #define DUALMINER_SCRYPT_DM_HASH_TIME	0.00003333333333
 #define DUALMINER_SHA2_DM_HASH_TIME     0.00000000300000
 
-#define DUALMINER_SCRYPT_READ_COUNT 48  // 4.8s to read
-#define DUALMINER_SHA2_READ_COUNT	16  // 1.6s to read
+#define DUALMINER_SCRYPT_READ_TIMEOUT_MS 4800  // 4.8s to read
+#define DUALMINER_SHA2_READ_TIMEOUT_MS   1600  // 1.6s to read
 
 #define DUALMINER_0_9V_SHA2_UNITS  60
 #define DUALMINER_1_2V_SHA2_UNITS   0
@@ -263,9 +263,9 @@ bool dualminer_detect_one(const char *devpath)
 	}
 
 	if (dualminer_is_scrypt(info))
-		info->read_count = DUALMINER_SCRYPT_READ_COUNT; // 4.8s to read
+		info->read_timeout_ms = DUALMINER_SCRYPT_READ_TIMEOUT_MS; // 4.8s to read
 	else
-		info->read_count = DUALMINER_SHA2_READ_COUNT; // 1.6s to read
+		info->read_timeout_ms = DUALMINER_SHA2_READ_TIMEOUT_MS; // 1.6s to read
 
 	return true;
 }

+ 146 - 105
driver-icarus.c

@@ -84,8 +84,7 @@ ASSERT1(sizeof(uint32_t) == 4);
 #define ICARUS_READ_COUNT_LIMIT_MAX 100
 
 // In timing mode: Default starting value until an estimate can be obtained
-// 5 seconds allows for up to a ~840MH/s device
-#define ICARUS_READ_COUNT_TIMING	(5 * TIME_FACTOR)
+#define ICARUS_READ_COUNT_TIMING_MS  75
 
 // For a standard Icarus REV3
 #define ICARUS_REV3_HASH_TIME 0.00000000264083
@@ -130,10 +129,6 @@ ASSERT1(sizeof(uint32_t) == 4);
 // The value above used is doubled each history until it exceeds:
 #define MAX_MIN_DATA_COUNT 100
 
-#if (TIME_FACTOR != 10)
-#error TIME_FACTOR must be 10
-#endif
-
 static struct timeval history_sec = { HISTORY_SEC, 0 };
 
 static const char *MODE_DEFAULT_STR = "default";
@@ -170,102 +165,126 @@ void icarus_log_protocol(const char * const repr, const void *buf, size_t bufLen
 	applog(LOG_DEBUG, "%"PRIpreprv": DEVPROTO: %s %s", repr, prefix, hex);
 }
 
-int icarus_gets(const char * const repr, unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count, int read_size)
+int icarus_read(const char * const repr, uint8_t *buf, const int fd, struct timeval * const tvp_finish, struct thr_info * const thr, const struct timeval * const tvp_timeout, struct timeval * const tvp_now, int read_size)
 {
-	ssize_t ret = 0;
-	int rc = 0;
-	int epollfd = -1;
-	int epoll_timeout = ICARUS_READ_FAULT_DECISECONDS * 100;
-	int read_amount = read_size;
+	int rv;
+	long remaining_ms;
+	ssize_t ret;
+	struct timeval tv_start = *tvp_now;
 	bool first = true;
-
+	// If there is no thr, then there's no work restart to watch..
+	
 #ifdef HAVE_EPOLL
-	struct epoll_event ev = {
-		.events = EPOLLIN,
-		.data.fd = fd,
-	};
+	bool watching_work_restart = !thr;
+	int epollfd;
 	struct epoll_event evr[2];
-	if (thr && thr->work_restart_notifier[1] != -1) {
+	
 	epollfd = epoll_create(2);
 	if (epollfd != -1) {
+		struct epoll_event ev = {
+			.events = EPOLLIN,
+			.data.fd = fd,
+		};
 		if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev)) {
+			applog(LOG_DEBUG, "%"PRIpreprv": Error adding %s fd to epoll", "device", repr);
 			close(epollfd);
 			epollfd = -1;
 		}
+		else
+		if (thr && thr->work_restart_notifier[1] != -1)
 		{
 			ev.data.fd = thr->work_restart_notifier[0];
 			if (-1 == epoll_ctl(epollfd, EPOLL_CTL_ADD, thr->work_restart_notifier[0], &ev))
-				applog(LOG_ERR, "%"PRIpreprv": Error adding work restart fd to epoll", repr);
+				applog(LOG_DEBUG, "%"PRIpreprv": Error adding %s fd to epoll", "work restart", repr);
 			else
-			{
-				epoll_timeout *= read_count;
-				read_count = 1;
-			}
+				watching_work_restart = true;
 		}
 	}
 	else
-		applog(LOG_ERR, "%"PRIpreprv": Error creating epoll", repr);
-	}
+		applog(LOG_DEBUG, "%"PRIpreprv": Error creating epoll", repr);
+	
+	if (epollfd == -1 && (remaining_ms = timer_remaining_us(tvp_timeout, tvp_now)) < 100000)
+		applog(LOG_WARNING, "%"PRIpreprv": Failed to use epoll, and very short read timeout (%ldms)", repr, remaining_ms);
 #endif
-
-	// Read reply 1 byte at a time to get earliest tv_finish
+	
 	while (true) {
+		remaining_ms = timer_remaining_us(tvp_timeout, tvp_now) / 1000;
 #ifdef HAVE_EPOLL
-		if (epollfd != -1 && (ret = epoll_wait(epollfd, evr, 2, epoll_timeout)) != -1)
+		if (epollfd != -1)
 		{
-			if (ret == 1 && evr[0].data.fd == fd)
-				ret = read(fd, buf, 1);
-			else
+			if ((!watching_work_restart) && remaining_ms > 100)
+				remaining_ms = 100;
+			ret = epoll_wait(epollfd, evr, 2, remaining_ms);
+			timer_set_now(tvp_now);
+			switch (ret)
 			{
-				if (ret)
-					notifier_read(thr->work_restart_notifier);
-				ret = 0;
+				case -1:
+					if (unlikely(errno != EINTR))
+						return_via(out, rv = ICA_GETS_ERROR);
+					ret = 0;
+					break;
+				case 0:  // timeout
+					// handled after switch
+					break;
+				case 1:
+					if (evr[0].data.fd != fd)  // must be work restart notifier
+					{
+						notifier_read(thr->work_restart_notifier);
+						ret = 0;
+						break;
+					}
+					// fallthru to...
+				case 2:  // device has data
+					ret = read(fd, buf, read_size);
+					break;
+				default:
+					return_via(out, rv = ICA_GETS_ERROR);
 			}
 		}
 		else
 #endif
-		ret = read(fd, buf, 1);
-		if (ret < 0)
-			return ICA_GETS_ERROR;
-
+		{
+			if (remaining_ms > 100)
+				remaining_ms = 100;
+			vcom_set_timeout_ms(fd, remaining_ms);
+			// Read first byte alone to get earliest tv_finish
+			ret = read(fd, buf, first ? 1 : read_size);
+			timer_set_now(tvp_now);
+		}
 		if (first)
-			cgtime(tv_finish);
-
-		if (ret >= read_amount)
+			*tvp_finish = *tvp_now;
+		if (ret)
 		{
-			if (epollfd != -1)
-				close(epollfd);
-
+			if (unlikely(ret < 0))
+				return_via(out, rv = ICA_GETS_ERROR);
+			
+			first = false;
+			
 			if (opt_dev_protocol && opt_debug)
-				icarus_log_protocol(repr, buf, read_size, "RECV");
-
-			return ICA_GETS_OK;
-		}
-
-		if (ret > 0) {
+				icarus_log_protocol(repr, buf, ret, "RECV");
+			
+			if (ret >= read_size)
+				return_via(out, rv = ICA_GETS_OK);
+			
+			read_size -= ret;
 			buf += ret;
-			read_amount -= ret;
-			first = false;
+			// Always continue reading while data is coming in, ignoring the timeout
 			continue;
 		}
-			
-		if (thr && thr->work_restart) {
-			if (epollfd != -1)
-				close(epollfd);
-			applog(LOG_DEBUG, "%"PRIpreprv": Interrupted by work restart", repr);
-			return ICA_GETS_RESTART;
-		}
-
-		rc++;
-		if (rc >= read_count) {
-			if (epollfd != -1)
-				close(epollfd);
-			applog(LOG_DEBUG, "%"PRIpreprv": No data in %.2f seconds",
-			       repr,
-			       (float)rc * epoll_timeout / 1000.);
-			return ICA_GETS_TIMEOUT;
-		}
+		
+		if (thr && thr->work_restart)
+			return_via_applog(out, rv = ICA_GETS_RESTART, LOG_DEBUG, "%"PRIpreprv": Interrupted by work restart", repr);
+		
+		if (timer_passed(tvp_timeout, tvp_now))
+			return_via_applog(out, rv = ICA_GETS_TIMEOUT, LOG_DEBUG, "%"PRIpreprv": No data in %.3f seconds", repr, timer_elapsed_us(&tv_start, tvp_now) / 1e6);
 	}
+
+out:
+#ifdef HAVE_EPOLL
+	if (epollfd != -1)
+		close(epollfd);
+#endif
+	return rv;
 }
 
 int icarus_write(const char * const repr, int fd, const void *buf, size_t bufLen)
@@ -321,14 +340,14 @@ const char *_icarus_set_timing(struct ICARUS_INFO * const info, const char * con
 
 	if (strcasecmp(buf, MODE_SHORT_STR) == 0) {
 		// short
-		info->read_count = ICARUS_READ_COUNT_TIMING;
+		info->read_timeout_ms = ICARUS_READ_COUNT_TIMING_MS;
 		info->read_count_limit = 0;  // 0 = no limit
 
 		info->timing_mode = MODE_SHORT;
 		info->do_icarus_timing = true;
 	} else if (strncasecmp(buf, MODE_SHORT_STREQ, strlen(MODE_SHORT_STREQ)) == 0) {
 		// short=limit
-		info->read_count = ICARUS_READ_COUNT_TIMING;
+		info->read_timeout_ms = ICARUS_READ_COUNT_TIMING_MS;
 
 		info->timing_mode = MODE_SHORT;
 		info->do_icarus_timing = true;
@@ -340,14 +359,14 @@ const char *_icarus_set_timing(struct ICARUS_INFO * const info, const char * con
 			info->read_count_limit = ICARUS_READ_COUNT_LIMIT_MAX;
 	} else if (strcasecmp(buf, MODE_LONG_STR) == 0) {
 		// long
-		info->read_count = ICARUS_READ_COUNT_TIMING;
+		info->read_timeout_ms = ICARUS_READ_COUNT_TIMING_MS;
 		info->read_count_limit = 0;  // 0 = no limit
 
 		info->timing_mode = MODE_LONG;
 		info->do_icarus_timing = true;
 	} else if (strncasecmp(buf, MODE_LONG_STREQ, strlen(MODE_LONG_STREQ)) == 0) {
 		// long=limit
-		info->read_count = ICARUS_READ_COUNT_TIMING;
+		info->read_timeout_ms = ICARUS_READ_COUNT_TIMING_MS;
 
 		info->timing_mode = MODE_LONG;
 		info->do_icarus_timing = true;
@@ -362,15 +381,18 @@ const char *_icarus_set_timing(struct ICARUS_INFO * const info, const char * con
 		info->Hs = Hs / NANOSEC;
 		info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
 
-		info->read_count = 0;
+		info->read_timeout_ms = 0;
 		if ((eq = strchr(buf, '=')) != NULL)
-			info->read_count = atoi(eq+1);
+			info->read_timeout_ms = atof(&eq[1]) * 100;
 
-		if (info->read_count < 1)
-			info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
-
-		if (unlikely(info->read_count < 1))
-			info->read_count = 1;
+		if (info->read_timeout_ms < 1)
+		{
+			info->read_timeout_ms = info->fullnonce * 1000;
+			if (unlikely(info->read_timeout_ms < 2))
+				info->read_timeout_ms = 1;
+			else
+				--info->read_timeout_ms;
+		}
 
 		info->read_count_limit = 0;  // 0 = no limit
 		
@@ -381,33 +403,35 @@ const char *_icarus_set_timing(struct ICARUS_INFO * const info, const char * con
 
 		info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
 
-		info->read_count = 0;
+		info->read_timeout_ms = 0;
 		if ((eq = strchr(buf, '=')) != NULL)
-			info->read_count = atoi(eq+1);
+			info->read_timeout_ms = atof(&eq[1]) * 100;
 
-		int def_read_count = ICARUS_READ_COUNT_TIMING;
+		unsigned def_read_timeout_ms = ICARUS_READ_COUNT_TIMING_MS;
 
 		if (info->timing_mode == MODE_DEFAULT) {
 			if (drv == &icarus_drv) {
 				info->do_default_detection = 0x10;
 			} else {
-				def_read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+				def_read_timeout_ms = info->fullnonce * 1000;
+				if (def_read_timeout_ms > 0)
+					--def_read_timeout_ms;
 			}
 
 			info->do_icarus_timing = false;
 		}
-		if (info->read_count < 1)
-			info->read_count = def_read_count;
+		if (info->read_timeout_ms < 1)
+			info->read_timeout_ms = def_read_timeout_ms;
 		
 		info->read_count_limit = 0;  // 0 = no limit
 	}
 
 	info->min_data_count = MIN_DATA_COUNT;
 
-	applog(LOG_DEBUG, "%"PRIpreprv": Init: mode=%s read_count=%d limit=%dms Hs=%e",
+	applog(LOG_DEBUG, "%"PRIpreprv": Init: mode=%s read_timeout_ms=%u limit=%dms Hs=%e",
 		repr,
 		timing_mode_str(info->timing_mode),
-		info->read_count, info->read_count_limit, info->Hs);
+		info->read_timeout_ms, info->read_count_limit, info->Hs);
 	
 	return NULL;
 }
@@ -445,6 +469,7 @@ int icarus_excess_nonce_size(int fd, struct ICARUS_INFO *info)
 
 int icarus_probe_work_division(const int fd, const char * const repr, struct ICARUS_INFO * const info)
 {
+	struct timeval tv_now, tv_timeout;
 	struct timeval tv_finish;
 	
 	// For reading the nonce from Icarus
@@ -459,12 +484,14 @@ int icarus_probe_work_division(const int fd, const char * const repr, struct ICA
 	unsigned char pkt[64] =
 		"\x2e\x4c\x8f\x91\xfd\x59\x5d\x2d\x7e\xa2\x0a\xaa\xcb\x64\xa2\xa0"
 		"\x43\x82\x86\x02\x77\xcf\x26\xb6\xa1\xee\x04\xc5\x6a\x5b\x50\x4a"
-		"BFGMiner Probe\0\0"
+		"WDiv\0\0\0\0BFGMiner"
 		"BFG\0\x64\x61\x01\x1a\xc9\x06\xa9\x51\xfb\x9b\x3c\x73";
 	
 	icarus_write(repr, fd, pkt, sizeof(pkt));
 	memset(res_bin, 0, sizeof(res_bin));
-	if (ICA_GETS_OK == icarus_gets(repr, res_bin, fd, &tv_finish, NULL, info->read_count, info->read_size))
+	timer_set_now(&tv_now);
+	timer_set_delay(&tv_timeout, &tv_now, info->read_timeout_ms * 1000);
+	if (ICA_GETS_OK == icarus_read(repr, res_bin, fd, &tv_finish, NULL, &tv_timeout, &tv_now, info->read_size))
 	{
 		memcpy(&res, res_bin, sizeof(res));
 		res = icarus_nonce32toh(info, res);
@@ -559,7 +586,10 @@ struct cgpu_info *icarus_detect_custom(const char *devpath, struct device_drv *a
 		// Do not use info->read_size here, instead read exactly ICARUS_NONCE_SIZE
 		// We will then compare the bytes left in fd with info->read_size to determine
 		// if this is a valid device
-		icarus_gets(devpath, nonce_bin, fd, &tv_finish, NULL, info->probe_read_count, ICARUS_NONCE_SIZE);
+		struct timeval tv_now, tv_timeout;
+		timer_set_now(&tv_now);
+		timer_set_delay(&tv_timeout, &tv_now, info->probe_read_count * 100000);
+		icarus_read(devpath, nonce_bin, fd, &tv_finish, NULL, &tv_timeout, &tv_now, ICARUS_NONCE_SIZE);
 		
 		// How many bytes were left after reading the above nonce
 		int bytes_left = icarus_excess_nonce_size(fd, info);
@@ -821,6 +851,7 @@ void handle_identify(struct thr_info * const thr, int ret, const bool was_first_
 	struct icarus_state * const state = thr->cgpu_data;
 	int fd = icarus->device_fd;
 	struct timeval tv_now;
+	struct timeval tv_timeout, tv_finish;
 	double delapsed;
 	
 	// For reading the nonce from Icarus
@@ -847,7 +878,8 @@ void handle_identify(struct thr_info * const thr, int ret, const bool was_first_
 			
 			// Try to get more nonces (ignoring work restart)
 			memset(nonce_bin, 0, sizeof(nonce_bin));
-			ret = icarus_gets(icarus->proc_repr, nonce_bin, fd, &tv_now, NULL, (info->fullnonce - delapsed) * 10, info->read_size);
+			timer_set_delay(&tv_timeout, &tv_now, (uint64_t)(info->fullnonce - delapsed) * 1000000);
+			ret = icarus_read(icarus->proc_repr, nonce_bin, fd, &tv_finish, NULL, &tv_timeout, &tv_now, info->read_size);
 			if (ret == ICA_GETS_OK)
 			{
 				memcpy(&nonce, nonce_bin, sizeof(nonce));
@@ -904,6 +936,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	int64_t hash_count;
 	struct timeval tv_start = {.tv_sec=0}, elapsed;
 	struct timeval tv_history_start, tv_history_finish;
+	struct timeval tv_now, tv_timeout;
 	double Ti, Xi;
 	int i;
 	bool was_hw_error = false;
@@ -912,7 +945,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	struct ICARUS_HISTORY *history0, *history;
 	int count;
 	double Hs, W, fullnonce;
-	int read_count;
+	int read_timeout_ms;
 	bool limited;
 	uint32_t values;
 	int64_t hash_count_range;
@@ -945,11 +978,13 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		}
 		else
 		{
-			read_count = info->read_count;
+			read_timeout_ms = info->read_timeout_ms;
 keepwaiting:
 			/* Icarus will return info->read_size bytes nonces or nothing */
 			memset(nonce_bin, 0, sizeof(nonce_bin));
-			ret = icarus_gets(icarus->proc_repr, nonce_bin, fd, &state->tv_workfinish, thr, read_count, info->read_size);
+			timer_set_now(&tv_now);
+			timer_set_delay(&tv_timeout, &tv_now, read_timeout_ms * 1000);
+			ret = icarus_read(icarus->proc_repr, nonce_bin, fd, &state->tv_workfinish, thr, &tv_timeout, &tv_now, info->read_size);
 			switch (ret) {
 				case ICA_GETS_RESTART:
 					// The prepared work is invalid, and the current work is abandoned
@@ -1002,8 +1037,8 @@ keepwaiting:
 			}
 			if (info->continue_search)
 			{
-				read_count = info->read_count - ((timer_elapsed_us(&state->tv_workstart, NULL) / (1000000 / TIME_FACTOR)) + 1);
-				if (read_count)
+				read_timeout_ms = info->read_timeout_ms - ((timer_elapsed_us(&state->tv_workstart, NULL) / 1000) + 1);
+				if (read_timeout_ms)
 				{
 					submit_nonce(icarus_thread_for_nonce(icarus, nonce), nonce_work, nonce);
 					goto keepwaiting;
@@ -1126,7 +1161,9 @@ keepwaiting:
 			// Real Icarus?
 			if (!info->do_default_detection) {
 				applog(LOG_DEBUG, "%"PRIpreprv": Seems to be a real Icarus", icarus->proc_repr);
-				info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+				info->read_timeout_ms = info->fullnonce * 1000;
+				if (info->read_timeout_ms > 0)
+					--info->read_timeout_ms;
 			}
 		}
 		else
@@ -1215,15 +1252,17 @@ keepwaiting:
 			memset(history0, 0, sizeof(struct ICARUS_HISTORY));
 
 			fullnonce = W + Hs * (((double)0xffffffff) + 1);
-			read_count = (int)(fullnonce * TIME_FACTOR) - 1;
-			if (info->read_count_limit > 0 && read_count > info->read_count_limit) {
-				read_count = info->read_count_limit;
+			read_timeout_ms = fullnonce * 1000;
+			if (read_timeout_ms > 0)
+				--read_timeout_ms;
+			if (info->read_count_limit > 0 && read_timeout_ms > info->read_count_limit * 100) {
+				read_timeout_ms = info->read_count_limit * 100;
 				limited = true;
 			} else
 				limited = false;
 
 			info->Hs = Hs;
-			info->read_count = read_count;
+			info->read_timeout_ms = read_timeout_ms;
 
 			info->fullnonce = fullnonce;
 			info->count = count;
@@ -1237,9 +1276,9 @@ keepwaiting:
 				info->do_icarus_timing = false;
 
 //			applog(LOG_DEBUG, "%"PRIpreprv" Re-estimate: read_count=%d%s fullnonce=%fs history count=%d Hs=%e W=%e values=%d hash range=0x%08lx min data count=%u", icarus->proc_repr, read_count, limited ? " (limited)" : "", fullnonce, count, Hs, W, values, hash_count_range, info->min_data_count);
-			applog(LOG_DEBUG, "%"PRIpreprv" Re-estimate: Hs=%e W=%e read_count=%d%s fullnonce=%.3fs",
+			applog(LOG_DEBUG, "%"PRIpreprv" Re-estimate: Hs=%e W=%e read_timeout_ms=%u%s fullnonce=%.3fs",
 					icarus->proc_repr,
-					Hs, W, read_count,
+					Hs, W, read_timeout_ms,
 					limited ? " (limited)" : "", fullnonce);
 		}
 		info->history_count++;
@@ -1278,7 +1317,9 @@ static struct api_data *icarus_drv_stats(struct cgpu_info *cgpu)
 	// care since hashing performance is way more important than
 	// locking access to displaying API debug 'stats'
 	// If locking becomes an issue for any of them, use copy_data=true also
-	root = api_add_int(root, "read_count", &(info->read_count), false);
+	const unsigned read_count_ds = info->read_timeout_ms / 100;
+	root = api_add_uint(root, "read_count", &read_count_ds, true);
+	root = api_add_uint(root, "read_timeout_ms", &(info->read_timeout_ms), false);
 	root = api_add_int(root, "read_count_limit", &(info->read_count_limit), false);
 	root = api_add_double(root, "fullnonce", &(info->fullnonce), false);
 	root = api_add_int(root, "count", &(info->count), false);

+ 5 - 10
driver-icarus.h

@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-2014 Luke Dashjr
+ * Copyright 2012-2015 Luke Dashjr
  * Copyright 2014 Nate Woolls
  * Copyright 2012 Xiangfu
  * Copyright 2012 Andrew Smith
@@ -21,11 +21,6 @@
 #include "dynclock.h"
 #include "miner.h"
 
-// Fraction of a second, USB timeout is measured in
-// i.e. 10 means 1/10 of a second
-// Right now, it MUST be 10 due to other assumptions.
-#define TIME_FACTOR 10
-// It's 10 per second, thus value = 10/TIME_FACTOR =
 #define ICARUS_READ_FAULT_DECISECONDS 1
 
 #define NANOSEC 1000000000.0
@@ -77,8 +72,8 @@ struct ICARUS_INFO {
 	struct ICARUS_HISTORY history[INFO_HISTORY+1];
 	uint32_t min_data_count;
 
-	// Timeout scanning for a nonce (deciseconds)
-	int read_count;
+	// Timeout scanning for a nonce
+	unsigned read_timeout_ms;
 	// Timeout scanning for a golden nonce (deciseconds)
 	int probe_read_count;
 	
@@ -162,8 +157,8 @@ struct icarus_state {
 };
 
 extern struct cgpu_info *icarus_detect_custom(const char *devpath, struct device_drv *, struct ICARUS_INFO *);
-extern int icarus_gets(const char *repr, unsigned char *, int fd, struct timeval *tv_finish, struct thr_info *, int read_count, int read_size);
-extern int icarus_write(const char *repr, int fd, const void *buf, size_t bufLen);
+extern int icarus_read(const char *repr, uint8_t *buf, int fd, struct timeval *tvp_finish, struct thr_info *, const struct timeval *tvp_timeout, struct timeval *tvp_now, int read_size);
+extern int icarus_write(const char * const repr, int fd, const void *buf, size_t bufLen);
 extern bool icarus_init(struct thr_info *);
 extern void do_icarus_close(struct thr_info *thr);
 extern bool icarus_job_start(struct thr_info *);

+ 3 - 3
driver-zeusminer.c

@@ -1,7 +1,7 @@
 /*
  * Copyright 2014 Nate Woolls
  * Copyright 2014 ZeusMiner Team
- * Copyright 2014 Luke Dashjr
+ * Copyright 2014-2015 Luke Dashjr
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -133,8 +133,8 @@ bool zeusminer_detect_one(const char *devpath)
 	//golden_speed_per_core is the number of hashes / second / core
 	uint64_t golden_speed_per_core = (uint64_t)(hash_count / duration_sec);
 	//don't combine the following two lines - overflows leaving info->read_count at 0
-	info->read_count = (uint32_t)((4294967296 * 10) / (ZEUSMINER_CHIP_CORES * chips_count_max * golden_speed_per_core * 2));
-	info->read_count = info->read_count * 3 / 4;
+	info->read_timeout_ms = ((uint64_t)(0x100000000 * 1000)) / (ZEUSMINER_CHIP_CORES * chips_count_max * golden_speed_per_core * 2);
+	info->read_timeout_ms = info->read_timeout_ms * 3 / 4;
 	
 	return true;
 }

+ 4 - 4
lowl-vcom.c

@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-2014 Luke Dashjr
+ * Copyright 2012-2015 Luke Dashjr
  * Copyright 2013 Con Kolivas
  * Copyright 2012 Andrew Smith
  * Copyright 2013 Xiangfu
@@ -1056,19 +1056,19 @@ bool valid_baud(int baud)
 	}
 }
 
-bool vcom_set_timeout(const int fdDev, const uint8_t timeout)
+bool vcom_set_timeout_ms(const int fdDev, const unsigned timeout_ms)
 {
 #ifdef WIN32
 	const HANDLE hSerial = (HANDLE)_get_osfhandle(fdDev);
 	// Code must specify a valid timeout value (0 means don't timeout)
-	const DWORD ctoms = ((DWORD)timeout * 100);
+	const DWORD ctoms = timeout_ms;
 	COMMTIMEOUTS cto = {ctoms, 0, ctoms, 0, ctoms};
 	return (SetCommTimeouts(hSerial, &cto) != 0);
 #else
 	struct termios my_termios;
 	
 	tcgetattr(fdDev, &my_termios);
-	my_termios.c_cc[VTIME] = (cc_t)timeout;
+	my_termios.c_cc[VTIME] = (cc_t)(timeout_ms + 99) / 100;
 	return (tcsetattr(fdDev, TCSANOW, &my_termios) == 0);
 #endif
 }

+ 2 - 1
lowl-vcom.h

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

+ 10 - 1
util.h

@@ -1,5 +1,5 @@
 /*
- * Copyright 2013-2014 Luke Dashjr
+ * Copyright 2013-2015 Luke Dashjr
  * Copyright 2012-2014 Con Kolivas
  * Copyright 2011 Andrew Smith
  * Copyright 2011 Jeff Garzik
@@ -723,6 +723,15 @@ int timer_elapsed(const struct timeval *tvp_timer, const struct timeval *tvp_now
 	return tv.tv_sec;
 }
 
+static inline
+long timer_remaining_us(const struct timeval *tvp_timer, const struct timeval *tvp_now)
+{
+	struct timeval tv;
+	const struct timeval *_tvp_now = _bfg_nullisnow(tvp_now, &tv);
+	timersub(tvp_timer, _tvp_now, &tv);
+	return timeval_to_us(&tv);
+}
+
 static inline
 bool timer_passed(const struct timeval *tvp_timer, const struct timeval *tvp_now)
 {