Browse Source

Merge commit 'b606a60349fe2f1c1c56a1fec833ec849b798676' into redfury

Conflicts:
	driver-bitfury.c
Con Kolivas 12 years ago
parent
commit
7ae8ee8dc3
10 changed files with 279 additions and 95 deletions
  1. 16 5
      ASIC-README
  2. 12 1
      api.c
  3. 32 27
      cgminer.c
  4. 189 53
      driver-bitfury.c
  5. 8 0
      driver-bitfury.h
  6. 3 0
      miner.h
  7. 3 3
      usbutils.c
  8. 9 6
      usbutils.h
  9. 6 0
      util.c
  10. 1 0
      util.h

+ 16 - 5
ASIC-README

@@ -1,10 +1,10 @@
 SUPPORTED DEVICES
 
 Currently supported devices include the Avalon (including BitBurner), the
-Butterfly Labs SC range of devices and the ASICMINER block erupters. No COM
-ports on windows or TTY devices will be used by cgminer as it communicates
-directly with them via USB so it is normal for them to not exist or be
-disconnected when cgminer is running.
+Butterfly Labs SC range of devices, the ASICMINER block erupters and the BPMC
+BF1 (bitfury) USB devices. No COM ports on windows or TTY devices will be used
+by cgminer as it communicates directly with them via USB so it is normal for
+them to not exist or be disconnected when cgminer is running.
 
 
 The BFL devices should come up as one of the following:
@@ -24,7 +24,18 @@ ASICMINER block erupters will come up as AMU.
 
 ASICMINER devices need the --enable-icarus option when compiling cgminer.
 Also note that the AMU is managed by the Icarus driver which is detailed
-in the FPGA-README
+in the FPGA-README. Configuring them uses the same mechanism as outlined
+below for getting started with butterfly labs ASICs.
+
+
+BITFURY devices
+
+Bitfury devices need the --enable-bitfury option when compiling cgminer.
+
+Currently only the BPMC BF1 devices AKA redfury/bluefury are supported and
+come up as BF1. There are no options available for them. Bitfury device are
+also set up as per the butterfly labs ASICs below.
+
 
 
 GETTING STARTED WITH BUTTERFLY LABS ASICS

+ 12 - 1
api.c

@@ -29,7 +29,7 @@
 #include "miner.h"
 #include "util.h"
 
-#if defined(USE_BFLSC) || defined(USE_AVALON)
+#if defined(USE_BFLSC) || defined(USE_AVALON) || defined(USE_BITFURY)
 #define HAVE_AN_ASIC 1
 #endif
 
@@ -176,6 +176,9 @@ static const char *DEVICECODE = ""
 #ifdef USE_BITFORCE
 			"BFL "
 #endif
+#ifdef USE_BITFURY
+			"BFU "
+#endif
 #ifdef USE_ICARUS
 			"ICA "
 #endif
@@ -1223,6 +1226,10 @@ static int numascs()
 #ifdef USE_BFLSC
 		if (devices[i]->drv->drv_id == DRIVER_BFLSC)
 			count++;
+#endif
+#ifdef USE_BITFURY
+		if (devices[i]->drv->drv_id == DRIVER_BITFURY)
+			count++;
 #endif
 	}
 	rd_unlock(&devices_lock);
@@ -1243,6 +1250,10 @@ static int ascdevice(int ascid)
 #ifdef USE_BFLSC
 		if (devices[i]->drv->drv_id == DRIVER_BFLSC)
 			count++;
+#endif
+#ifdef USE_BITFURY
+		if (devices[i]->drv->drv_id == DRIVER_BITFURY)
+			count++;
 #endif
 		if (count == (ascid + 1))
 			goto foundit;

+ 32 - 27
cgminer.c

@@ -3658,15 +3658,6 @@ static void rebuild_hash(struct work *work)
 		scrypt_regenhash(work);
 	else
 		regen_hash(work);
-
-	work->share_diff = share_diff(work);
-	if (unlikely(work->share_diff >= current_diff)) {
-		work->block = true;
-		work->pool->solved++;
-		found_blocks++;
-		work->mandatory = true;
-		applog(LOG_NOTICE, "Found block for pool %d!", work->pool->pool_no);
-	}
 }
 
 static bool cnx_needed(struct pool *pool);
@@ -3844,7 +3835,7 @@ int restart_wait(struct thr_info *thr, unsigned int mstime)
 
 	mutex_lock(&restart_lock);
 	if (thr->work_restart)
-		rc = ETIMEDOUT;
+		rc = 0;
 	else
 		rc = pthread_cond_timedwait(&restart_cond, &restart_lock, &abstime);
 	mutex_unlock(&restart_lock);
@@ -6016,17 +6007,12 @@ void inc_hw_errors(struct thr_info *thr)
 	thr->cgpu->drv->hw_error(thr);
 }
 
-/* Returns true if nonce for work was a valid share */
-bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
+bool test_nonce(struct work *work, uint32_t nonce)
 {
 	uint32_t *work_nonce = (uint32_t *)(work->data + 64 + 12);
-	struct timeval tv_work_found;
-	unsigned char hash2[32];
-	uint32_t *hash2_32 = (uint32_t *)hash2;
+	uint32_t *hash2_32 = (uint32_t *)work->hash2;
 	uint32_t diff1targ;
-	bool ret = true;
 
-	cgtime(&tv_work_found);
 	*work_nonce = htole32(nonce);
 
 	/* Do one last check before attempting to submit the work */
@@ -6034,14 +6020,16 @@ bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
 	flip32(hash2_32, work->hash);
 
 	diff1targ = opt_scrypt ? 0x0000ffffUL : 0;
-	if (be32toh(hash2_32[7]) > diff1targ) {
-		applog(LOG_INFO, "%s%d: invalid nonce - HW error",
-		       thr->cgpu->drv->name, thr->cgpu->device_id);
+	return (be32toh(hash2_32[7]) <= diff1targ);
+}
 
-		inc_hw_errors(thr);
-		ret = false;
-		goto out;
-	}
+/* To be used once the work has been tested to be meet diff1 and has had its
+ * nonce adjusted. */
+void submit_tested_work(struct thr_info *thr, struct work *work)
+{
+	struct timeval tv_work_found;
+
+	work->share_diff = share_diff(work);
 
 	mutex_lock(&stats_lock);
 	total_diff1 += work->device_diff;
@@ -6050,13 +6038,30 @@ bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
 	thr->cgpu->last_device_valid_work = time(NULL);
 	mutex_unlock(&stats_lock);
 
-	if (!fulltest(hash2, work->target)) {
+	if (!fulltest(work->hash2, work->target)) {
 		applog(LOG_INFO, "Share below target");
-		goto out;
+		return;
 	}
 
+	cgtime(&tv_work_found);
 	submit_work_async(work, &tv_work_found);
-out:
+}
+
+/* Returns true if nonce for work was a valid share */
+bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
+{
+	bool ret = true;
+
+	if (test_nonce(work, nonce))
+		submit_tested_work(thr, work);
+	else {
+		applog(LOG_INFO, "%s%d: invalid nonce - HW error",
+		       thr->cgpu->drv->name, thr->cgpu->device_id);
+
+		inc_hw_errors(thr);
+		ret = false;
+	}
+
 	return ret;
 }
 

+ 189 - 53
driver-bitfury.c

@@ -11,7 +11,10 @@
 
 #include "miner.h"
 #include "driver-bitfury.h"
+#include "sha2.h"
 
+/* Wait longer 1/3 longer than it would take for a full nonce range */
+#define BF1WAIT 1600
 struct device_drv bitfury_drv;
 
 static void bitfury_empty_buffer(struct cgpu_info *bitfury)
@@ -27,16 +30,17 @@ static void bitfury_empty_buffer(struct cgpu_info *bitfury)
 static void bitfury_open(struct cgpu_info *bitfury)
 {
 	/* Magic open sequence */
-	usb_transfer(bitfury, 0x21, 0x22, 0x0003, 0, C_BFO_OPEN);
+	usb_transfer(bitfury, 0x21, 0x22, 0x0003, 0, C_BF1_OPEN);
 	bitfury_empty_buffer(bitfury);
 }
 
 static void bitfury_close(struct cgpu_info *bitfury)
 {
+	bitfury_empty_buffer(bitfury);
 	/* Magic close sequence */
-	usb_transfer(bitfury, 0x21, 0x22, 0, 0, C_BFO_CLOSE);
+	usb_transfer(bitfury, 0x21, 0x22, 0, 0, C_BF1_CLOSE);
 	bitfury_empty_buffer(bitfury);
-	usb_transfer(bitfury, 0x23, 0x08, 0x9053, 1, C_BFO_CLOSE);
+	usb_transfer(bitfury, 0x23, 0x08, 0x9053, 1, C_BF1_CLOSE);
 	bitfury_empty_buffer(bitfury);
 }
 
@@ -47,12 +51,51 @@ static void bitfury_identify(struct cgpu_info *bitfury)
 	usb_write(bitfury, "L", 1, &amount, C_PING);
 }
 
+static bool bitfury_getinfo(struct cgpu_info *bitfury, struct bitfury_info *info)
+{
+	char buf[512];
+	int amount;
+
+	usb_write(bitfury, "I", 1, &amount, C_BF1_REQINFO);
+	usb_read(bitfury, buf, 14, &amount, C_BF1_GETINFO);
+	if (amount != 14) {
+		applog(LOG_INFO, "%s %d: Getinfo received %d bytes",
+		       bitfury->drv->name, bitfury->device_id, amount);
+		return false;
+	}
+	info->version = buf[1];
+	memcpy(&info->product, buf + 2, 8);
+	memcpy(&info->serial, buf + 10, 4);
+
+	applog(LOG_INFO, "%s %d: Getinfo returned version %d, product %s serial %08x", bitfury->drv->name,
+	       bitfury->device_id, info->version, info->product, info->serial);
+	bitfury_empty_buffer(bitfury);
+	return true;
+}
+
+static bool bitfury_reset(struct cgpu_info *bitfury)
+{
+	char buf[512];
+	int amount;
+
+	usb_write(bitfury, "R", 1, &amount, C_BF1_REQRESET);
+	usb_read_timeout(bitfury, buf, 7, &amount, BF1WAIT, C_BF1_GETRESET);
+
+	if (amount != 7) {
+		applog(LOG_INFO, "%s %d: Getreset received %d bytes",
+		       bitfury->drv->name, bitfury->device_id, amount);
+		return false;
+	}
+	applog(LOG_INFO, "%s %d: Getreset returned %s", bitfury->drv->name,
+	       bitfury->device_id, buf);
+	bitfury_empty_buffer(bitfury);
+	return true;
+}
+
 static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
 {
 	struct cgpu_info *bitfury;
 	struct bitfury_info *info;
-	char buf[512];
-	int amount;
 
 	bitfury = usb_alloc_cgpu(&bitfury_drv, 1);
 
@@ -60,7 +103,7 @@ static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_device
 		bitfury = usb_free_cgpu(bitfury);
 		goto out;
 	}
-	applog(LOG_INFO, "%s%d: Found at %s", bitfury->drv->name,
+	applog(LOG_INFO, "%s %d: Found at %s", bitfury->drv->name,
 	       bitfury->device_id, bitfury->device_path);
 
 	info = calloc(sizeof(struct bitfury_info), 1);
@@ -73,37 +116,23 @@ static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_device
 	bitfury_open(bitfury);
 
 	/* Send getinfo request */
-	usb_write(bitfury, "I", 1, &amount, C_BFO_REQINFO);
-	usb_read(bitfury, buf, 14, &amount, C_BFO_GETINFO);
-	if (amount != 14) {
-		applog(LOG_WARNING, "%s%d: Getinfo received %d bytes",
-		       bitfury->drv->name, bitfury->device_id, amount);
+	if (!bitfury_getinfo(bitfury, info))
 		goto out_close;
-	}
-	info->version = buf[1];
-	memcpy(&info->product, buf + 2, 8);
-	memcpy(&info->serial, buf + 10, 4);
-
-	applog(LOG_INFO, "%s%d: Getinfo returned version %d, product %s serial %08x", bitfury->drv->name,
-	       bitfury->device_id, info->version, info->product, info->serial);
-	bitfury_empty_buffer(bitfury);
 
 	/* Send reset request */
-	usb_write(bitfury, "R", 1, &amount, C_BFO_REQRESET);
-	usb_read_timeout(bitfury, buf, 7, &amount, 1000, C_BFO_GETRESET);
-
-	if (amount != 7) {
-		applog(LOG_WARNING, "%s%d: Getreset received %d bytes",
-		       bitfury->drv->name, bitfury->device_id, amount);
+	if (!bitfury_reset(bitfury))
 		goto out_close;
-	}
-	applog(LOG_INFO, "%s%d: Getreset returned %s", bitfury->drv->name,
-	       bitfury->device_id, buf);
-	bitfury_empty_buffer(bitfury);
 
 	bitfury_identify(bitfury);
 	bitfury_empty_buffer(bitfury);
-	//return true;
+
+	if (!add_cgpu(bitfury))
+		goto out_close;
+
+	update_usb_stats(bitfury);
+	applog(LOG_INFO, "%s %d: Found at %s",
+	       bitfury->drv->name, bitfury->device_id, bitfury->device_path);
+	return true;
 out_close:
 	bitfury_close(bitfury);
 out:
@@ -115,40 +144,152 @@ static void bitfury_detect(void)
 	usb_detect(&bitfury_drv, bitfury_detect_one);
 }
 
-static bool bitfury_prepare(struct thr_info __maybe_unused *thr)
+static uint32_t decnonce(uint32_t in)
 {
-	return false;
+	uint32_t out;
+
+	/* First part load */
+	out = (in & 0xFF) << 24; in >>= 8;
+
+	/* Byte reversal */
+	in = (((in & 0xaaaaaaaa) >> 1) | ((in & 0x55555555) << 1));
+	in = (((in & 0xcccccccc) >> 2) | ((in & 0x33333333) << 2));
+	in = (((in & 0xf0f0f0f0) >> 4) | ((in & 0x0f0f0f0f) << 4));
+
+	out |= (in >> 2)&0x3FFFFF;
+
+	/* Extraction */
+	if (in & 1) out |= (1 << 23);
+	if (in & 2) out |= (1 << 22);
+
+	out -= 0x800004;
+	return out;
 }
 
-static bool bitfury_fill(struct cgpu_info __maybe_unused *bitfury)
+#define BT_OFFSETS 3
+const uint32_t bf_offsets[] = {0, -0x400000, -0x800000};
+
+static bool bitfury_checkresults(struct thr_info *thr, struct work *work, uint32_t nonce)
 {
-	return true;
+	int i;
+
+	for (i = 0; i < BT_OFFSETS; i++) {
+		if (test_nonce(work, nonce + bf_offsets[i])) {
+			submit_tested_work(thr, work);
+			return true;
+		}
+	}
+	return false;
 }
 
-static int64_t bitfury_scanhash(struct thr_info __maybe_unused *thr)
+static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work,
+				int64_t __maybe_unused max_nonce)
 {
+	struct cgpu_info *bitfury = thr->cgpu;
+	struct bitfury_info *info = bitfury->device_data;
+	struct timeval tv_now;
+	int amount, i;
+	char buf[45];
+	int ms_diff;
+
+	buf[0] = 'W';
+	memcpy(buf + 1, work->midstate, 32);
+	memcpy(buf + 33, work->data + 64, 12);
+
+	/* New results may spill out from the latest work, making us drop out
+	 * too early so read whatever we get for the first half nonce and then
+	 * look for the results to prev work. */
+	cgtime(&tv_now);
+	ms_diff = 600 - ms_tdiff(&tv_now, &info->tv_start);
+	if (ms_diff > 0) {
+		usb_read_timeout(bitfury, info->buf, 512, &amount, ms_diff, C_BF1_GETRES);
+		info->tot += amount;
+	}
+
+	if (unlikely(thr->work_restart))
+		goto cascade;
+
+	/* Now look for the bulk of the previous work results, they will come
+	 * in a batch following the first data. */
+	cgtime(&tv_now);
+	ms_diff = BF1WAIT - ms_tdiff(&tv_now, &info->tv_start);
+	if (unlikely(ms_diff < 10))
+		ms_diff = 10;
+	usb_read_once_timeout(bitfury, info->buf + info->tot, 7, &amount, ms_diff, C_BF1_GETRES);
+	info->tot += amount;
+	while (amount) {
+		usb_read_once_timeout(bitfury, info->buf + info->tot, 512, &amount, 10, C_BF1_GETRES);
+		info->tot += amount;
+	};
+
+	if (unlikely(thr->work_restart))
+		goto cascade;
+
+	/* Send work */
+	usb_write(bitfury, buf, 45, &amount, C_BF1_REQWORK);
+	cgtime(&info->tv_start);
+	/* Get response acknowledging work */
+	usb_read(bitfury, buf, 7, &amount, C_BF1_GETWORK);
+
+	/* Only happens on startup */
+	if (unlikely(!info->prevwork[BF1ARRAY_SIZE]))
+		goto cascade;
+
+	/* Search for what work the nonce matches in order of likelihood. Last
+	 * entry is end of result marker. */
+	for (i = 0; i < info->tot - 7; i += 7) {
+		uint32_t nonce;
+		int j;
+
+		/* Ignore state & switched data in results for now. */
+		memcpy(&nonce, info->buf + i + 3, 4);
+		nonce = decnonce(nonce);
+		for (j = 0; j < BF1ARRAY_SIZE; j++) {
+			if (bitfury_checkresults(thr, info->prevwork[j], nonce)) {
+				info->nonces++;
+				break;
+			}
+		}
+	}
+
+	info->tot = 0;
+	free_work(info->prevwork[BF1ARRAY_SIZE]);
+cascade:
+	for (i = BF1ARRAY_SIZE; i > 0; i--)
+		info->prevwork[i] = info->prevwork[i - 1];
+	info->prevwork[0] = copy_work(work);
+	work->blk.nonce = 0xffffffff;
+	if (info->nonces) {
+		info->nonces--;
+		return (int64_t)0xffffffff;
+	}
 	return 0;
 }
 
-static void bitfury_flush_work(struct cgpu_info __maybe_unused *bitfury)
+static struct api_data *bitfury_api_stats(struct cgpu_info *cgpu)
 {
-}
+	struct bitfury_info *info = cgpu->device_data;
+	struct api_data *root = NULL;
+	char serial[16];
+	int version;
 
-static struct api_data *bitfury_api_stats(struct cgpu_info __maybe_unused *cgpu)
-{
-	return NULL;
-}
+	version = info->version;
+	root = api_add_int(root, "Version", &version, true);
+	root = api_add_string(root, "Product", info->product, false);
+	sprintf(serial, "%08x", info->serial);
+	root = api_add_string(root, "Serial", serial, true);
 
-static void get_bitfury_statline_before(char __maybe_unused *buf, size_t __maybe_unused bufsiz,
-					struct cgpu_info __maybe_unused *bitfury)
-{
+	return root;
 }
 
-static void bitfury_init(struct cgpu_info __maybe_unused *bitfury)
+static void bitfury_init(struct cgpu_info  *bitfury)
 {
+	bitfury_close(bitfury);
+	bitfury_open(bitfury);
+	bitfury_reset(bitfury);
 }
 
-static void bitfury_shutdown(struct thr_info __maybe_unused *thr)
+static void bitfury_shutdown(struct thr_info *thr)
 {
 	struct cgpu_info *bitfury = thr->cgpu;
 
@@ -159,15 +300,10 @@ static void bitfury_shutdown(struct thr_info __maybe_unused *thr)
 struct device_drv bitfury_drv = {
 	.drv_id = DRIVER_BITFURY,
 	.dname = "bitfury",
-	.name = "BFO",
+	.name = "BF1",
 	.drv_detect = bitfury_detect,
-	.thread_prepare = bitfury_prepare,
-	.hash_work = hash_queued_work,
-	.queue_full = bitfury_fill,
-	.scanwork = bitfury_scanhash,
-	.flush_work = bitfury_flush_work,
+	.scanhash = bitfury_scanhash,
 	.get_api_stats = bitfury_api_stats,
-	.get_statline_before = get_bitfury_statline_before,
 	.reinit_device = bitfury_init,
 	.thread_shutdown = bitfury_shutdown,
 	.identify_device = bitfury_identify

+ 8 - 0
driver-bitfury.h

@@ -10,12 +10,20 @@
 #ifndef BITFURY_H
 #define BITFURY_H
 
+#include "miner.h"
 #include "usbutils.h"
 
+#define BF1ARRAY_SIZE 2
+
 struct bitfury_info {
 	uint8_t version;
 	char product[8];
 	uint32_t serial;
+	struct work *prevwork[BF1ARRAY_SIZE + 1];
+	char buf[512];
+	int tot;
+	int nonces;
+	struct timeval tv_start;
 };
 
 #endif /* BITFURY_H */

+ 3 - 0
miner.h

@@ -1263,6 +1263,7 @@ struct work {
 #endif
 	double		device_diff;
 	uint64_t	share_diff;
+	unsigned char	hash2[32];
 
 	int		rolls;
 
@@ -1356,6 +1357,8 @@ struct modminer_fpga_state {
 
 extern void get_datestamp(char *, size_t, struct timeval *);
 extern void inc_hw_errors(struct thr_info *thr);
+extern bool test_nonce(struct work *work, uint32_t nonce);
+extern void submit_tested_work(struct thr_info *thr, struct work *work);
 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);

+ 3 - 3
usbutils.c

@@ -84,7 +84,7 @@
 #else
 #define BFLSC_TIMEOUT_MS 300
 #define BITFORCE_TIMEOUT_MS 200
-#define BITFURY_TIMEOUT_MS 200
+#define BITFURY_TIMEOUT_MS 100
 #define MODMINER_TIMEOUT_MS 100
 #define AVALON_TIMEOUT_MS 200
 #define ICARUS_TIMEOUT_MS 200
@@ -266,7 +266,7 @@ static struct usb_find_devices find_dev[] = {
 #ifdef USE_BITFURY
 	{
 		.drv = DRV_BITFURY,
-		.name = "BFO",
+		.name = "BF1",
 		.ident = IDENT_BFU,
 		.idVendor = 0x03eb,
 		.idProduct = 0x204b,
@@ -2671,7 +2671,7 @@ int _usb_read(struct cgpu_info *cgpu, int epinfo, char *buf, size_t bufsiz, int
 			memcpy(usbdev->buffer, usbbuf + bufsiz, usbdev->bufamt);
 			tot -= usbdev->bufamt;
 			usbbuf[tot] = '\0';
-			applog(LOG_ERR, "USB: %s%i read1 buffering %d extra bytes",
+			applog(LOG_INFO, "USB: %s%i read1 buffering %d extra bytes",
 					cgpu->drv->name, cgpu->device_id, usbdev->bufamt);
 		}
 

+ 9 - 6
usbutils.h

@@ -322,12 +322,15 @@ struct cg_usb_info {
 	USB_ADD_COMMAND(C_ENABLE_UART, "EnableUART") \
 	USB_ADD_COMMAND(C_BB_SET_VOLTAGE, "SetCoreVoltage") \
 	USB_ADD_COMMAND(C_BB_GET_VOLTAGE, "GetCoreVoltage") \
-	USB_ADD_COMMAND(C_BFO_OPEN, "BF1Open") \
-	USB_ADD_COMMAND(C_BFO_CLOSE, "BF1Close") \
-	USB_ADD_COMMAND(C_BFO_REQINFO, "BF1RequestInfo") \
-	USB_ADD_COMMAND(C_BFO_GETINFO, "BF1GetInfo") \
-	USB_ADD_COMMAND(C_BFO_REQRESET, "BF1RequestReset") \
-	USB_ADD_COMMAND(C_BFO_GETRESET, "BF1GetReset")
+	USB_ADD_COMMAND(C_BF1_OPEN, "BF1Open") \
+	USB_ADD_COMMAND(C_BF1_CLOSE, "BF1Close") \
+	USB_ADD_COMMAND(C_BF1_REQINFO, "BF1RequestInfo") \
+	USB_ADD_COMMAND(C_BF1_GETINFO, "BF1GetInfo") \
+	USB_ADD_COMMAND(C_BF1_REQRESET, "BF1RequestReset") \
+	USB_ADD_COMMAND(C_BF1_GETRESET, "BF1GetReset") \
+	USB_ADD_COMMAND(C_BF1_REQWORK, "BF1RequestWork") \
+	USB_ADD_COMMAND(C_BF1_GETWORK, "BF1GetWork") \
+	USB_ADD_COMMAND(C_BF1_GETRES, "BF1GetResults")
 
 /* Create usb_cmds enum from USB_PARSE_COMMANDS macro */
 #define USB_ADD_COMMAND(X, Y) X,

+ 6 - 0
util.c

@@ -1074,6 +1074,12 @@ double us_tdiff(struct timeval *end, struct timeval *start)
 	return end->tv_sec * 1000000 + end->tv_usec - start->tv_sec * 1000000 - start->tv_usec;
 }
 
+/* Returns the milliseconds difference between end and start times */
+int ms_tdiff(struct timeval *end, struct timeval *start)
+{
+	return end->tv_sec * 1000 + end->tv_usec / 1000 - start->tv_sec * 1000 - start->tv_usec / 1000;
+}
+
 /* Returns the seconds difference between end and start times as a double */
 double tdiff(struct timeval *end, struct timeval *start)
 {

+ 1 - 0
util.h

@@ -98,6 +98,7 @@ void cgsleep_us_r(cgtimer_t *ts_start, int64_t us);
 int cgtimer_to_ms(cgtimer_t *cgt);
 void cgtimer_sub(cgtimer_t *a, cgtimer_t *b, cgtimer_t *res);
 double us_tdiff(struct timeval *end, struct timeval *start);
+int ms_tdiff(struct timeval *end, struct timeval *start);
 double tdiff(struct timeval *end, struct timeval *start);
 bool stratum_send(struct pool *pool, char *s, ssize_t len);
 bool sock_full(struct pool *pool);