Browse Source

Merge branch 'uniscan2' into bfgminer

Luke Dashjr 12 years ago
parent
commit
6e956186e6
24 changed files with 376 additions and 199 deletions
  1. 21 5
      deviceapi.c
  2. 6 0
      deviceapi.h
  3. 5 3
      driver-avalon.c
  4. 12 10
      driver-bigpic.c
  5. 12 8
      driver-bitforce.c
  6. 12 9
      driver-cairnsmore.c
  7. 26 15
      driver-erupter.c
  8. 10 18
      driver-hashbuster.c
  9. 4 3
      driver-icarus.c
  10. 11 28
      driver-klondike.c
  11. 11 9
      driver-littlefury.c
  12. 12 10
      driver-modminer.c
  13. 10 18
      driver-nanofury.c
  14. 11 18
      driver-x6500.c
  15. 9 17
      driver-ztex.c
  16. 16 3
      fpgautils.c
  17. 5 2
      fpgautils.h
  18. 36 19
      lowlevel.c
  19. 12 1
      lowlevel.h
  20. 1 1
      mcp2210.c
  21. 1 1
      mcp2210.h
  22. 117 1
      miner.c
  23. 3 0
      miner.h
  24. 13 0
      util.c

+ 21 - 5
deviceapi.c

@@ -708,7 +708,10 @@ out: ;
 	return NULL;
 }
 
-bool add_cgpu(struct cgpu_info *cgpu)
+static pthread_mutex_t _add_cgpu_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static
+bool _add_cgpu(struct cgpu_info *cgpu)
 {
 	int lpcount;
 	
@@ -780,6 +783,14 @@ bool add_cgpu(struct cgpu_info *cgpu)
 	return true;
 }
 
+bool add_cgpu(struct cgpu_info *cgpu)
+{
+	mutex_lock(&_add_cgpu_mutex);
+	const bool rv = _add_cgpu(cgpu);
+	mutex_unlock(&_add_cgpu_mutex);
+	return rv;
+}
+
 void add_cgpu_live(void *p)
 {
 	add_cgpu(p);
@@ -787,19 +798,24 @@ void add_cgpu_live(void *p)
 
 bool add_cgpu_slave(struct cgpu_info *cgpu, struct cgpu_info *prev_cgpu)
 {
-	int old_total_devices = total_devices_new;
-	
 	if (!prev_cgpu)
 		return add_cgpu(cgpu);
 	
 	while (prev_cgpu->next_proc)
 		prev_cgpu = prev_cgpu->next_proc;
 	
-	if (!add_cgpu(cgpu))
-		return false;
+	mutex_lock(&_add_cgpu_mutex);
 	
+	int old_total_devices = total_devices_new;
+	if (!_add_cgpu(cgpu))
+	{
+		mutex_unlock(&_add_cgpu_mutex);
+		return false;
+	}
 	prev_cgpu->next_proc = devices_new[old_total_devices];
 	
+	mutex_unlock(&_add_cgpu_mutex);
+	
 	return true;
 }
 

+ 6 - 0
deviceapi.h

@@ -5,6 +5,8 @@
 #include <stdint.h>
 #include <sys/time.h>
 
+#include <uthash.h>
+
 #include "miner.h"
 
 struct driver_registration;
@@ -20,6 +22,10 @@ extern struct driver_registration *_bfg_drvreg1;
 extern struct driver_registration *_bfg_drvreg2;
 extern void bfg_devapi_init();
 
+#define BFG_FIND_DRV_BY_DNAME(reg, name, namelen)  \
+	HASH_FIND(hh , _bfg_drvreg1, name, namelen, reg)
+#define BFG_FIND_DRV_BY_NAME(reg, name, namelen)  \
+	HASH_FIND(hh2, _bfg_drvreg2, name, namelen, reg)
 #define BFG_FOREACH_DRIVER_BY_DNAME(reg, tmp)  \
 	HASH_ITER(hh , _bfg_drvreg1, reg, tmp)
 #define BFG_FOREACH_DRIVER_BY_PRIORITY(reg, tmp)  \

+ 5 - 3
driver-avalon.c

@@ -40,6 +40,7 @@
 #include "fpgautils.h"
 #include "driver-avalon.h"
 #include "logging.h"
+#include "lowlevel.h"
 #include "util.h"
 
 BFG_REGISTER_DRIVER(avalon_drv)
@@ -629,9 +630,10 @@ static bool avalon_detect_one(const char *devpath)
 	return true;
 }
 
-static inline void avalon_detect()
+static
+bool avalon_lowl_probe(const struct lowlevel_device_info * const info)
 {
-	serial_detect_byname(&avalon_drv, avalon_detect_one);
+	return vcom_lowl_probe_wrapper(info, avalon_detect_one);
 }
 
 static void __avalon_init(struct cgpu_info *avalon)
@@ -1015,7 +1017,7 @@ static void avalon_shutdown(struct thr_info *thr)
 struct device_drv avalon_drv = {
 	.dname = "avalon",
 	.name = "AVA",
-	.drv_detect = avalon_detect,
+	.lowl_probe = avalon_lowl_probe,
 	.thread_prepare = avalon_prepare,
 	.minerloop = hash_queued_work,
 	.queue_full = avalon_fill,

+ 12 - 10
driver-bigpic.c

@@ -22,6 +22,7 @@
 #include "logging.h"
 
 #include "libbitfury.h"
+#include "lowlevel.h"
 #include "deviceapi.h"
 #include "sha2.h"
 
@@ -31,6 +32,12 @@
 
 BFG_REGISTER_DRIVER(bigpic_drv)
 
+static
+bool bigpic_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_vcom, "Bitfury", "BF1");
+}
+
 //------------------------------------------------------------------------------
 static bool bigpic_detect_custom(const char *devpath, struct device_drv *api, struct bigpic_info *info)
 {
@@ -131,16 +138,10 @@ static bool bigpic_detect_one(const char *devpath)
 	return true;
 }
 
-//------------------------------------------------------------------------------
-static int bigpic_detect_auto(void)
-{
-	return serial_autodetect(bigpic_detect_one, "Bitfury", "BF1");
-}
-
-//------------------------------------------------------------------------------
-static void bigpic_detect()
+static
+bool bigpic_lowl_probe(const struct lowlevel_device_info * const info)
 {
-	serial_detect_auto(&bigpic_drv, bigpic_detect_one, bigpic_detect_auto);
+	return vcom_lowl_probe_wrapper(info, bigpic_detect_one);
 }
 
 //------------------------------------------------------------------------------
@@ -318,7 +319,8 @@ struct device_drv bigpic_drv = {
 	.name = "BPM",
 	.probe_priority = -110,
 
-	.drv_detect = bigpic_detect,
+	.lowl_match = bigpic_lowl_match,
+	.lowl_probe = bigpic_lowl_probe,
 
 	.identify_device = bigpic_identify,
 

+ 12 - 8
driver-bitforce.c

@@ -24,6 +24,7 @@
 #include "deviceapi.h"
 #include "miner.h"
 #include "fpgautils.h"
+#include "lowlevel.h"
 #include "util.h"
 
 #define BITFORCE_SLEEP_MS 500
@@ -165,6 +166,12 @@ int bitforce_chips_to_plan_for(int parallel, int chipcount) {
 	                    return  1;
 }
 
+static
+bool bitforce_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_vcom, "BitFORCE", "SHA256");
+}
+
 static bool bitforce_detect_one(const char *devpath)
 {
 	int fdDev = serial_open(devpath, 0, 10, true);
@@ -314,14 +321,10 @@ static bool bitforce_detect_one(const char *devpath)
 	return add_cgpu(bitforce);
 }
 
-static int bitforce_detect_auto(void)
-{
-	return serial_autodetect(bitforce_detect_one, "BitFORCE", "SHA256");
-}
-
-static void bitforce_detect(void)
+static
+bool bitforce_lowl_probe(const struct lowlevel_device_info * const info)
 {
-	serial_detect_auto(&bitforce_drv, bitforce_detect_one, bitforce_detect_auto);
+	return vcom_lowl_probe_wrapper(info, bitforce_detect_one);
 }
 
 struct bitforce_data {
@@ -1589,7 +1592,8 @@ char *bitforce_set_device(struct cgpu_info *proc, char *option, char *setting, c
 struct device_drv bitforce_drv = {
 	.dname = "bitforce",
 	.name = "BFL",
-	.drv_detect = bitforce_detect,
+	.lowl_match = bitforce_lowl_match,
+	.lowl_probe = bitforce_lowl_probe,
 #ifdef HAVE_CURSES
 	.proc_wlogprint_status = bitforce_wlogprint_status,
 	.proc_tui_wlogprint_choices = bitforce_tui_wlogprint_choices,

+ 12 - 9
driver-cairnsmore.c

@@ -16,6 +16,7 @@
 #include "dynclock.h"
 #include "fpgautils.h"
 #include "icarus-common.h"
+#include "lowlevel.h"
 #include "miner.h"
 
 #define CAIRNSMORE1_IO_SPEED 115200
@@ -29,6 +30,12 @@
 
 BFG_REGISTER_DRIVER(cairnsmore_drv)
 
+static
+bool cairnsmore_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_vcom, "Cairnsmore1");
+}
+
 static bool cairnsmore_detect_one(const char *devpath)
 {
 	struct ICARUS_INFO *info = calloc(1, sizeof(struct ICARUS_INFO));
@@ -50,15 +57,10 @@ static bool cairnsmore_detect_one(const char *devpath)
 	return true;
 }
 
-static int cairnsmore_detect_auto(void)
-{
-	return serial_autodetect(cairnsmore_detect_one, "Cairnsmore1");
-}
-
-static void cairnsmore_detect()
+static
+bool cairnsmore_lowl_probe(const struct lowlevel_device_info * const info)
 {
-	// Actual serial detection is handled by Icarus driver
-	serial_detect_auto_byname(&cairnsmore_drv, cairnsmore_detect_one, cairnsmore_detect_auto);
+	return vcom_lowl_probe_wrapper(info, cairnsmore_detect_one);
 }
 
 static bool cairnsmore_send_cmd(int fd, uint8_t cmd, uint8_t data, bool probe)
@@ -204,7 +206,8 @@ static void cairnsmore_drv_init()
 	cairnsmore_drv = icarus_drv;
 	cairnsmore_drv.dname = "cairnsmore";
 	cairnsmore_drv.name = "ECM";
-	cairnsmore_drv.drv_detect = cairnsmore_detect;
+	cairnsmore_drv.lowl_match = cairnsmore_lowl_match;
+	cairnsmore_drv.lowl_probe = cairnsmore_lowl_probe;
 	cairnsmore_drv.thread_init = cairnsmore_init;
 	cairnsmore_drv.identify_device = cairnsmore_identify;
 	cairnsmore_drv.get_api_extra_device_status = cairnsmore_drv_extra_device_status;

+ 26 - 15
driver-erupter.c

@@ -14,6 +14,7 @@
 #include "miner.h"
 #include "fpgautils.h"
 #include "icarus-common.h"
+#include "lowlevel.h"
 
 #define ERUPTER_IO_SPEED 115200
 #define ERUPTER_HASH_TIME 0.0000000029761
@@ -41,12 +42,30 @@ static bool _erupter_detect_one(const char *devpath, struct device_drv *drv)
 	return true;
 }
 
+static
+bool erupter_emerald_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_vcom, "Block", "Erupter", "Emerald");
+}
+
 static bool erupter_emerald_detect_one(const char *devpath)
 {
 	// For detection via BEE:*
 	return _erupter_detect_one(devpath, &erupter_drv_emerald);
 }
 
+static
+bool erupter_emerald_lowl_probe(const struct lowlevel_device_info * const info)
+{
+	return vcom_lowl_probe_wrapper(info, erupter_emerald_detect_one);
+}
+
+static
+bool erupter_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_vcom, "Block", "Erupter");
+}
+
 static bool erupter_detect_one(const char *devpath)
 {
 	struct device_drv *drv = &erupter_drv;
@@ -58,21 +77,10 @@ static bool erupter_detect_one(const char *devpath)
 	return _erupter_detect_one(devpath, drv);
 }
 
-static int erupter_emerald_detect_auto(void)
-{
-	return serial_autodetect(erupter_emerald_detect_one, "Block", "Erupter", "Emerald");
-}
-
-static int erupter_detect_auto(void)
-{
-	return serial_autodetect(erupter_detect_one, "Block", "Erupter");
-}
-
-static void erupter_detect()
+static
+bool erupter_lowl_probe(const struct lowlevel_device_info * const info)
 {
-	// Actual serial detection is handled by Icarus driver
-	serial_detect_auto_byname(&erupter_drv, erupter_detect_one, erupter_detect_auto);
-	serial_detect_auto_byname(&erupter_drv_emerald, erupter_emerald_detect_one, erupter_emerald_detect_auto);
+	return vcom_lowl_probe_wrapper(info, erupter_detect_one);
 }
 
 static bool erupter_identify(struct cgpu_info *erupter)
@@ -88,12 +96,15 @@ static void erupter_drv_init()
 	erupter_drv = icarus_drv;
 	erupter_drv.dname = "erupter";
 	erupter_drv.name = "BES";
-	erupter_drv.drv_detect = erupter_detect;
+	erupter_drv.lowl_match = erupter_lowl_match;
+	erupter_drv.lowl_probe = erupter_lowl_probe;
 	erupter_drv.identify_device = erupter_identify;
 	++erupter_drv.probe_priority;
 	
 	erupter_drv_emerald = erupter_drv;
 	erupter_drv_emerald.name = "BEE";
+	erupter_drv.lowl_match = erupter_emerald_lowl_match;
+	erupter_drv.lowl_probe = erupter_emerald_lowl_probe;
 }
 
 struct device_drv erupter_drv = {

+ 10 - 18
driver-hashbuster.c

@@ -142,7 +142,13 @@ bool hashbuster_spi_txrx(struct spi_port * const port)
 }
 
 static
-bool hashbuster_foundlowl(struct lowlevel_device_info * const info, __maybe_unused void *userp)
+bool hashbuster_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_hid, HASHBUSTER_USB_PRODUCT);
+}
+
+static
+bool hashbuster_lowl_probe(const struct lowlevel_device_info * const info)
 {
 	const char * const product = info->product;
 	const char * const serial = info->serial;
@@ -185,7 +191,7 @@ bool hashbuster_foundlowl(struct lowlevel_device_info * const info, __maybe_unus
 	cgpu = malloc(sizeof(*cgpu));
 	*cgpu = (struct cgpu_info){
 		.drv = &hashbuster_drv,
-		.device_data = info,
+		.device_data = lowlevel_ref(info),
 		.threads = 1,
 		.procs = chip_n,
 		.device_path = strdup(info->path),
@@ -198,21 +204,6 @@ bool hashbuster_foundlowl(struct lowlevel_device_info * const info, __maybe_unus
 	return add_cgpu(cgpu);
 }
 
-static bool hashbuster_detect_one(const char *serial)
-{
-	return lowlevel_detect_serial(hashbuster_foundlowl, serial);
-}
-
-static int hashbuster_detect_auto()
-{
-	return lowlevel_detect(hashbuster_foundlowl, HASHBUSTER_USB_PRODUCT);
-}
-
-static void hashbuster_detect()
-{
-	serial_detect_auto(&hashbuster_drv, hashbuster_detect_one, hashbuster_detect_auto);
-}
-
 static
 bool hashbuster_init(struct thr_info * const thr)
 {
@@ -291,7 +282,8 @@ bool hashbuster_get_stats(struct cgpu_info * const cgpu)
 struct device_drv hashbuster_drv = {
 	.dname = "hashbuster",
 	.name = "HBR",
-	.drv_detect = hashbuster_detect,
+	.lowl_match = hashbuster_lowl_match,
+	.lowl_probe = hashbuster_lowl_probe,
 	
 	.thread_init = hashbuster_init,
 	.thread_disable = bitfury_disable,

+ 4 - 3
driver-icarus.c

@@ -675,9 +675,10 @@ static bool icarus_detect_one(const char *devpath)
 	return true;
 }
 
-static void icarus_detect()
+static
+bool icarus_lowl_probe(const struct lowlevel_device_info * const info)
 {
-	serial_detect(&icarus_drv, icarus_detect_one);
+	return vcom_lowl_probe_wrapper(info, icarus_detect_one);
 }
 
 static bool icarus_prepare(struct thr_info *thr)
@@ -1310,7 +1311,7 @@ struct device_drv icarus_drv = {
 	.dname = "icarus",
 	.name = "ICA",
 	.probe_priority = -120,
-	.drv_detect = icarus_detect,
+	.lowl_probe = icarus_lowl_probe,
 	.get_api_stats = icarus_drv_stats,
 	.thread_prepare = icarus_prepare,
 	.thread_init = icarus_init,

+ 11 - 28
driver-klondike.c

@@ -840,7 +840,15 @@ static void control_init(struct cgpu_info *klncgpu)
 }
 
 static
-bool klondike_foundlowl(struct lowlevel_device_info * const info, __maybe_unused void * const userp)
+bool klondike_lowl_match(const struct lowlevel_device_info * const info)
+{
+	if (!lowlevel_match_id(info, &lowl_usb, 0x04d8, 0xf60a))
+		return false;
+	return (info->manufacturer && strstr(info->manufacturer, "Klondike"));
+}
+
+static
+bool klondike_lowl_probe(const struct lowlevel_device_info * const info)
 {
 	if (unlikely(info->lowl != &lowl_usb))
 	{
@@ -926,32 +934,6 @@ bool klondike_foundlowl(struct lowlevel_device_info * const info, __maybe_unused
 	return false;
 }
 
-static
-bool klondike_detect_one(const char *serial)
-{
-	return lowlevel_detect_serial(klondike_foundlowl, serial);
-}
-
-static
-bool klondike_foundlowl_checkmanuf(struct lowlevel_device_info * const info, void * const userp)
-{
-	if (info->manufacturer && strstr(info->manufacturer, "Klondike"))
-		return klondike_foundlowl(info, userp);
-	return false;
-}
-
-static
-int klondike_autodetect()
-{
-	return lowlevel_detect_id(klondike_foundlowl_checkmanuf, NULL, &lowl_usb, 0x04d8, 0xf60a);
-}
-
-static
-void klondike_detect()
-{
-	generic_detect(&klondike_drv, klondike_detect_one, klondike_autodetect, 0);
-}
-
 static void klondike_check_nonce(struct cgpu_info *klncgpu, KLIST *kitem)
 {
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
@@ -1636,7 +1618,8 @@ static struct api_data *klondike_api_stats(struct cgpu_info *klncgpu)
 struct device_drv klondike_drv = {
 	.dname = "Klondike",
 	.name = "KLN",
-	.drv_detect = klondike_detect,
+	.lowl_match = klondike_lowl_match,
+	.lowl_probe = klondike_lowl_probe,
 	.get_api_stats = klondike_api_stats,
 	.get_stats = klondike_get_stats,
 	.thread_prepare = klondike_thread_prepare,

+ 11 - 9
driver-littlefury.c

@@ -19,6 +19,7 @@
 #include "fpgautils.h"
 #include "libbitfury.h"
 #include "logging.h"
+#include "lowlevel.h"
 #include "miner.h"
 #include "spidevc.h"
 #include "util.h"
@@ -222,6 +223,12 @@ bool littlefury_txrx(struct spi_port *port)
 	return true;
 }
 
+static
+bool littlefury_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_vcom, "LittleFury");
+}
+
 static
 bool littlefury_detect_one(const char *devpath)
 {
@@ -310,15 +317,9 @@ err:
 }
 
 static
-int littlefury_detect_auto(void)
-{
-	return serial_autodetect(littlefury_detect_one, "LittleFury");
-}
-
-static
-void littlefury_detect(void)
+bool littlefury_lowl_probe(const struct lowlevel_device_info * const info)
 {
-	serial_detect_auto(&littlefury_drv, littlefury_detect_one, littlefury_detect_auto);
+	return vcom_lowl_probe_wrapper(info, littlefury_detect_one);
 }
 
 static
@@ -470,7 +471,8 @@ void littlefury_reinit(struct cgpu_info * const proc)
 struct device_drv littlefury_drv = {
 	.dname = "littlefury",
 	.name = "LFY",
-	.drv_detect = littlefury_detect,
+	.lowl_match = littlefury_lowl_match,
+	.lowl_probe = littlefury_lowl_probe,
 	
 	.thread_init = littlefury_thread_init,
 	.thread_disable = littlefury_disable,

+ 12 - 10
driver-modminer.c

@@ -22,6 +22,7 @@
 #include "logging.h"
 #include "miner.h"
 #include "fpgautils.h"
+#include "lowlevel.h"
 #include "util.h"
 
 #define BITSTREAM_FILENAME "fpgaminer_x6500-overclocker-0402.bit"
@@ -100,6 +101,12 @@ _bailout(int fd, struct cgpu_info*modminer, int prio, const char *fmt, ...)
 // 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";
 
+static
+bool modminer_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_vcom, "ModMiner");
+}
+
 static bool
 modminer_detect_one(const char *devpath)
 {
@@ -159,16 +166,10 @@ modminer_detect_one(const char *devpath)
 
 #undef bailout
 
-static int
-modminer_detect_auto()
-{
-	return serial_autodetect(modminer_detect_one, "ModMiner");
-}
-
-static void
-modminer_detect()
+static
+bool modminer_lowl_probe(const struct lowlevel_device_info * const info)
 {
-	serial_detect_auto(&modminer_drv, modminer_detect_one, modminer_detect_auto);
+	return vcom_lowl_probe_wrapper(info, modminer_detect_one);
 }
 
 #define bailout(...)  return _bailout(-1, modminer, __VA_ARGS__);
@@ -846,7 +847,8 @@ void modminer_wlogprint_status(struct cgpu_info *cgpu)
 struct device_drv modminer_drv = {
 	.dname = "modminer",
 	.name = "MMQ",
-	.drv_detect = modminer_detect,
+	.lowl_match = modminer_lowl_match,
+	.lowl_probe = modminer_lowl_probe,
 	.override_statline_temp2 = get_modminer_upload_percent,
 	.get_stats = modminer_get_stats,
 	.get_api_extra_device_status = get_modminer_drv_extra_device_status,

+ 10 - 18
driver-nanofury.c

@@ -173,7 +173,13 @@ fail:
 }
 
 static
-bool nanofury_foundlowl(struct lowlevel_device_info * const info, __maybe_unused void *userp)
+bool nanofury_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_mcp2210, NANOFURY_USB_PRODUCT);
+}
+
+static
+bool nanofury_lowl_probe(const struct lowlevel_device_info * const info)
 {
 	const char * const product = info->product;
 	const char * const serial = info->serial;
@@ -211,7 +217,7 @@ bool nanofury_foundlowl(struct lowlevel_device_info * const info, __maybe_unused
 	cgpu = malloc(sizeof(*cgpu));
 	*cgpu = (struct cgpu_info){
 		.drv = &nanofury_drv,
-		.device_data = info,
+		.device_data = lowlevel_ref(info),
 		.threads = 1,
 		// TODO: .name
 		.device_path = strdup(info->path),
@@ -225,21 +231,6 @@ bool nanofury_foundlowl(struct lowlevel_device_info * const info, __maybe_unused
 	return add_cgpu(cgpu);
 }
 
-static bool nanofury_detect_one(const char *serial)
-{
-	return lowlevel_detect_serial(nanofury_foundlowl, serial);
-}
-
-static int nanofury_detect_auto()
-{
-	return lowlevel_detect(nanofury_foundlowl, NANOFURY_USB_PRODUCT);
-}
-
-static void nanofury_detect()
-{
-	serial_detect_auto(&nanofury_drv, nanofury_detect_one, nanofury_detect_auto);
-}
-
 static
 bool nanofury_init(struct thr_info * const thr)
 {
@@ -335,7 +326,8 @@ void nanofury_shutdown(struct thr_info * const thr)
 struct device_drv nanofury_drv = {
 	.dname = "nanofury",
 	.name = "NFY",
-	.drv_detect = nanofury_detect,
+	.lowl_match = nanofury_lowl_match,
+	.lowl_probe = nanofury_lowl_probe,
 	
 	.thread_init = nanofury_init,
 	.thread_disable = nanofury_disable,

+ 11 - 18
driver-x6500.c

@@ -127,7 +127,14 @@ uint32_t x6500_get_register(struct jtag_port *jp, uint8_t addr)
 	return bits2int(buf, 32);
 }
 
-static bool x6500_foundlowl(struct lowlevel_device_info * const info, __maybe_unused void *userp)
+static
+bool x6500_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_ft232r, X6500_USB_PRODUCT);
+}
+
+static
+bool x6500_lowl_probe(const struct lowlevel_device_info * const info)
 {
 	const char * const product = info->product;
 	const char * const serial = info->serial;
@@ -153,27 +160,12 @@ static bool x6500_foundlowl(struct lowlevel_device_info * const info, __maybe_un
 	x6500->procs = 2;
 	x6500->name = strdup(product);
 	x6500->cutofftemp = 85;
-	x6500->device_data = info;
+	x6500->device_data = lowlevel_ref(info);
 	cgpu_copy_libusb_strings(x6500, dev);
 
 	return add_cgpu(x6500);
 }
 
-static bool x6500_detect_one(const char *serial)
-{
-	return lowlevel_detect_serial(x6500_foundlowl, serial);
-}
-
-static int x6500_detect_auto()
-{
-	return lowlevel_detect(x6500_foundlowl, X6500_USB_PRODUCT);
-}
-
-static void x6500_detect()
-{
-	serial_detect_auto(&x6500_api, x6500_detect_one, x6500_detect_auto);
-}
-
 static bool x6500_prepare(struct thr_info *thr)
 {
 	struct cgpu_info *x6500 = thr->cgpu;
@@ -834,7 +826,8 @@ void x6500_wlogprint_status(struct cgpu_info *cgpu)
 struct device_drv x6500_api = {
 	.dname = "x6500",
 	.name = "XBS",
-	.drv_detect = x6500_detect,
+	.lowl_match = x6500_lowl_match,
+	.lowl_probe = x6500_lowl_probe,
 	.thread_prepare = x6500_prepare,
 	.thread_init = x6500_thread_init,
 	.get_stats = x6500_get_stats,

+ 9 - 17
driver-ztex.c

@@ -77,7 +77,13 @@ static struct cgpu_info *ztex_setup(struct libztex_device *dev, int fpgacount)
 }
 
 static
-bool ztex_foundlowl(struct lowlevel_device_info * const info, __maybe_unused void *userp)
+bool ztex_lowl_match(const struct lowlevel_device_info * const info)
+{
+	return lowlevel_match_lowlproduct(info, &lowl_usb, "btcminer for ZTEX");
+}
+
+static
+bool ztex_lowl_probe(const struct lowlevel_device_info * const info)
 {
 	const char * const product = info->product;
 	const char * const serial = info->serial;
@@ -125,21 +131,6 @@ bool ztex_foundlowl(struct lowlevel_device_info * const info, __maybe_unused voi
 	return true;
 }
 
-static bool ztex_detect_one(const char *serial)
-{
-	return lowlevel_detect_serial(ztex_foundlowl, serial);
-}
-
-static int ztex_autodetect()
-{
-	return lowlevel_detect(ztex_foundlowl, "btcminer for ZTEX");
-}
-
-static void ztex_detect()
-{
-	generic_detect(&ztex_drv, ztex_detect_one, ztex_autodetect, 0);
-}
-
 static bool ztex_change_clock_func(struct thr_info *thr, int bestM)
 {
 	struct cgpu_info *cgpu = thr->cgpu;
@@ -421,7 +412,8 @@ static void ztex_disable(struct thr_info *thr)
 struct device_drv ztex_drv = {
 	.dname = "ztex",
 	.name = "ZTX",
-	.drv_detect = ztex_detect,
+	.lowl_match = ztex_lowl_match,
+	.lowl_probe = ztex_lowl_probe,
 	.get_api_extra_device_status = get_ztex_drv_extra_device_status,
 	.thread_init = ztex_prepare,
 	.scanhash = ztex_scanhash,

+ 16 - 3
fpgautils.c

@@ -100,7 +100,7 @@ void clear_detectone_meta_info(void)
 	};
 }
 
-static char *_vcom_unique_id(const char *);
+#define _vcom_unique_id(devpath)  devpath_to_devid(devpath)
 
 struct lowlevel_device_info *_vcom_devinfo_findorcreate(struct lowlevel_device_info ** const devinfo_list, const char * const devpath)
 {
@@ -647,6 +647,20 @@ extern void _vcom_devinfo_scan_querydosdevice(struct lowlevel_device_info **);
 extern void _vcom_devinfo_scan_lsdev(struct lowlevel_device_info **);
 #endif
 
+bool vcom_lowl_probe_wrapper(const struct lowlevel_device_info * const info, detectone_func_t detectone)
+{
+	if (info->lowl != &lowl_vcom)
+		return false;
+	detectone_meta_info = (struct detectone_meta_info_t){
+		.manufacturer = info->manufacturer,
+		.product = info->product,
+		.serial = info->serial,
+	};
+	const bool rv = detectone(info->path);
+	clear_detectone_meta_info();
+	return rv;
+}
+
 bool _serial_autodetect_found_cb(struct lowlevel_device_info * const devinfo, void *userp)
 {
 	detectone_func_t detectone = userp;
@@ -781,8 +795,7 @@ struct device_drv *bfg_claim_any2(struct device_drv * const api, const char * co
 	return bfg_claim_any(api, verbose, devpath);
 }
 
-static
-char *_vcom_unique_id(const char * const devpath)
+char *devpath_to_devid(const char * const devpath)
 {
 #ifndef WIN32
 	char *devs = malloc(6 + (sizeof(dev_t) * 2) + 1);

+ 5 - 2
fpgautils.h

@@ -21,10 +21,13 @@ struct detectone_meta_info_t {
 	const char *serial;
 };
 
-// NOTE: Should detectone become run multithreaded, this will become a threadsafe #define
-extern struct detectone_meta_info_t detectone_meta_info;
+extern struct detectone_meta_info_t *_detectone_meta_info();
+#define detectone_meta_info (*_detectone_meta_info())
 extern void clear_detectone_meta_info(void);
 
+extern char *devpath_to_devid(const char *);
+extern bool vcom_lowl_probe_wrapper(const struct lowlevel_device_info *, detectone_func_t);
+
 extern int _serial_autodetect(detectone_func_t, ...);
 #define serial_autodetect(...)  _serial_autodetect(__VA_ARGS__, NULL)
 

+ 36 - 19
lowlevel.c

@@ -34,6 +34,8 @@ void lowlevel_devinfo_semicpy(struct lowlevel_device_info * const dst, const str
 
 void lowlevel_devinfo_free(struct lowlevel_device_info * const info)
 {
+	if (info->ref--)
+		return;
 	if (info->lowl->devinfo_free)
 		info->lowl->devinfo_free(info);
 	free(info->manufacturer);
@@ -44,6 +46,13 @@ void lowlevel_devinfo_free(struct lowlevel_device_info * const info)
 	free(info);
 }
 
+struct lowlevel_device_info *lowlevel_ref(const struct lowlevel_device_info * const cinfo)
+{
+	struct lowlevel_device_info * const info = (void*)cinfo;
+	++info->ref;
+	return info;
+}
+
 void lowlevel_scan_free()
 {
 	if (!devinfo_list)
@@ -58,7 +67,7 @@ void lowlevel_scan_free()
 	}
 }
 
-void lowlevel_scan()
+struct lowlevel_device_info *lowlevel_scan()
 {
 	struct lowlevel_device_info *devinfo_mid_list;
 	
@@ -99,6 +108,29 @@ void lowlevel_scan()
 		       (unsigned)devinfo_mid_list->vid, (unsigned)devinfo_mid_list->pid,
 		       devinfo_mid_list->manufacturer, devinfo_mid_list->product, devinfo_mid_list->serial);
 	}
+	
+	return devinfo_list;
+}
+
+bool _lowlevel_match_product(const struct lowlevel_device_info * const info, const char ** const needles)
+{
+	if (!info->product)
+		return false;
+	for (int i = 0; needles[i]; ++i)
+		if (!strstr(info->product, needles[i]))
+			return false;
+	return true;
+}
+
+bool lowlevel_match_id(const struct lowlevel_device_info * const info, const struct lowlevel_driver * const lowl, const int32_t vid, const int32_t pid)
+{
+	if (info->lowl != lowl)
+		return false;
+	if (vid != -1 && vid != info->vid)
+		return false;
+	if (pid != -1 && pid != info->pid)
+		return false;
+	return true;
 }
 
 #define DETECT_BEGIN  \
@@ -109,44 +141,29 @@ void lowlevel_scan()
 	{  \
 // END DETECT_BEGIN
 
-#define DETECT_PREEND  \
+#define DETECT_END  \
 		if (!cb(info, userp))  \
 			continue;  \
 		LL_DELETE(devinfo_list, info);  \
 		++found;  \
-// END DETECT_PREEND
-
-#define DETECT_END  \
 	}  \
 	return found;  \
 // END DETECT_END
 
 int _lowlevel_detect(lowl_found_devinfo_func_t cb, const char *serial, const char **product_needles, void * const userp)
 {
-	int i;
-	
 	DETECT_BEGIN
 		if (serial && ((!info->serial) || strcmp(serial, info->serial)))
 			continue;
-		if (product_needles[0] && !info->product)
+		if (product_needles[0] && !_lowlevel_match_product(info, product_needles))
 			continue;
-		for (i = 0; product_needles[i]; ++i)
-			if (!strstr(info->product, product_needles[i]))
-				goto next;
-	DETECT_PREEND
-next: ;
 	DETECT_END
 }
 
 int lowlevel_detect_id(const lowl_found_devinfo_func_t cb, void * const userp, const struct lowlevel_driver * const lowl, const int32_t vid, const int32_t pid)
 {
 	DETECT_BEGIN
-		if (info->lowl != lowl)
-			continue;
-		if (vid != -1 && vid != info->vid)
-			continue;
-		if (pid != -1 && pid != info->pid)
+		if (!lowlevel_match_id(info, lowl, vid, pid))
 			continue;
-	DETECT_PREEND
 	DETECT_END
 }

+ 12 - 1
lowlevel.h

@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <pthread.h>
 
 #include <uthash.h>
 
@@ -30,14 +31,24 @@ struct lowlevel_device_info {
 	
 	struct lowlevel_device_info *next;
 	UT_hash_handle hh;
+	pthread_t probe_pth;
+	int ref;
 };
 
-extern void lowlevel_scan();
+extern struct lowlevel_device_info *lowlevel_scan();
+extern bool _lowlevel_match_product(const struct lowlevel_device_info *, const char **);
+#define lowlevel_match_product(info, ...)  \
+	_lowlevel_match_product(info, (const char *[]){__VA_ARGS__, NULL})
+#define lowlevel_match_lowlproduct(info, matchlowl, ...)  \
+	(matchlowl == info->lowl && _lowlevel_match_product(info, (const char *[]){__VA_ARGS__, NULL}))
+extern bool lowlevel_match_id(const struct lowlevel_device_info *, const struct lowlevel_driver *, int32_t vid, int32_t pid);
 extern int _lowlevel_detect(lowl_found_devinfo_func_t, const char *serial, const char **product_needles, void *);
 #define lowlevel_detect(func, ...)  _lowlevel_detect(func, NULL, (const char *[]){__VA_ARGS__, NULL}, NULL)
 #define lowlevel_detect_serial(func, serial)  _lowlevel_detect(func, serial, (const char *[]){NULL}, NULL)
 extern int lowlevel_detect_id(lowl_found_devinfo_func_t, void *, const struct lowlevel_driver *, int32_t vid, int32_t pid);
 extern void lowlevel_scan_free();
+
+extern struct lowlevel_device_info *lowlevel_ref(const struct lowlevel_device_info *);
 extern void lowlevel_devinfo_semicpy(struct lowlevel_device_info *dst, const struct lowlevel_device_info *src);
 extern void lowlevel_devinfo_free(struct lowlevel_device_info *);
 

+ 1 - 1
mcp2210.c

@@ -107,7 +107,7 @@ bool mcp2210_get_configs(struct mcp2210_device * const h)
 	return true;
 }
 
-struct mcp2210_device *mcp2210_open(struct lowlevel_device_info *info)
+struct mcp2210_device *mcp2210_open(const struct lowlevel_device_info * const info)
 {
 	struct mcp2210_device *h;
 	char * const path = info->path;

+ 1 - 1
mcp2210.h

@@ -17,7 +17,7 @@ enum mcp2210_gpio_value {
 
 struct mcp2210_device;
 
-extern struct mcp2210_device *mcp2210_open(struct lowlevel_device_info *);
+extern struct mcp2210_device *mcp2210_open(const struct lowlevel_device_info *);
 extern void mcp2210_close(struct mcp2210_device *);
 
 extern bool mcp2210_spi_cancel(struct mcp2210_device *);

+ 117 - 1
miner.c

@@ -68,6 +68,7 @@
 #include "logging.h"
 #include "miner.h"
 #include "findnonce.h"
+#include "fpgautils.h"
 #include "adl.h"
 #include "driver-cpu.h"
 #include "driver-opencl.h"
@@ -10129,6 +10130,7 @@ extern struct sigaction pcwm_orig_term_handler;
 #endif
 
 bool bfg_need_detect_rescan;
+extern void probe_device(struct lowlevel_device_info *);
 
 static
 void drv_detect_all()
@@ -10137,7 +10139,12 @@ rescan:
 	bfg_need_detect_rescan = false;
 	
 #ifdef HAVE_BFG_LOWLEVEL
-	lowlevel_scan();
+	struct lowlevel_device_info * const infolist = lowlevel_scan(), *info, *infotmp;
+	
+	LL_FOREACH_SAFE(infolist, info, infotmp)
+		probe_device(info);
+	LL_FOREACH_SAFE(infolist, info, infotmp)
+		pthread_join(info->probe_pth, NULL);
 #endif
 	
 	struct driver_registration *reg, *tmp;
@@ -10270,6 +10277,115 @@ void _scan_serial(void *p)
 	}
 }
 
+static
+bool _probe_device_internal(struct lowlevel_device_info * const info, const char * const dname, const size_t dnamelen)
+{
+	struct driver_registration *dreg;
+	
+	BFG_FIND_DRV_BY_DNAME(dreg, dname, dnamelen);
+	if (!dreg)
+	{
+		BFG_FIND_DRV_BY_NAME(dreg, dname, dnamelen);
+		if (!dreg)
+			return false;
+	}
+	
+	const struct device_drv * const drv = dreg->drv;
+	if (!drv->lowl_probe)
+		return false;
+	return drv->lowl_probe(info);
+}
+
+static
+void *probe_device_thread(void *p)
+{
+	struct lowlevel_device_info * const info = p;
+	
+	{
+		char threadname[5 + strlen(info->devid) + 1];
+		sprintf(threadname, "probe%s", info->devid);
+		RenameThread(threadname);
+	}
+	
+	// If already in use, ignore
+	if (bfg_claim_any(NULL, NULL, info->devid))
+		applogr(NULL, LOG_DEBUG, "%s: \"%s\" already in use",
+		        __func__, info->product);
+	
+	// if lowlevel device matches specific user assignment, probe requested driver(s)
+	struct string_elist *sd_iter, *sd_tmp;
+	struct driver_registration *dreg, *dreg_tmp;
+	DL_FOREACH_SAFE(scan_devices, sd_iter, sd_tmp)
+	{
+		const char * const dname = sd_iter->string;
+		const char * const colon = strchr(dname, ':');
+		if (!colon)
+			continue;
+		const char * const ser = &colon[1];
+		if (!(true
+			|| (info->serial && !strcasecmp(ser, info->serial))
+			|| (info->path   && !strcasecmp(ser, info->path  ))
+		))
+		{
+			char *devid = devpath_to_devid(ser);
+			if (!devid)
+				continue;
+			const bool different = strcmp(info->devid, devid);
+			free(devid);
+			if (different)
+				continue;
+		}
+		const size_t dnamelen = (colon - dname);
+		if (_probe_device_internal(info, dname, dnamelen))
+			return NULL;
+	}
+	
+	// probe driver(s) with auto enabled and matching VID/PID/Product/etc of device
+	BFG_FOREACH_DRIVER_BY_PRIORITY(dreg, dreg_tmp)
+	{
+		const struct device_drv * const drv = dreg->drv;
+		if (!(drv->lowl_match && drv->lowl_match(info)))
+			continue;
+		if (drv->lowl_probe(info))
+			return NULL;
+	}
+	
+	// probe driver(s) with 'all' enabled
+	bool allall = false;
+	DL_FOREACH_SAFE(scan_devices, sd_iter, sd_tmp)
+	{
+		const char * const dname = sd_iter->string;
+		const char * const colon = strchr(dname, ':');
+		if (!colon)
+		{
+			if (!strcasecmp(dname, "all"))
+				allall = true;
+			continue;
+		}
+		if (strcasecmp(&colon[1], "all"))
+			continue;
+		const size_t dnamelen = (colon - dname);
+		if (_probe_device_internal(info, dname, dnamelen))
+			return NULL;
+	}
+	if (allall)
+	{
+		BFG_FOREACH_DRIVER_BY_PRIORITY(dreg, dreg_tmp)
+		{
+			const struct device_drv * const drv = dreg->drv;
+			if (drv->lowl_probe(info))
+				return NULL;
+		}
+	}
+	
+	return NULL;
+}
+
+void probe_device(struct lowlevel_device_info * const info)
+{
+	pthread_create(&info->probe_pth, NULL, probe_device_thread, info);
+}
+
 int create_new_cgpus(void (*addfunc)(void*), void *arg)
 {
 	static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

+ 3 - 0
miner.h

@@ -288,6 +288,7 @@ typedef uint8_t supported_algos_t;
 struct api_data;
 struct thr_info;
 struct work;
+struct lowlevel_device_info;
 
 struct device_drv {
 	const char *dname;
@@ -298,6 +299,8 @@ struct device_drv {
 	// DRV-global functions
 	void (*drv_init)();
 	void (*drv_detect)();
+	bool (*lowl_match)(const struct lowlevel_device_info *);
+	bool (*lowl_probe)(const struct lowlevel_device_info *);
 
 	// Processor-specific functions
 	void (*reinit_device)(struct cgpu_info *);

+ 13 - 0
util.c

@@ -52,6 +52,9 @@
 
 #include <utlist.h>
 
+#ifdef HAVE_FPGAUTILS
+#include "fpgautils.h"
+#endif
 #include "miner.h"
 #include "compat.h"
 #include "util.h"
@@ -2501,6 +2504,9 @@ struct bfgtls_data {
 #ifdef WIN32
 	LPSTR bfg_strerror_socketresult;
 #endif
+#ifdef HAVE_FPGAUTILS
+	struct detectone_meta_info_t __detectone_meta_info;
+#endif
 };
 
 static
@@ -2528,6 +2534,13 @@ struct bfgtls_data *get_bfgtls()
 	return bfgtls;
 }
 
+#ifdef HAVE_FPGAUTILS
+struct detectone_meta_info_t *_detectone_meta_info()
+{
+	return &get_bfgtls()->__detectone_meta_info;
+}
+#endif
+
 void bfg_init_threadlocal()
 {
 	if (pthread_key_create(&key_bfgtls, NULL))