Browse Source

Merge branch 'master' into hashfast

Conflicts:
	Makefile.am
	api.c
	cgminer.c
	configure.ac
	miner.h
	usbutils.c
	usbutils.h
Con Kolivas 12 years ago
parent
commit
f49a3c7657
23 changed files with 1027 additions and 709 deletions
  1. 3 0
      01-cgminer.rules
  2. 16 5
      ASIC-README
  3. 8 0
      Makefile.am
  4. 137 0
      NEWS
  5. 22 68
      api.c
  6. 59 123
      cgminer.c
  7. 22 5
      configure.ac
  8. 16 7
      driver-avalon.c
  9. 1 0
      driver-avalon.h
  10. 2 4
      driver-bflsc.c
  11. 2 4
      driver-bitforce.c
  12. 330 0
      driver-bitfury.c
  13. 30 0
      driver-bitfury.h
  14. 8 3
      driver-hashfast.c
  15. 67 36
      driver-icarus.c
  16. 2 4
      driver-modminer.c
  17. 9 11
      driver-opencl.c
  18. 2 4
      driver-ztex.c
  19. 44 12
      miner.h
  20. 176 395
      usbutils.c
  21. 64 28
      usbutils.h
  22. 6 0
      util.c
  23. 1 0
      util.h

+ 3 - 0
01-cgminer.rules

@@ -18,3 +18,6 @@ ATTRS{idVendor}=="067b", ATTRS{idProduct}=="0230", SUBSYSTEMS=="usb", ACTION=="a
 
 # Ztex
 ATTRS{idVendor}=="221a", ATTRS{idProduct}=="0100", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev"
+
+# BF1
+ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204b", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev"

+ 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

+ 8 - 0
Makefile.am

@@ -86,6 +86,14 @@ if HAS_HASHFAST
 cgminer_SOURCES += driver-hashfast.c driver-hashfast.h
 endif
 
+if HAS_BITFURY
+cgminer_SOURCES += driver-bitfury.c driver-bitfury.h
+endif
+
+if HAS_ICARUS
+cgminer_SOURCES += driver-icarus.c
+endif
+
 if HAS_ICARUS
 cgminer_SOURCES += driver-icarus.c
 endif

+ 137 - 0
NEWS

@@ -1,3 +1,140 @@
+Version 3.5.0 - 29th September 2013
+
+- Add magic init sequence required on BF1 devices to get them mining on windows.
+- usbinfo.devlock is only ever write locked so convert it to a mutex
+- Icarus remove unneeded opt_debug tests due to applog being a macro
+- Icarus - CMR shouldn't wait the full timeout due to handle sharing
+- We should only yield once in cg_wunlock
+- Provide a function to downgrade a cglock from a write lock to an intermediate
+variant.
+- Deuglify use of _PARSE_COMMANDS macro expansions.
+- Deuglify use of usb parse commands macro in usbutils.
+- Use the driver add commands macros in api.c to avoid individually listing
+them.
+- Separate out asic fpga and opencl drivers in the driver parse commands macro
+for use individually as needed.
+- Use macro expansion in usb_find_devices to avoid explicitly listing them all.
+- Use macro expansion to iterate over all the drivers without explicitly writing
+them out in usbutils.c
+- Iterate over the bitfury offsets in order of decreasing likelihood.
+- Reattach the kernel driver on linux on usb_uninit.
+- Attach the kernel driver on failure to usb init on linux.
+- libusb kernel driver operations are only available on linux.
+- There is no need to get the external prototypes for drivers in cgminer.c any
+more.
+- Remove unnecessary gpu_threads initialisation.
+- Put avalon last in the sequence of adding drivers to prevent it trying to
+claim similar chip devices on startup.
+- Use macro expansion to iterate over all device drivers without needing to
+explicitly code in support in all places. Pass a hotplug bool to the detect()
+function to prevent opencl trying to hogplug GPUs.
+- Forward declare all device drivers in miner.h avoiding the need to export them
+everywhere else.
+- Add a noop function for driver detect when it's missing.
+- Reuse the DRIVER_ macros to avoid having yet another definition for DRV_
+- Use macro expansion to generate extern device_drv prototypes.
+- Create a macro list of drivers to enable easier addition of further drivers.
+- There is no point setting the BF1 preferred packet size to the maximum since
+it will do so automatically.
+- icarus ensure all cmr interfaces are initialised properly
+- usbutils - fix USBDEBUG warnings
+- Remove unnecessary steps in communicating with BF1 and just use USB interface
+1.
+- usbutils - usb_bulk_transfer fix the buf/data fix
+- usb_bulk_transfer - use the allocated buffer
+- Set preferred packet sizes per interface on BF1.
+- usbutils allow PrefPacketSize per endpoint
+- Remove magic control sequences on open/close on BF1 and just flush the read
+buffers.
+- Check return codes in getinfo and reset and fail as needed in BF1.
+- Check return code for bitfury_open and release resources properly on failed
+initialisation.
+- Abstract out flushing of interrupt reads in BF1 devices.
+- Perform interrupt read after close message on BF1 as per serial close.
+- Perform interrupt read flush as per serial open on BF1 devices.
+- Add information for 2nd USB interface on BF1 devices and choose interface 1
+for bulk transfers.
+- usbutils - bulk transfer copy test fix
+- usbutils - add USBDEBUG for usb_bulk_transfer
+- Add more read_ii variants to usbutils.
+- Name remainder of BFU usb commands used.
+- Use submit_tested_work in bitfury driver to avoid unnecessarily re-testing the
+work for validity.
+- Abstract out work submission once it's been tested, to be used by drivers that
+do their own internal validity testing.
+- Store the hash2 array in struct work for further reuse.
+- usbutils - which_intinfo not requried
+- Use the test_nonce function within submit_nonce and store the uint32
+corresponding to hash2 37 for further use.
+- usbutils - interfaces must all be on one handle - ep implies the interface
+- avalon stats use exact type
+- Only set share diff if we've confirmed it's a share first.
+- Update ASIC-README for bitfury devices.
+- Use an array of offsets when checking nonces in bitfury_checkresults
+- Limit the duration we wait for reads in BF1 based on time already elapsed to
+account for other delays such as work restart messages or out of work.
+- Minimise size of serial string we copy in BF1 stats to avoid overflow.
+- Implement basic API stats for BF1 and increase array of results to check for
+the rare straggling result.
+- Space debug output for bf1 to separate from numerals.
+- Abstract out the bitfury open close and reset functions and use them on
+reinit.
+- Rename BF1 devices BF1
+- Check for work restart, breaking out early after usb reads in BF1.
+- Do not lose the first sets of results from BF1.
+- There is no point checking for results from the next round of work on BF1.
+- Last result returned by BF1 is an end of results marker so ignore it.
+- restart_wait should return 0 if thr_restart is true.
+- Remove unused code by bitfury driver since current driver uses serialised
+scanhash.
+- Meter out return of estimated hashes in BF1 to smooth out visible hashrate.
+- Optimise inner scanhash loop for bf1.
+- Add yet another backup work for triple buffering of work in bf1 to account for
+extra late results returned and don't check nonce offsets which appear to never
+return.
+- Name the work request and result usb commands for BF1
+- Define a mandatory upper limit to waiting for reset and data on BF1 based on
+full nonce duration.
+- Decrease usb buffering to verbose logging.
+- Add in first draft for a serialised work model sending/receiving data for BF1
+devices.
+- Add complete close sequence to bf1 as it happens on serial.
+- Provide a bitfury identify function for bf1.
+- Reliably extract BF1 information at startup and reset the device.
+- Add commands for getting BF1 bitfury info
+- Add magic BF1 bitfury open and close control sequences.
+- Add BF1 detection code to bitfury driver.
+- Create basic placeholders for bitfury driver code.
+- Add bf1 device information to usbutils to enable device detection.
+- Add basic defines for building for bitfury devices.
+- Add redfury device to udev rules.
+- avalon: display the FPGA controller version on API
+- pool_active uninitialised_var rolltime
+- Use macro expansion to only need to define usb enums and commands in one
+place.
+- usbutils saving incorrect overflow buffer
+- ignore libusb.la and *.lo on linux
+- icarus support CMR with no extensions
+- usbtils - interfaces dont work yet in libusb windows so disable for that only
+- Provide a --disable-libcurl config option to build support for stratum mining
+only.
+- Fix the api-example.c compile under Linux
+- usbutils - only release the device once - for the first intinfo
+- usbutils set_interface is no longer valid
+- ubsutils interfaces much each have their own handle
+- usbutils kernel_detach should use the interface number
+- usbutils - allow the driver to change which_intinfo
+- Reset quotas on load balance for all pools at the same time to avoid running
+out during selection and unintentionally dropping to fallback.
+- Break out of select pool from a common point for appropriate debug messages
+and to avoid further tests.
+- usbutils correct/reverse CMR product numbers
+- usbutils specifically track handles and interfaces
+- change drivers to use usb_interface() - required for multi interface change
+- usbutils - allow a device to use multiple interfaces (and better var names)
+- Cast -1 to (char) to cope with different default char types on ARM.
+
+
 Version 3.4.3 - 13th September 2013
 
 - Put corefoundation and iokit separate in ldflags for darwin.

+ 22 - 68
api.c

@@ -29,7 +29,7 @@
 #include "miner.h"
 #include "util.h"
 
-#if defined(USE_BFLSC) || defined(USE_AVALON) || defined(USE_HASHFAST)
+#if defined(USE_BFLSC) || defined(USE_AVALON) || defined(USE_HASHFAST) || defined(USE_BITFURY)
 #define HAVE_AN_ASIC 1
 #endif
 
@@ -167,8 +167,8 @@ static const char *SCRYPTSTR = "scrypt";
 static const char *SHA256STR = "sha256";
 
 static const char *DEVICECODE = ""
-#ifdef HAVE_OPENCL
-			"GPU "
+#ifdef USE_AVALON
+			"AVA "
 #endif
 #ifdef USE_BFLSC
 			"BAS "
@@ -176,20 +176,23 @@ static const char *DEVICECODE = ""
 #ifdef USE_BITFORCE
 			"BFL "
 #endif
+#ifdef USE_BITFURY
+			"BFU "
+#endif
+#ifdef HAVE_OPENCL
+			"GPU "
+#endif
 #ifdef USE_HASHFAST
 			"HFA "
 #endif
 #ifdef USE_ICARUS
 			"ICA "
 #endif
-#ifdef USE_AVALON
-			"AVA "
+#ifdef USE_MODMINER
+			"MMQ "
 #endif
 #ifdef USE_ZTEX
 			"ZTX "
-#endif
-#ifdef USE_MODMINER
-			"MMQ "
 #endif
 			"";
 
@@ -1211,26 +1214,18 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
 	return root;
 }
 
+#define DRIVER_COUNT_DRV(X) if (devices[i]->drv->drv_id == DRIVER_##X) \
+	count++;
+
 #ifdef HAVE_AN_ASIC
-static int numascs()
+static int numascs(void)
 {
 	int count = 0;
 	int i;
 
 	rd_lock(&devices_lock);
 	for (i = 0; i < total_devices; i++) {
-#ifdef USE_AVALON
-		if (devices[i]->drv->drv_id == DRIVER_AVALON)
-			count++;
-#endif
-#ifdef USE_BFLSC
-		if (devices[i]->drv->drv_id == DRIVER_BFLSC)
-			count++;
-#endif
-#ifdef USE_HASHFAST
-		if (devices[i]->drv->drv_id == DRIVER_HASHFAST)
-			count++;
-#endif
+		ASIC_PARSE_COMMANDS(DRIVER_COUNT_DRV)
 	}
 	rd_unlock(&devices_lock);
 	return count;
@@ -1243,18 +1238,7 @@ static int ascdevice(int ascid)
 
 	rd_lock(&devices_lock);
 	for (i = 0; i < total_devices; i++) {
-#ifdef USE_AVALON
-		if (devices[i]->drv->drv_id == DRIVER_AVALON)
-			count++;
-#endif
-#ifdef USE_BFLSC
-		if (devices[i]->drv->drv_id == DRIVER_BFLSC)
-			count++;
-#endif
-#ifdef USE_HASHFAST
-		if (devices[i]->drv->drv_id == DRIVER_HASHFAST)
-			count++;
-#endif
+		ASIC_PARSE_COMMANDS(DRIVER_COUNT_DRV)
 		if (count == (ascid + 1))
 			goto foundit;
 	}
@@ -1270,29 +1254,14 @@ foundit:
 #endif
 
 #ifdef HAVE_AN_FPGA
-static int numpgas()
+static int numpgas(void)
 {
 	int count = 0;
 	int i;
 
 	rd_lock(&devices_lock);
 	for (i = 0; i < total_devices; i++) {
-#ifdef USE_BITFORCE
-		if (devices[i]->drv->drv_id == DRIVER_BITFORCE)
-			count++;
-#endif
-#ifdef USE_ICARUS
-		if (devices[i]->drv->drv_id == DRIVER_ICARUS)
-			count++;
-#endif
-#ifdef USE_ZTEX
-		if (devices[i]->drv->drv_id == DRIVER_ZTEX)
-			count++;
-#endif
-#ifdef USE_MODMINER
-		if (devices[i]->drv->drv_id == DRIVER_MODMINER)
-			count++;
-#endif
+		FPGA_PARSE_COMMANDS(DRIVER_COUNT_DRV)
 	}
 	rd_unlock(&devices_lock);
 	return count;
@@ -1305,22 +1274,7 @@ static int pgadevice(int pgaid)
 
 	rd_lock(&devices_lock);
 	for (i = 0; i < total_devices; i++) {
-#ifdef USE_BITFORCE
-		if (devices[i]->drv->drv_id == DRIVER_BITFORCE)
-			count++;
-#endif
-#ifdef USE_ICARUS
-		if (devices[i]->drv->drv_id == DRIVER_ICARUS)
-			count++;
-#endif
-#ifdef USE_ZTEX
-		if (devices[i]->drv->drv_id == DRIVER_ZTEX)
-			count++;
-#endif
-#ifdef USE_MODMINER
-		if (devices[i]->drv->drv_id == DRIVER_MODMINER)
-			count++;
-#endif
+		FPGA_PARSE_COMMANDS(DRIVER_COUNT_DRV)
 		if (count == (pgaid + 1))
 			goto foundit;
 	}
@@ -1770,11 +1724,11 @@ static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom
 			dev_runtime = 1.0;
 
 #ifdef USE_ZTEX
-		if (cgpu->drv->drv_id == DRIVER_ZTEX && cgpu->device_ztex)
+		if (cgpu->drv->drv_id == DRIVER_ztex && cgpu->device_ztex)
 			frequency = cgpu->device_ztex->freqM1 * (cgpu->device_ztex->freqM + 1);
 #endif
 #ifdef USE_MODMINER
-		if (cgpu->drv->drv_id == DRIVER_MODMINER)
+		if (cgpu->drv->drv_id == DRIVER_modminer)
 			frequency = cgpu->clock;
 #endif
 

+ 59 - 123
cgminer.c

@@ -123,7 +123,7 @@ bool opt_scrypt;
 #endif
 #endif
 bool opt_restart = true;
-static bool opt_nogpu;
+bool opt_nogpu;
 
 struct list_head scan_devices;
 static bool devices_enabled[MAX_DEVICES];
@@ -1567,6 +1567,9 @@ static char *opt_verusage_and_exit(const char *extra)
 #ifdef USE_BITFORCE
 		"bitforce "
 #endif
+#ifdef USE_BITFURY
+		"bitfury "
+#endif
 #ifdef HAVE_OPENCL
 		"GPU "
 #endif
@@ -3662,15 +3665,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);
@@ -3848,7 +3842,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);
@@ -5578,7 +5572,7 @@ static bool pool_active(struct pool *pool, bool pinging)
 	bool ret = false;
 	json_t *val;
 	CURL *curl;
-	int rolltime;
+	int uninitialised_var(rolltime);
 
 	if (pool->has_gbt)
 		applog(LOG_DEBUG, "Retrieving block template from pool %s", pool->rpc_url);
@@ -6020,17 +6014,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 */
@@ -6038,14 +6027,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;
@@ -6054,13 +6045,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;
 }
 
@@ -7351,34 +7359,6 @@ void enable_curses(void) {
 }
 #endif
 
-#ifdef USE_BFLSC
-extern struct device_drv bflsc_drv;
-#endif
-
-#ifdef USE_BITFORCE
-extern struct device_drv bitforce_drv;
-#endif
-
-#ifdef USE_HASHFAST
-extern struct device_drv hashfast_drv;
-#endif
-
-#ifdef USE_ICARUS
-extern struct device_drv icarus_drv;
-#endif
-
-#ifdef USE_AVALON
-extern struct device_drv avalon_drv;
-#endif
-
-#ifdef USE_MODMINER
-extern struct device_drv modminer_drv;
-#endif
-
-#ifdef USE_ZTEX
-extern struct device_drv ztex_drv;
-#endif
-
 static int cgminer_id_count = 0;
 
 /* Various noop functions for drivers that don't support or need their
@@ -7433,14 +7413,17 @@ static void noop_thread_enable(struct thr_info __maybe_unused *thr)
 {
 }
 
+static void noop_detect(bool __maybe_unused hotplug)
+{
+}
 #define noop_flush_work noop_reinit_device
 #define noop_queue_full noop_get_stats
 
 /* Fill missing driver drv functions with noops */
-void fill_device_drv(struct cgpu_info *cgpu)
+void fill_device_drv(struct device_drv *drv)
 {
-	struct device_drv *drv = cgpu->drv;
-
+	if (!drv->drv_detect)
+		drv->drv_detect = &noop_detect;
 	if (!drv->reinit_device)
 		drv->reinit_device = &noop_reinit_device;
 	if (!drv->get_statline_before)
@@ -7495,7 +7478,7 @@ void enable_device(struct cgpu_info *cgpu)
 #endif
 	}
 #ifdef HAVE_OPENCL
-	if (cgpu->drv->drv_id == DRIVER_OPENCL) {
+	if (cgpu->drv->drv_id == DRIVER_opencl) {
 		gpu_threads += cgpu->threads;
 	}
 #endif
@@ -7538,8 +7521,6 @@ bool add_cgpu(struct cgpu_info *cgpu)
 	cgpu->last_device_valid_work = time(NULL);
 	mutex_unlock(&stats_lock);
 
-	fill_device_drv(cgpu);
-
 	if (hotplug_mode)
 		devices[total_devices + new_devices++] = cgpu;
 	else
@@ -7630,6 +7611,8 @@ static void hotplug_process()
 	switch_logsize(true);
 }
 
+#define DRIVER_DRV_DETECT_HOTPLUG(X) X##_drv.drv_detect(true);
+
 static void *hotplug_thread(void __maybe_unused *userdata)
 {
 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
@@ -7649,29 +7632,9 @@ static void *hotplug_thread(void __maybe_unused *userdata)
 			new_devices = 0;
 			new_threads = 0;
 
-#ifdef USE_ICARUS
-			icarus_drv.drv_detect();
-#endif
-
-#ifdef USE_BFLSC
-			bflsc_drv.drv_detect();
-#endif
-
-#ifdef USE_BITFORCE
-			bitforce_drv.drv_detect();
-#endif
-
-#ifdef USE_HASHFAST
-			hashfast_drv.drv_detect();
-#endif
-
-#ifdef USE_MODMINER
-			modminer_drv.drv_detect();
-#endif
-
-#ifdef USE_AVALON
-			avalon_drv.drv_detect();
-#endif
+			/* Use the DRIVER_PARSE_COMMANDS macro to detect all
+			 * devices */
+			DRIVER_PARSE_COMMANDS(DRIVER_DRV_DETECT_HOTPLUG)
 
 			if (new_devices)
 				hotplug_process();
@@ -7697,6 +7660,9 @@ static void probe_pools(void)
 	}
 }
 
+#define DRIVER_FILL_DEVICE_DRV(X) fill_device_drv(&X##_drv);
+#define DRIVER_DRV_DETECT_ALL(X) X##_drv.drv_detect(false);
+
 int main(int argc, char *argv[])
 {
 	struct sigaction handler;
@@ -7877,44 +7843,14 @@ int main(int argc, char *argv[])
 	}
 #endif
 
-#ifdef HAVE_OPENCL
-	if (!opt_nogpu)
-		opencl_drv.drv_detect();
-	gpu_threads = 0;
-#endif
-
-	if (!opt_scrypt) {
-#ifdef USE_ICARUS
-	icarus_drv.drv_detect();
-#endif
-
-#ifdef USE_BFLSC
-	bflsc_drv.drv_detect();
-#endif
-
-#ifdef USE_BITFORCE
-	bitforce_drv.drv_detect();
-#endif
+	/* Use the DRIVER_PARSE_COMMANDS macro to fill all the device_drvs */
+	DRIVER_PARSE_COMMANDS(DRIVER_FILL_DEVICE_DRV)
 
-#ifdef USE_HASHFAST
-	hf_init_crc8();
-	hf_init_crc32();
-	hashfast_drv.drv_detect();
-#endif
-
-#ifdef USE_MODMINER
-	modminer_drv.drv_detect();
-#endif
-
-#ifdef USE_ZTEX
-		ztex_drv.drv_detect();
-#endif
-
-	/* Detect avalon last since it will try to claim the device regardless
-	 * as detection is unreliable. */
-#ifdef USE_AVALON
-	avalon_drv.drv_detect();
-#endif
+	if (opt_scrypt)
+		opencl_drv.drv_detect(false);
+	else {
+	/* Use the DRIVER_PARSE_COMMANDS macro to detect all devices */
+		DRIVER_PARSE_COMMANDS(DRIVER_DRV_DETECT_ALL)
 	}
 
 	if (opt_display_devs) {

+ 22 - 5
configure.ac

@@ -1,8 +1,8 @@
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [3])
-m4_define([v_min], [4])
-m4_define([v_mic], [3])
+m4_define([v_min], [5])
+m4_define([v_mic], [0])
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_ver], [v_maj.v_min.v_mic])
 m4_define([lt_rev], m4_eval(v_maj + v_min))
@@ -253,6 +253,17 @@ if test "x$bitforce" = xyes; then
 fi
 AM_CONDITIONAL([HAS_BITFORCE], [test x$bitforce = xyes])
 
+bitfury="no"
+
+AC_ARG_ENABLE([bitfury],
+	[AC_HELP_STRING([--enable-bitfury],[Compile support for BitFury ASICs (default disabled)])],
+	[bitfury=$enableval]
+	)
+if test "x$bitfury" = xyes; then
+	AC_DEFINE([USE_BITFURY], [1], [Defined to 1 if BitForce support is wanted])
+fi
+AM_CONDITIONAL([HAS_BITFURY], [test x$bitfury = xyes])
+
 hashfast="no"
 
 AC_ARG_ENABLE([hashfast],
@@ -321,7 +332,7 @@ else
 	])
 fi
 
-if test x$avalon$bitforce$modminer$bflsc$icarus$hashfast != xnononononono; then
+if test x$avalon$bitforce$bitfury$modminer$bflsc$icarus$hashfast != xnonononononono; then
 	want_usbutils=true
 else
 	want_usbutils=false
@@ -493,14 +504,14 @@ if test "x$opencl" != xno; then
 
 	else
 		echo "  OpenCL...............: NOT FOUND. GPU mining support DISABLED"
-		if test "x$bitforce$avalon$icarus$ztex$modminer$bflsc$hashfast" = xnonononononono; then
+		if test "x$avalon$bitforce$bitfury$icarus$ztex$modminer$bflsc$hashfast" = xnononononononono; then
 			AC_MSG_ERROR([No mining configured in])
 		fi
 		echo "  scrypt...............: Disabled (needs OpenCL)"
 	fi
 else
 	echo "  OpenCL...............: Detection overrided. GPU mining support DISABLED"
-	if test "x$bitforce$icarus$avalon$ztex$modminer$bflsc$hashfast" = xnonononononono; then
+	if test "x$avalon$bitforce$bitfury$icarus$ztex$modminer$bflsc$hashfast" = xnononononononono; then
 		AC_MSG_ERROR([No mining configured in])
 	fi
 	echo "  scrypt...............: Disabled (needs OpenCL)"
@@ -535,6 +546,12 @@ else
 	echo "  BitForce.FPGAs.......: Disabled"
 fi
 
+if test "x$bitfury" = xyes; then
+	echo "  BitFury.ASICs........: Enabled"
+else
+	echo "  BitFury.ASICs........: Disabled"
+fi
+
 if test "x$hashfast" = xyes; then
 	echo "  Hashfast.ASICs.......: Enabled"
 else

+ 16 - 7
driver-avalon.c

@@ -52,7 +52,6 @@ int opt_bitburner_core_voltage = BITBURNER_DEFAULT_CORE_VOLTAGE;
 bool opt_avalon_auto;
 
 static int option_offset = -1;
-struct device_drv avalon_drv;
 
 static int avalon_init_task(struct avalon_task *at,
 			    uint8_t reset, uint8_t ff, uint8_t fan,
@@ -273,6 +272,7 @@ static int avalon_reset(struct cgpu_info *avalon, bool initial)
 	struct avalon_task at;
 	uint8_t *buf, *tmp;
 	struct timespec p;
+	struct avalon_info *info = avalon->device_data;
 
 	/* Send reset, then check for result */
 	avalon_init_task(&at, 1, 0,
@@ -329,9 +329,17 @@ static int avalon_reset(struct cgpu_info *avalon, bool initial)
 		       " (%d: %02x %02x %02x %02x)", avalon->drv->name, avalon->device_id,
 		       i, buf[0], buf[1], buf[2], buf[3]);
 		/* FIXME: return 1; */
-	} else
-		applog(LOG_WARNING, "%s%d: Reset succeeded",
-		       avalon->drv->name, avalon->device_id);
+	} else {
+		/* buf[44]: minor
+		 * buf[45]: day
+		 * buf[46]: year,month, d6: 201306
+		 */
+		info->ctlr_ver = ((buf[46] >> 4) + 2000) * 1000000 +
+			(buf[46] & 0x0f) * 10000 +
+			buf[45] * 100 +	buf[44];
+		applog(LOG_WARNING, "%s%d: Reset succeeded (Controller version: %d)",
+		       avalon->drv->name, avalon->device_id, info->ctlr_ver);
+	}
 
 	return 0;
 }
@@ -711,7 +719,7 @@ static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found
 	/* Even though this is an FTDI type chip, we want to do the parsing
 	 * all ourselves so set it to std usb type */
 	avalon->usbdev->usb_type = USB_TYPE_STD;
-	avalon->usbdev->PrefPacketSize = AVALON_USB_PACKETSIZE;
+	usb_set_pps(avalon, AVALON_USB_PACKETSIZE);
 
 	/* We have a real Avalon! */
 	avalon_initialise(avalon);
@@ -791,7 +799,7 @@ shin:
 	return false;
 }
 
-static void avalon_detect(void)
+static void avalon_detect(bool __maybe_unused hotplug)
 {
 	usb_detect(&avalon_drv, avalon_detect_one);
 }
@@ -1522,6 +1530,7 @@ static struct api_data *avalon_api_stats(struct cgpu_info *cgpu)
 				info->version1, info->version2, info->version3);
 		root = api_add_string(root, "version", buf, true);
 	}
+	root = api_add_uint32(root, "Controller Version", &(info->ctlr_ver), false);
 
 	return root;
 }
@@ -1590,7 +1599,7 @@ static char *avalon_set_device(struct cgpu_info *avalon, char *option, char *set
 }
 
 struct device_drv avalon_drv = {
-	.drv_id = DRIVER_AVALON,
+	.drv_id = DRIVER_avalon,
 	.dname = "avalon",
 	.name = "AVA",
 	.drv_detect = avalon_detect,

+ 1 - 0
driver-avalon.h

@@ -125,6 +125,7 @@ struct avalon_info {
 	int matching_work[AVALON_DEFAULT_MINER_NUM];
 
 	int frequency;
+	uint32_t ctlr_ver;
 
 	struct thr_info *thr;
 	pthread_t read_thr;

+ 2 - 4
driver-bflsc.c

@@ -33,8 +33,6 @@ int opt_bflsc_overheat = BFLSC_TEMP_OVERHEAT;
 
 static const char *blank = "";
 
-struct device_drv bflsc_drv;
-
 static enum driver_version drv_ver(struct cgpu_info *bflsc, const char *ver)
 {
 	char *tmp;
@@ -895,7 +893,7 @@ shin:
 	return false;
 }
 
-static void bflsc_detect(void)
+static void bflsc_detect(bool __maybe_unused hotplug)
 {
 	usb_detect(&bflsc_drv, bflsc_detect_one);
 }
@@ -1915,7 +1913,7 @@ else a whole lot of something like these ... etc
 }
 
 struct device_drv bflsc_drv = {
-	.drv_id = DRIVER_BFLSC,
+	.drv_id = DRIVER_bflsc,
 	.dname = "BitForceSC",
 	.name = BFLSC_SINGLE,
 	.drv_detect = bflsc_detect,

+ 2 - 4
driver-bitforce.c

@@ -77,8 +77,6 @@
 
 static const char *blank = "";
 
-struct device_drv bitforce_drv;
-
 static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
 {
 	int err, interface;
@@ -290,7 +288,7 @@ shin:
 	return false;
 }
 
-static void bitforce_detect(void)
+static void bitforce_detect(bool __maybe_unused hotplug)
 {
 	usb_detect(&bitforce_drv, bitforce_detect_one);
 }
@@ -742,7 +740,7 @@ static struct api_data *bitforce_api_stats(struct cgpu_info *cgpu)
 }
 
 struct device_drv bitforce_drv = {
-	.drv_id = DRIVER_BITFORCE,
+	.drv_id = DRIVER_bitforce,
 	.dname = "BitForce",
 	.name = "BFL",
 	.drv_detect = bitforce_detect,

+ 330 - 0
driver-bitfury.c

@@ -0,0 +1,330 @@
+/*
+ * 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
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "config.h"
+
+#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
+
+static void bitfury_empty_buffer(struct cgpu_info *bitfury)
+{
+	char buf[512];
+	int amount;
+
+	do {
+		usb_read_once(bitfury, buf, 512, &amount, C_BF1_FLUSH);
+	} while (amount);
+}
+
+static void bitfury_open(struct cgpu_info *bitfury)
+{
+	uint32_t buf[2];
+
+	bitfury_empty_buffer(bitfury);
+	/* Magic sequence to reset device only really needed for windows but
+	 * harmless on linux. */
+	buf[0] = 0x80250000;
+	buf[1] = 0x00000800;
+	usb_transfer(bitfury, 0, 9, 1, 0, C_BF1_RESET);
+	usb_transfer(bitfury, 0x21, 0x22, 0, 0, C_BF1_OPEN);
+	usb_transfer_data(bitfury, 0x21, 0x20, 0x0000, 0, buf, 7, C_BF1_INIT);
+}
+
+static void bitfury_close(struct cgpu_info *bitfury)
+{
+	bitfury_empty_buffer(bitfury);
+}
+
+static void bitfury_identify(struct cgpu_info *bitfury)
+{
+	int amount;
+
+	usb_write(bitfury, "L", 1, &amount, C_BF1_IDENTIFY);
+}
+
+static bool bitfury_getinfo(struct cgpu_info *bitfury, struct bitfury_info *info)
+{
+	int amount, err;
+	char buf[16];
+
+	err = usb_write(bitfury, "I", 1, &amount, C_BF1_REQINFO);
+	if (err) {
+		applog(LOG_INFO, "%s %d: Failed to write REQINFO",
+		       bitfury->drv->name, bitfury->device_id);
+		return false;
+	}
+	err = usb_read(bitfury, buf, 14, &amount, C_BF1_GETINFO);
+	if (err) {
+		applog(LOG_INFO, "%s %d: Failed to read GETINFO",
+		       bitfury->drv->name, bitfury->device_id);
+		return false;
+	}
+	if (amount != 14) {
+		applog(LOG_INFO, "%s %d: Getinfo received %d bytes instead of 14",
+		       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)
+{
+	int amount, err;
+	char buf[16];
+
+	err = usb_write(bitfury, "R", 1, &amount, C_BF1_REQRESET);
+	if (err) {
+		applog(LOG_INFO, "%s %d: Failed to write REQRESET",
+		       bitfury->drv->name, bitfury->device_id);
+		return false;
+	}
+	err = usb_read_timeout(bitfury, buf, 7, &amount, BF1WAIT, C_BF1_GETRESET);
+	if (err) {
+		applog(LOG_INFO, "%s %d: Failed to read GETRESET",
+		       bitfury->drv->name, bitfury->device_id);
+		return false;
+	}
+	if (amount != 7) {
+		applog(LOG_INFO, "%s %d: Getreset received %d bytes instead of 7",
+		       bitfury->drv->name, bitfury->device_id, amount);
+		return false;
+	}
+	applog(LOG_DEBUG, "%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;
+
+	bitfury = usb_alloc_cgpu(&bitfury_drv, 1);
+
+	if (!usb_init(bitfury, dev, found))
+		goto out;
+	applog(LOG_INFO, "%s %d: Found at %s", bitfury->drv->name,
+	       bitfury->device_id, bitfury->device_path);
+
+	info = calloc(sizeof(struct bitfury_info), 1);
+	if (!info)
+		quit(1, "Failed to calloc info in bitfury_detect_one");
+	bitfury->device_data = info;
+
+	usb_buffer_enable(bitfury);
+
+	bitfury_open(bitfury);
+
+	/* Send getinfo request */
+	if (!bitfury_getinfo(bitfury, info))
+		goto out_close;
+
+	/* Send reset request */
+	if (!bitfury_reset(bitfury))
+		goto out_close;
+
+	bitfury_identify(bitfury);
+	bitfury_empty_buffer(bitfury);
+
+	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);
+	usb_uninit(bitfury);
+out:
+	bitfury = usb_free_cgpu(bitfury);
+	return false;
+}
+
+static void bitfury_detect(bool __maybe_unused hotplug)
+{
+	usb_detect(&bitfury_drv, bitfury_detect_one);
+}
+
+static uint32_t decnonce(uint32_t in)
+{
+	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;
+}
+
+#define BT_OFFSETS 3
+const uint32_t bf_offsets[] = {-0x800000, 0, -0x400000};
+
+static bool bitfury_checkresults(struct thr_info *thr, struct work *work, uint32_t nonce)
+{
+	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 *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 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;
+
+	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);
+
+	return root;
+}
+
+static void bitfury_init(struct cgpu_info  *bitfury)
+{
+	bitfury_close(bitfury);
+	bitfury_open(bitfury);
+	bitfury_reset(bitfury);
+}
+
+static void bitfury_shutdown(struct thr_info *thr)
+{
+	struct cgpu_info *bitfury = thr->cgpu;
+
+	bitfury_close(bitfury);
+}
+
+/* Currently hardcoded to BF1 devices */
+struct device_drv bitfury_drv = {
+	.drv_id = DRIVER_bitfury,
+	.dname = "bitfury",
+	.name = "BF1",
+	.drv_detect = bitfury_detect,
+	.scanhash = bitfury_scanhash,
+	.get_api_stats = bitfury_api_stats,
+	.reinit_device = bitfury_init,
+	.thread_shutdown = bitfury_shutdown,
+	.identify_device = bitfury_identify
+};

+ 30 - 0
driver-bitfury.h

@@ -0,0 +1,30 @@
+/*
+ * 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
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#ifndef BITFURY_H
+#define BITFURY_H
+
+#include "miner.h"
+#include "usbutils.h"
+
+#define BF1ARRAY_SIZE 2
+
+struct bitfury_info {
+	struct cgpu_info *base_cgpu;
+	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 */

+ 8 - 3
driver-hashfast.c

@@ -285,7 +285,7 @@ static bool hashfast_detect_one_usb(libusb_device *dev, struct usb_find_devices
 	}
 
 	hashfast->usbdev->usb_type = USB_TYPE_STD;
-	hashfast->usbdev->PrefPacketSize = HASHFAST_USB_PACKETSIZE;
+	usb_set_pps(hashfast, HASHFAST_USB_PACKETSIZE);
 
 	hashfast_usb_initialise(hashfast);
 
@@ -293,8 +293,13 @@ static bool hashfast_detect_one_usb(libusb_device *dev, struct usb_find_devices
 	return hashfast_detect_common(hashfast, baud);
 }
 
-static void hashfast_detect(void)
+static void hashfast_detect(bool hotplug)
 {
+	/* Set up the CRC tables only once. */
+	if (!hotplug) {
+		hf_init_crc8();
+		hf_init_crc32();
+	}
 	usb_detect(&hashfast_drv, hashfast_detect_one_usb);
 }
 
@@ -328,7 +333,7 @@ static void hashfast_shutdown(struct thr_info __maybe_unused *thr)
 }
 
 struct device_drv hashfast_drv = {
-	.drv_id = DRIVER_HASHFAST,
+	.drv_id = DRIVER_hashfast,
 	.dname = "Hashfast",
 	.name = "HFA",
 	.drv_detect = hashfast_detect,

+ 67 - 36
driver-icarus.c

@@ -74,6 +74,7 @@ ASSERT1(sizeof(uint32_t) == 4);
 
 // USB ms timeout to wait - user specified timeouts are multiples of this
 #define ICARUS_WAIT_TIMEOUT 100
+#define ICARUS_CMR2_TIMEOUT 1
 
 // Defined in multiples of ICARUS_WAIT_TIMEOUT
 // Must of course be greater than ICARUS_READ_COUNT_TIMING/ICARUS_WAIT_TIMEOUT
@@ -177,6 +178,8 @@ static const char *MODE_VALUE_STR = "value";
 static const char *MODE_UNKNOWN_STR = "unknown";
 
 struct ICARUS_INFO {
+	int intinfo;
+
 	// time to calculate the golden_ob
 	uint64_t golden_hashes;
 	struct timeval golden_tv;
@@ -184,6 +187,8 @@ struct ICARUS_INFO {
 	struct ICARUS_HISTORY history[INFO_HISTORY+1];
 	uint32_t min_data_count;
 
+	int timeout;
+
 	// seconds per Hash
 	double Hs;
 	// ms til we abort
@@ -233,8 +238,6 @@ struct ICARUS_INFO {
 //
 static int option_offset = -1;
 
-struct device_drv icarus_drv;
-
 /*
 #define ICA_BUFSIZ (0x200)
 
@@ -277,7 +280,7 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
 	usb_set_cps(icarus, baud / 10);
 	usb_enable_cps(icarus);
 
-	interface = usb_interface(icarus);
+	interface = _usb_interface(icarus, info->intinfo);
 	ident = usb_ident(icarus);
 
 	switch (ident) {
@@ -287,9 +290,6 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
 		case IDENT_CMR2:
 			usb_set_pps(icarus, BLT_PREF_PACKET);
 
-			if (ident == IDENT_CMR2) // Chip hack
-				interface++;
-
 			// Reset
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET,
 				 interface, C_RESET);
@@ -298,7 +298,7 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
 				return;
 
 			// Latency
-			usb_ftdi_set_latency(icarus);
+			_usb_ftdi_set_latency(icarus, info->intinfo);
 
 			if (icarus->usbinfo.nodev)
 				return;
@@ -434,9 +434,10 @@ static void rev(unsigned char *s, size_t l)
 
 static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct timeval *tv_start, struct timeval *tv_finish, struct thr_info *thr, int read_time)
 {
+	struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data);
 	struct timeval read_start, read_finish;
 	int err, amt;
-	int rc = 0;
+	int rc = 0, delay;
 	int read_amount = ICARUS_READ_SIZE;
 	bool first = true;
 
@@ -446,7 +447,9 @@ static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct
 			return ICA_NONCE_ERROR;
 
 		cgtime(&read_start);
-		err = usb_read_timeout(icarus, (char *)buf, read_amount, &amt, ICARUS_WAIT_TIMEOUT, C_GETRESULTS);
+		err = usb_read_ii_timeout(icarus, info->intinfo,
+					  (char *)buf, read_amount, &amt,
+					  info->timeout, C_GETRESULTS);
 		cgtime(&read_finish);
 		if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
 			applog(LOG_ERR, "%s%i: Comms error (rerr=%d amt=%d)",
@@ -471,10 +474,7 @@ static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct
 		}
 
 		if (thr && thr->work_restart) {
-			if (opt_debug) {
-				applog(LOG_DEBUG,
-					"Icarus Read: Work restart at %d ms", rc);
-			}
+			applog(LOG_DEBUG, "Icarus Read: Work restart at %d ms", rc);
 			return ICA_NONCE_RESTART;
 		}
 
@@ -483,6 +483,18 @@ static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct
 			read_amount -= amt;
 			first = false;
 		}
+
+		if (info->timeout < ICARUS_WAIT_TIMEOUT) {
+			delay = ICARUS_WAIT_TIMEOUT - rc;
+			if (delay > 0) {
+				cgsleep_ms(delay);
+
+				if (thr && thr->work_restart) {
+					applog(LOG_DEBUG, "Icarus Read: Work restart at %d ms", rc);
+					return ICA_NONCE_RESTART;
+				}
+			}
+		}
 	}
 }
 
@@ -796,6 +808,7 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
 	int baud, uninitialised_var(work_division), uninitialised_var(fpga_count);
 	struct cgpu_info *icarus;
 	int ret, err, amount, tries;
+	enum sub_ident ident;
 	bool ok;
 
 	icarus = usb_alloc_cgpu(&icarus_drv, 1);
@@ -814,6 +827,23 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
 		quit(1, "Failed to malloc ICARUS_INFO");
 	icarus->device_data = (void *)info;
 
+	ident = usb_ident(icarus);
+	switch (ident) {
+		case IDENT_ICA:
+		case IDENT_BLT:
+		case IDENT_LLT:
+		case IDENT_AMU:
+		case IDENT_CMR1:
+			info->timeout = ICARUS_WAIT_TIMEOUT;
+			break;
+		case IDENT_CMR2:
+			info->timeout = ICARUS_CMR2_TIMEOUT;
+			break;
+		default:
+			quit(1, "%s icarus_detect_one() invalid %s ident=%d",
+				icarus->drv->dname, icarus->drv->dname, ident);
+	}
+
 	tries = 2;
 	ok = false;
 	while (!ok && tries-- > 0) {
@@ -879,7 +909,7 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
 			struct cgpu_info *cgtmp;
 			struct ICARUS_INFO *intmp;
 
-			cgtmp = usb_init_intinfo(icarus, i);
+			cgtmp = usb_copy_cgpu(icarus);
 			if (!cgtmp) {
 				applog(LOG_ERR, "%s%d: Init failed initinfo %d",
 						icarus->drv->name, icarus->device_id, i);
@@ -888,13 +918,6 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
 
 			cgtmp->usbinfo.usbstat = USB_NOSTAT;
 
-			if (!add_cgpu(cgtmp)) {
-				usb_uninit(cgtmp);
-				continue;
-			}
-
-			update_usb_stats(cgtmp);
-
 			intmp = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO));
 			if (unlikely(!intmp))
 				quit(1, "Failed2 to malloc ICARUS_INFO");
@@ -903,6 +926,18 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
 
 			// Initialise everything to match
 			memcpy(intmp, info, sizeof(struct ICARUS_INFO));
+
+			intmp->intinfo = i;
+
+			icarus_initialise(cgtmp, baud);
+
+			if (!add_cgpu(cgtmp)) {
+				usb_uninit(cgtmp);
+				free(intmp);
+				continue;
+			}
+
+			update_usb_stats(cgtmp);
 		}
 	}
 
@@ -921,7 +956,7 @@ shin:
 	return false;
 }
 
-static void icarus_detect()
+static void icarus_detect(bool __maybe_unused hotplug)
 {
 	usb_detect(&icarus_drv, icarus_detect_one);
 }
@@ -976,7 +1011,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	// We only want results for the work we are about to send
 	usb_buffer_clear(icarus);
 
-	err = usb_write(icarus, (char *)ob_bin, sizeof(ob_bin), &amount, C_SENDWORK);
+	err = usb_write_ii(icarus, info->intinfo, (char *)ob_bin, sizeof(ob_bin), &amount, C_SENDWORK);
 	if (err < 0 || amount != sizeof(ob_bin)) {
 		applog(LOG_ERR, "%s%i: Comms error (werr=%d amt=%d)",
 				icarus->drv->name, icarus->device_id, err, amount);
@@ -1014,12 +1049,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		if (unlikely(estimate_hashes > 0xffffffff))
 			estimate_hashes = 0xffffffff;
 
-		if (opt_debug) {
-			applog(LOG_DEBUG, "%s%d: no nonce = 0x%08lX hashes (%ld.%06lds)",
-					icarus->drv->name, icarus->device_id,
-					(long unsigned int)estimate_hashes,
-					elapsed.tv_sec, elapsed.tv_usec);
-		}
+		applog(LOG_DEBUG, "%s%d: no nonce = 0x%08lX hashes (%ld.%06lds)",
+				icarus->drv->name, icarus->device_id,
+				(long unsigned int)estimate_hashes,
+				elapsed.tv_sec, elapsed.tv_usec);
 
 		return estimate_hashes;
 	}
@@ -1051,12 +1084,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	if (opt_debug || info->do_icarus_timing)
 		timersub(&tv_finish, &tv_start, &elapsed);
 
-	if (opt_debug) {
-		applog(LOG_DEBUG, "%s%d: nonce = 0x%08x = 0x%08lX hashes (%ld.%06lds)",
-				icarus->drv->name, icarus->device_id,
-				nonce, (long unsigned int)hash_count,
-				elapsed.tv_sec, elapsed.tv_usec);
-	}
+	applog(LOG_DEBUG, "%s%d: nonce = 0x%08x = 0x%08lX hashes (%ld.%06lds)",
+			icarus->drv->name, icarus->device_id,
+			nonce, (long unsigned int)hash_count,
+			elapsed.tv_sec, elapsed.tv_usec);
 
 	// Ignore possible end condition values ... and hw errors
 	// TODO: set limitations on calculated values depending on the device
@@ -1203,7 +1234,7 @@ static void icarus_shutdown(__maybe_unused struct thr_info *thr)
 }
 
 struct device_drv icarus_drv = {
-	.drv_id = DRIVER_ICARUS,
+	.drv_id = DRIVER_icarus,
 	.dname = "Icarus",
 	.name = "ICA",
 	.drv_detect = icarus_detect,

+ 2 - 4
driver-modminer.c

@@ -87,8 +87,6 @@
 // Limit when reducing shares_to_good
 #define MODMINER_MIN_BACK 12
 
-struct device_drv modminer_drv;
-
 // 45 noops sent when detecting, in case the device was left in "start job" reading
 static const char NOOP[] = MODMINER_PING "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
 
@@ -239,7 +237,7 @@ shin:
 		return false;
 }
 
-static void modminer_detect()
+static void modminer_detect(bool __maybe_unused hotplug)
 {
 	usb_detect(&modminer_drv, modminer_detect_one);
 }
@@ -1132,7 +1130,7 @@ static char *modminer_set_device(struct cgpu_info *modminer, char *option, char
 }
 
 struct device_drv modminer_drv = {
-	.drv_id = DRIVER_MODMINER,
+	.drv_id = DRIVER_modminer,
 	.dname = "ModMiner",
 	.name = "MMQ",
 	.drv_detect = modminer_detect,

+ 9 - 11
driver-opencl.c

@@ -56,10 +56,6 @@ extern void decay_time(double *f, double fadd);
 
 /**********************************************/
 
-#ifdef HAVE_OPENCL
-struct device_drv opencl_drv;
-#endif
-
 #ifdef HAVE_ADL
 extern float gpu_temp(int gpu);
 extern int gpu_fanspeed(int gpu);
@@ -585,7 +581,7 @@ char *set_intensity(char *arg)
 void print_ndevs(int *ndevs)
 {
 	opt_log_output = true;
-	opencl_drv.drv_detect();
+	opencl_drv.drv_detect(false);
 	clear_adl(*ndevs);
 	applog(LOG_INFO, "%i GPU devices max detected", *ndevs);
 }
@@ -753,7 +749,7 @@ retry:
 		for (i = 0; i < mining_threads; ++i) {
 			thr = get_thread(i);
 			cgpu = thr->cgpu;
-			if (cgpu->drv->drv_id != DRIVER_OPENCL)
+			if (cgpu->drv->drv_id != DRIVER_opencl)
 				continue;
 			if (dev_from_id(i) != selected)
 				continue;
@@ -1148,7 +1144,7 @@ select_cgpu:
 	for (thr_id = 0; thr_id < mining_threads; ++thr_id) {
 		thr = get_thread(thr_id);
 		cgpu = thr->cgpu;
-		if (cgpu->drv->drv_id != DRIVER_OPENCL)
+		if (cgpu->drv->drv_id != DRIVER_opencl)
 			continue;
 		if (dev_from_id(thr_id) != gpu)
 			continue;
@@ -1173,7 +1169,7 @@ select_cgpu:
 
 		thr = get_thread(thr_id);
 		cgpu = thr->cgpu;
-		if (cgpu->drv->drv_id != DRIVER_OPENCL)
+		if (cgpu->drv->drv_id != DRIVER_opencl)
 			continue;
 		if (dev_from_id(thr_id) != gpu)
 			continue;
@@ -1210,7 +1206,7 @@ select_cgpu:
 	for (thr_id = 0; thr_id < mining_threads; ++thr_id) {
 		thr = get_thread(thr_id);
 		cgpu = thr->cgpu;
-		if (cgpu->drv->drv_id != DRIVER_OPENCL)
+		if (cgpu->drv->drv_id != DRIVER_opencl)
 			continue;
 		if (dev_from_id(thr_id) != gpu)
 			continue;
@@ -1231,10 +1227,12 @@ void *reinit_gpu(__maybe_unused void *userdata)
 
 
 #ifdef HAVE_OPENCL
-static void opencl_detect()
+static void opencl_detect(bool hotplug)
 {
 	int i;
 
+	if (opt_nogpu || hotplug)
+		return;
 	nDevs = clDevicesNum();
 	if (nDevs < 0) {
 		applog(LOG_ERR, "clDevicesNum returned error, no GPUs usable");
@@ -1575,7 +1573,7 @@ static void opencl_thread_shutdown(struct thr_info *thr)
 }
 
 struct device_drv opencl_drv = {
-	.drv_id = DRIVER_OPENCL,
+	.drv_id = DRIVER_opencl,
 	.dname = "opencl",
 	.name = "GPU",
 	.drv_detect = opencl_detect,

+ 2 - 4
driver-ztex.c

@@ -31,8 +31,6 @@
 
 #define GOLDEN_BACKLOG 5
 
-struct device_drv ztex_drv;
-
 // Forward declarations
 static void ztex_disable(struct thr_info* thr);
 static bool ztex_prepare(struct thr_info *thr);
@@ -54,7 +52,7 @@ static void ztex_releaseFpga(struct libztex_device* ztex)
 	}
 }
 
-static void ztex_detect(void)
+static void ztex_detect(bool __maybe_unused hotplug)
 {
 	int cnt;
 	int i,j;
@@ -413,7 +411,7 @@ static void ztex_disable(struct thr_info *thr)
 }
 
 struct device_drv ztex_drv = {
-	.drv_id = DRIVER_ZTEX,
+	.drv_id = DRIVER_ztex,
 	.dname = "ztex",
 	.name = "ZTX",
 	.drv_detect = ztex_detect,

+ 44 - 12
miner.h

@@ -230,18 +230,39 @@ static inline int fsync (int fd)
 #define MIN(x, y)	((x) > (y) ? (y) : (x))
 #define MAX(x, y)	((x) > (y) ? (x) : (y))
 
+/* Put avalon last to make it the last device it tries to detect to prevent it
+ * trying to claim same chip but different devices. Adding a device here will
+ * update all macros in the code that use the *_PARSE_COMMANDS macros for each
+ * listed driver. */
+#define FPGA_PARSE_COMMANDS(DRIVER_ADD_COMMAND) \
+	DRIVER_ADD_COMMAND(bitforce) \
+	DRIVER_ADD_COMMAND(icarus) \
+	DRIVER_ADD_COMMAND(modminer) \
+	DRIVER_ADD_COMMAND(ztex)
+
+#define ASIC_PARSE_COMMANDS(DRIVER_ADD_COMMAND) \
+	DRIVER_ADD_COMMAND(bflsc) \
+	DRIVER_ADD_COMMAND(bitfury) \
+	DRIVER_ADD_COMMAND(hashfast) \
+	DRIVER_ADD_COMMAND(avalon)
+
+#define DRIVER_PARSE_COMMANDS(DRIVER_ADD_COMMAND) \
+	DRIVER_ADD_COMMAND(opencl) \
+	FPGA_PARSE_COMMANDS(DRIVER_ADD_COMMAND) \
+	ASIC_PARSE_COMMANDS(DRIVER_ADD_COMMAND)
+
+#define DRIVER_ENUM(X) DRIVER_##X,
+#define DRIVER_PROTOTYPE(X) struct device_drv X##_drv;
+
+/* Create drv_driver enum from DRIVER_PARSE_COMMANDS macro */
 enum drv_driver {
-	DRIVER_OPENCL = 0,
-	DRIVER_ICARUS,
-	DRIVER_BITFORCE,
-	DRIVER_MODMINER,
-	DRIVER_ZTEX,
-	DRIVER_BFLSC,
-	DRIVER_AVALON,
-	DRIVER_HASHFAST,
+	DRIVER_PARSE_COMMANDS(DRIVER_ENUM)
 	DRIVER_MAX
 };
 
+/* Use DRIVER_PARSE_COMMANDS to generate extern device_drv prototypes */
+DRIVER_PARSE_COMMANDS(DRIVER_PROTOTYPE)
+
 enum alive {
 	LIFE_WELL,
 	LIFE_SICK,
@@ -318,7 +339,7 @@ struct device_drv {
 	char *name;
 
 	// DRV-global functions
-	void (*drv_detect)();
+	void (*drv_detect)(bool);
 
 	// Device-specific functions
 	void (*reinit_device)(struct cgpu_info *);
@@ -823,7 +844,7 @@ static inline void cglock_init(cglock_t *lock)
 	rwlock_init(&lock->rwlock);
 }
 
-/* Read lock variant of cglock */
+/* Read lock variant of cglock. Cannot be promoted. */
 static inline void cg_rlock(cglock_t *lock)
 {
 	mutex_lock(&lock->mutex);
@@ -831,7 +852,8 @@ static inline void cg_rlock(cglock_t *lock)
 	mutex_unlock_noyield(&lock->mutex);
 }
 
-/* Intermediate variant of cglock */
+/* Intermediate variant of cglock - behaves as a read lock but can be promoted
+ * to a write lock or demoted to read lock. */
 static inline void cg_ilock(cglock_t *lock)
 {
 	mutex_lock(&lock->mutex);
@@ -858,6 +880,12 @@ static inline void cg_dwlock(cglock_t *lock)
 	mutex_unlock_noyield(&lock->mutex);
 }
 
+/* Demote a write variant to an intermediate variant */
+static inline void cg_dwilock(cglock_t *lock)
+{
+	wr_unlock(&lock->rwlock);
+}
+
 /* Downgrade intermediate variant to a read lock */
 static inline void cg_dlock(cglock_t *lock)
 {
@@ -872,7 +900,7 @@ static inline void cg_runlock(cglock_t *lock)
 
 static inline void cg_wunlock(cglock_t *lock)
 {
-	wr_unlock(&lock->rwlock);
+	wr_unlock_noyield(&lock->rwlock);
 	mutex_unlock(&lock->mutex);
 }
 
@@ -903,6 +931,7 @@ extern bool opt_api_listen;
 extern bool opt_api_network;
 extern bool opt_delaynet;
 extern bool opt_restart;
+extern bool opt_nogpu;
 extern char *opt_icarus_options;
 extern char *opt_icarus_timing;
 extern bool opt_worktime;
@@ -1263,6 +1292,7 @@ struct work {
 #endif
 	double		device_diff;
 	uint64_t	share_diff;
+	unsigned char	hash2[32];
 
 	int		rolls;
 
@@ -1356,6 +1386,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);

File diff suppressed because it is too large
+ 176 - 395
usbutils.c


+ 64 - 28
usbutils.h

@@ -109,6 +109,9 @@
 // Use the device defined timeout
 #define DEVTIMEOUT 0
 
+// The default intinfo structure used is the first one
+#define DEFAULT_INTINFO 0
+
 // For endpoints defined in usb_find_devices.intinfos.epinfos,
 // the first two must be the default IN and OUT and both must always exist
 #define DEFAULT_EP_IN 0
@@ -118,11 +121,14 @@ struct usb_epinfo {
 	uint8_t att;
 	uint16_t size;
 	unsigned char ep;
+	uint16_t wMaxPacketSize;
+	uint16_t PrefPacketSize;
 	bool found;
 };
 
 struct usb_intinfo {
 	int interface;
+	int ctrl_transfer;
 	int epinfo_count;
 	struct usb_epinfo *epinfos;
 };
@@ -134,6 +140,7 @@ enum sub_ident {
 	IDENT_BAS,
 	IDENT_BAM,
 	IDENT_BFL,
+	IDENT_BFU,
 	IDENT_MMQ,
 	IDENT_AVA,
 	IDENT_BTB,
@@ -157,9 +164,7 @@ struct usb_find_devices {
 	char *iProduct;
 	int config;
 	unsigned int timeout;
-	uint16_t wMaxPacketSize;
 	uint16_t latency;
-	int which_intinfo;
 	int intinfo_count;
 	struct usb_intinfo *intinfos;
 };
@@ -193,7 +198,6 @@ struct cg_usb_device {
 	char *buffer;
 	uint32_t bufsiz;
 	uint32_t bufamt;
-	uint16_t PrefPacketSize;
 	cgtimer_t cgt_last_write;
 	size_t last_write_siz;
 };
@@ -234,7 +238,7 @@ struct cg_usb_info {
 	 * that uses the lock - however, all usbutils code MUST use it
 	 * to avoid devices disappearing while in use by multiple threads
 	 */
-	pthread_rwlock_t *devlock;
+	pthread_mutex_t *devlock;
 
 	time_t last_pipe;
 	uint64_t pipe_count;
@@ -258,7 +262,10 @@ struct cg_usb_info {
 	struct cg_usb_tmo usb_tmo[USB_TMOS];
 };
 
-#define USB_PARSE_COMMANDS \
+#define ENUMERATION(a,b) a,
+#define JUMPTABLE(a,b) b,
+
+#define USB_PARSE_COMMANDS(USB_ADD_COMMAND) \
 	USB_ADD_COMMAND(C_REJECTED, "RejectedNoDevice") \
 	USB_ADD_COMMAND(C_PING, "Ping") \
 	USB_ADD_COMMAND(C_CLEAR, "Clear") \
@@ -322,6 +329,20 @@ 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_BF1_RESET, "BF1Reset") \
+	USB_ADD_COMMAND(C_BF1_OPEN, "BF1Open") \
+	USB_ADD_COMMAND(C_BF1_INIT, "BF1Init") \
+	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") \
+	USB_ADD_COMMAND(C_BF1_FLUSH, "BF1Flush") \
+	USB_ADD_COMMAND(C_BF1_IFLUSH, "BF1InterruptFlush") \
+	USB_ADD_COMMAND(C_BF1_IDENTIFY, "BF1Identify") \
 	USB_ADD_COMMAND(C_HF_RESET, "HFReset") \
 	USB_ADD_COMMAND(C_HF_PLL_CONFIG, "HFPLLConfig") \
 	USB_ADD_COMMAND(C_HF_ADDRESS, "HFAddress") \
@@ -335,12 +356,10 @@ struct cg_usb_info {
 	USB_ADD_COMMAND(C_HF_CLOCKGATE, "HFClockGate")
 
 /* Create usb_cmds enum from USB_PARSE_COMMANDS macro */
-#define USB_ADD_COMMAND(X, Y) X,
 enum usb_cmds {
-	USB_PARSE_COMMANDS
+	USB_PARSE_COMMANDS(ENUMERATION)
 	C_MAX
 };
-#undef USB_ADD_COMMAND
 
 struct device_drv;
 struct cgpu_info;
@@ -353,17 +372,17 @@ struct cgpu_info *usb_alloc_cgpu(struct device_drv *drv, int threads);
 struct cgpu_info *usb_free_cgpu_devlock(struct cgpu_info *cgpu, bool free_devlock);
 #define usb_free_cgpu(cgpu) usb_free_cgpu_devlock(cgpu, true)
 void usb_uninit(struct cgpu_info *cgpu);
-struct cgpu_info *usb_init_intinfo(struct cgpu_info *orig,  int intinfo);
 bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found);
 void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *));
 struct api_data *api_usb_stats(int *count);
 void update_usb_stats(struct cgpu_info *cgpu);
-int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, enum usb_cmds cmd, bool readonce);
-int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds);
+int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, enum usb_cmds cmd, bool readonce);
+int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds);
 int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint32_t *data, int siz, unsigned int timeout, enum usb_cmds cmd);
 int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, char *buf, int bufsiz, int *amount, unsigned int timeout, enum usb_cmds cmd);
 int usb_ftdi_cts(struct cgpu_info *cgpu);
-int usb_ftdi_set_latency(struct cgpu_info *cgpu);
+int _usb_ftdi_set_latency(struct cgpu_info *cgpu, int intinfo);
+#define usb_ftdi_set_latency(_cgpu) _usb_ftdi_set_latency(_cgpu, DEFAULT_INTINFO)
 void usb_buffer_enable(struct cgpu_info *cgpu);
 void usb_buffer_disable(struct cgpu_info *cgpu);
 void usb_buffer_clear(struct cgpu_info *cgpu);
@@ -371,55 +390,72 @@ uint32_t usb_buffer_size(struct cgpu_info *cgpu);
 void usb_set_cps(struct cgpu_info *cgpu, int cps);
 void usb_enable_cps(struct cgpu_info *cgpu);
 void usb_disable_cps(struct cgpu_info *cgpu);
-int usb_interface(struct cgpu_info *cgpu);
+int _usb_interface(struct cgpu_info *cgpu, int intinfo);
+#define usb_interface(_cgpu) _usb_interface(_cgpu, DEFAULT_INTINFO)
 enum sub_ident usb_ident(struct cgpu_info *cgpu);
-void usb_set_pps(struct cgpu_info *cgpu, uint16_t PrefPacketSize);
+void _usb_set_pps(struct cgpu_info *cgpu, int intinfo, int epinfo, uint16_t PrefPacketSize);
+#define usb_set_pps(_cgpu, _pps) _usb_set_pps(_cgpu, -1, -1, _pps)
 void usb_set_dev_start(struct cgpu_info *cgpu);
 void usb_cleanup();
 void usb_initialise();
 void *usb_resource_thread(void *userdata);
 
 #define usb_read(cgpu, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)
+
+#define usb_read_ii(cgpu, intinfo, buf, bufsiz, read, cmd) \
+	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)
 
 #define usb_read_once(cgpu, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true)
+
+#define usb_read_ii_once(cgpu, intinfo, buf, bufsiz, read, cmd) \
+	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true)
 
 #define usb_read_once_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true)
+
+#define usb_read_ii_once_timeout(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \
+	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true)
 
 #define usb_read_nl(cgpu, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "\n", cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "\n", cmd, false)
 
 #define usb_read_nl_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "\n", cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "\n", cmd, false)
 
 #define usb_read_ok(cgpu, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "OK\n", cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "OK\n", cmd, false)
 
 #define usb_read_ok_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "OK\n", cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "OK\n", cmd, false)
 
 #define usb_read_ep(cgpu, ep, buf, bufsiz, read, cmd) \
-	_usb_read(cgpu, ep, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)
 
 #define usb_read_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false)
+
+#define usb_read_ii_timeout(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \
+	_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false)
 
 #define usb_read_ep_timeout(cgpu, ep, buf, bufsiz, read, timeout, cmd) \
-	_usb_read(cgpu, ep, buf, bufsiz, read, timeout, NULL, cmd, false)
+	_usb_read(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, read, timeout, NULL, cmd, false)
 
 #define usb_write(cgpu, buf, bufsiz, wrote, cmd) \
-	_usb_write(cgpu, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
+	_usb_write(cgpu, DEFAULT_INTINFO, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
+
+#define usb_write_ii(cgpu, intinfo, buf, bufsiz, wrote, cmd) \
+	_usb_write(cgpu, intinfo, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
 
 #define usb_write_ep(cgpu, ep, buf, bufsiz, wrote, cmd) \
-	_usb_write(cgpu, ep, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
+	_usb_write(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
 
 #define usb_write_timeout(cgpu, buf, bufsiz, wrote, timeout, cmd) \
-	_usb_write(cgpu, DEFAULT_EP_OUT, buf, bufsiz, wrote, timeout, cmd)
+	_usb_write(cgpu, DEFAULT_INTINFO, DEFAULT_EP_OUT, buf, bufsiz, wrote, timeout, cmd)
 
 #define usb_write_ep_timeout(cgpu, ep, buf, bufsiz, wrote, timeout, cmd) \
-	_usb_write(cgpu, ep, buf, bufsiz, wrote, timeout, cmd)
+	_usb_write(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, wrote, timeout, cmd)
 
 #define usb_transfer(cgpu, typ, req, val, idx, cmd) \
 	_usb_transfer(cgpu, typ, req, val, idx, NULL, 0, DEVTIMEOUT, cmd)

+ 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

@@ -99,6 +99,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);

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