Browse Source

Merge branch 'cairnsmore' into bfgminer

Conflicts:
	fpgautils.c
	fpgautils.h
Luke Dashjr 13 years ago
parent
commit
e6b6d8816d
11 changed files with 479 additions and 222 deletions
  1. 7 3
      FPGA-README
  2. 2 1
      Makefile.am
  3. 5 0
      api.c
  4. 1 104
      driver-bitforce.c
  5. 72 0
      driver-cairnsmore.c
  6. 127 105
      driver-icarus.c
  7. 167 3
      fpgautils.c
  8. 10 5
      fpgautils.h
  9. 76 0
      icarus-common.h
  10. 10 1
      miner.c
  11. 2 0
      miner.h

+ 7 - 3
FPGA-README

@@ -42,7 +42,7 @@ Icarus
 There are two hidden options in cgminer when Icarus support is compiled in:
 There are two hidden options in cgminer when Icarus support is compiled in:
 
 
 --icarus-options <arg> Set specific FPGA board configurations - one set of values for all or comma separated
 --icarus-options <arg> Set specific FPGA board configurations - one set of values for all or comma separated
-           baud:work_division:fpga_count
+           baud:work_division:fpga_count:quirks
 
 
            baud           The Serial/USB baud rate - 115200 or 57600 only - default 115200
            baud           The Serial/USB baud rate - 115200 or 57600 only - default 115200
            work_division  The fraction of work divided up for each FPGA chip - 1, 2, 4 or 8
            work_division  The fraction of work divided up for each FPGA chip - 1, 2, 4 or 8
@@ -51,13 +51,17 @@ There are two hidden options in cgminer when Icarus support is compiled in:
                           as work_division - range is from 1 up to 'work_division'
                           as work_division - range is from 1 up to 'work_division'
                           It defaults to the value of work_division - or 2 if you don't specify
                           It defaults to the value of work_division - or 2 if you don't specify
                           work_division
                           work_division
+           quirks         List of quirks to enable and disable (after a minus sign):
+                            r  Reopen device regularly to workaround buggy Icarus USB chipset
+                               (enabled by default)
 
 
 If you define fewer comma seperated values than Icarus devices, the last values will be used
 If you define fewer comma seperated values than Icarus devices, the last values will be used
 for all extra devices
 for all extra devices
 
 
-An example would be: --icarus-options 57600:2:1
+An example would be: --icarus-options 57600:2:1:-r
 This would mean: use 57600 baud, the FPGA board divides the work in half however
 This would mean: use 57600 baud, the FPGA board divides the work in half however
-only 1 FPGA actually runs on the board (e.g. like an early CM1 Icarus copy bitstream)
+only 1 FPGA actually runs on the board, and don't reopen the device (e.g. like
+an early CM1 Icarus copy bitstream)
 
 
 --icarus-timing <arg> Set how the Icarus timing is calculated - one setting/value for all or comma separated
 --icarus-timing <arg> Set how the Icarus timing is calculated - one setting/value for all or comma separated
            default[=N]   Use the default Icarus hash time (2.6316ns)
            default[=N]   Use the default Icarus hash time (2.6316ns)

+ 2 - 1
Makefile.am

@@ -88,7 +88,8 @@ endif
 endif
 endif
 
 
 if HAS_ICARUS
 if HAS_ICARUS
-bfgminer_SOURCES += driver-icarus.c
+bfgminer_SOURCES += driver-icarus.c icarus-common.h
+bfgminer_SOURCES += driver-cairnsmore.c
 endif
 endif
 
 
 if HAS_MODMINER
 if HAS_MODMINER

+ 5 - 0
api.c

@@ -606,6 +606,7 @@ extern struct device_api bitforce_api;
 #endif
 #endif
 
 
 #ifdef USE_ICARUS
 #ifdef USE_ICARUS
+extern struct device_api cairnsmore_api;
 extern struct device_api icarus_api;
 extern struct device_api icarus_api;
 #endif
 #endif
 
 
@@ -1037,6 +1038,8 @@ static int numpgas()
 			count++;
 			count++;
 #endif
 #endif
 #ifdef USE_ICARUS
 #ifdef USE_ICARUS
+		if (devices[i]->api == &cairnsmore_api)
+			count++;
 		if (devices[i]->api == &icarus_api)
 		if (devices[i]->api == &icarus_api)
 			count++;
 			count++;
 #endif
 #endif
@@ -1063,6 +1066,8 @@ static int pgadevice(int pgaid)
 			count++;
 			count++;
 #endif
 #endif
 #ifdef USE_ICARUS
 #ifdef USE_ICARUS
+		if (devices[i]->api == &cairnsmore_api)
+			count++;
 		if (devices[i]->api == &icarus_api)
 		if (devices[i]->api == &icarus_api)
 			count++;
 			count++;
 #endif
 #endif

+ 1 - 104
driver-bitforce.c

@@ -18,28 +18,6 @@
 
 
 #include "config.h"
 #include "config.h"
 
 
-#ifdef WIN32
-
-#include <windows.h>
-
-#define dlsym (void*)GetProcAddress
-#define dlclose FreeLibrary
-
-typedef unsigned long FT_STATUS;
-typedef PVOID FT_HANDLE;
-__stdcall FT_STATUS (*FT_ListDevices)(PVOID pArg1, PVOID pArg2, DWORD Flags);
-__stdcall FT_STATUS (*FT_Open)(int idx, FT_HANDLE*);
-__stdcall FT_STATUS (*FT_GetComPortNumber)(FT_HANDLE, LPLONG lplComPortNumber);
-__stdcall FT_STATUS (*FT_Close)(FT_HANDLE);
-const uint32_t FT_OPEN_BY_DESCRIPTION =       2;
-const uint32_t FT_LIST_ALL         = 0x20000000;
-const uint32_t FT_LIST_NUMBER_ONLY = 0x80000000;
-enum {
-	FT_OK,
-};
-
-#endif /* WIN32 */
-
 #include "compat.h"
 #include "compat.h"
 #include "fpgautils.h"
 #include "fpgautils.h"
 #include "miner.h"
 #include "miner.h"
@@ -137,92 +115,11 @@ static bool bitforce_detect_one(const char *devpath)
 	return add_cgpu(bitforce);
 	return add_cgpu(bitforce);
 }
 }
 
 
-#define LOAD_SYM(sym)  do { \
-	if (!(sym = dlsym(dll, #sym))) {  \
-		applog(LOG_DEBUG, "Failed to load " #sym ", not using FTDI bitforce autodetect");  \
-		goto out;  \
-	}  \
-} while(0)
-
-#ifdef WIN32
-static int bitforce_autodetect_ftdi(void)
-{
-	char devpath[] = "\\\\.\\COMnnnnn";
-	char *devpathnum = &devpath[7];
-	char **bufptrs;
-	char *buf;
-	int found = 0;
-	int i;
-
-	FT_STATUS ftStatus;
-	DWORD numDevs;
-	HMODULE dll = LoadLibrary("FTD2XX.DLL");
-	if (!dll) {
-		applog(LOG_DEBUG, "FTD2XX.DLL failed to load, not using FTDI bitforce autodetect");
-		return 0;
-	}
-	LOAD_SYM(FT_ListDevices);
-	LOAD_SYM(FT_Open);
-	LOAD_SYM(FT_GetComPortNumber);
-	LOAD_SYM(FT_Close);
-	
-	ftStatus = FT_ListDevices(&numDevs, NULL, FT_LIST_NUMBER_ONLY);
-	if (ftStatus != FT_OK) {
-		applog(LOG_DEBUG, "FTDI device count failed, not using FTDI bitforce autodetect");
-		goto out;
-	}
-	applog(LOG_DEBUG, "FTDI reports %u devices", (unsigned)numDevs);
-
-	buf = alloca(65 * numDevs);
-	bufptrs = alloca(sizeof(*bufptrs) * (numDevs + 1));
-
-	for (i = 0; i < numDevs; ++i)
-		bufptrs[i] = &buf[i * 65];
-	bufptrs[numDevs] = NULL;
-	ftStatus = FT_ListDevices(bufptrs, &numDevs, FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION);
-	if (ftStatus != FT_OK) {
-		applog(LOG_DEBUG, "FTDI device list failed, not using FTDI bitforce autodetect");
-		goto out;
-	}
-	
-	for (i = numDevs; i > 0; ) {
-		--i;
-		bufptrs[i][64] = '\0';
-		
-		if (!(strstr(bufptrs[i], "BitFORCE") && strstr(bufptrs[i], "SHA256")))
-			continue;
-		
-		FT_HANDLE ftHandle;
-		if (FT_OK != FT_Open(i, &ftHandle))
-			continue;
-		LONG lComPortNumber;
-		ftStatus = FT_GetComPortNumber(ftHandle, &lComPortNumber);
-		FT_Close(ftHandle);
-		if (FT_OK != ftStatus || lComPortNumber < 0)
-			continue;
-		
-		sprintf(devpathnum, "%d", (int)lComPortNumber);
-		
-		if (bitforce_detect_one(devpath))
-			++found;
-	}
-
-out:
-	dlclose(dll);
-	return found;
-}
-#else
-static int bitforce_autodetect_ftdi(void)
-{
-	return 0;
-}
-#endif
-
 static int bitforce_detect_auto(void)
 static int bitforce_detect_auto(void)
 {
 {
 	return (serial_autodetect_udev     (bitforce_detect_one, "BitFORCE*SHA256") ?:
 	return (serial_autodetect_udev     (bitforce_detect_one, "BitFORCE*SHA256") ?:
 		serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?:
 		serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?:
-		bitforce_autodetect_ftdi() ?:
+		serial_autodetect_ftdi(bitforce_detect_one, "BitFORCE", "SHA256") ?:
 		0);
 		0);
 }
 }
 
 

+ 72 - 0
driver-cairnsmore.c

@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012 Luke Dashjr
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "fpgautils.h"
+#include "icarus-common.h"
+#include "miner.h"
+
+#define CAIRNSMORE1_IO_SPEED 115200
+#define CAIRNSMORE1_HASH_TIME 0.0000000024484
+
+struct device_api cairnsmore_api;
+
+static bool cairnsmore_detect_one(const char *devpath)
+{
+	struct ICARUS_INFO *info = calloc(1, sizeof(struct ICARUS_INFO));
+	if (unlikely(!info))
+		quit(1, "Failed to malloc ICARUS_INFO");
+
+	info->baud = CAIRNSMORE1_IO_SPEED;
+	info->work_division = 2;
+	info->fpga_count = 2;
+	info->quirk_reopen = false;
+	info->Hs = CAIRNSMORE1_HASH_TIME;
+
+	if (!icarus_detect_custom(devpath, &cairnsmore_api, info)) {
+		free(info);
+		return false;
+	}
+	return true;
+}
+
+static int cairnsmore_detect_auto(void)
+{
+	return
+	serial_autodetect_udev     (cairnsmore_detect_one, "*Cairnsmore1*") ?:
+	serial_autodetect_devserial(cairnsmore_detect_one, "Cairnsmore1") ?:
+	serial_autodetect_ftdi     (cairnsmore_detect_one, "Cairnsmore1", NULL) ?:
+	0;
+}
+
+static void cairnsmore_detect()
+{
+	// Actual serial detection is handled by Icarus driver
+	serial_detect_auto_byname(cairnsmore_api.dname, cairnsmore_detect_one, cairnsmore_detect_auto);
+}
+
+void convert_icarus_to_cairnsmore(struct cgpu_info *cm1)
+{
+	struct ICARUS_INFO *info = cm1->cgpu_data;
+	info->Hs = CAIRNSMORE1_HASH_TIME;
+	info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
+	info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+	cm1->api = &cairnsmore_api;
+	renumber_cgpu(cm1);
+}
+
+extern struct device_api icarus_api;
+
+__attribute__((constructor(1000)))
+static void cairnsmore_api_init()
+{
+	cairnsmore_api = icarus_api;
+	cairnsmore_api.dname = "cairnsmore";
+	cairnsmore_api.name = "ECM";
+	cairnsmore_api.api_detect = cairnsmore_detect;
+}

+ 127 - 105
driver-icarus.c

@@ -56,6 +56,7 @@
 
 
 #include "elist.h"
 #include "elist.h"
 #include "fpgautils.h"
 #include "fpgautils.h"
+#include "icarus-common.h"
 #include "miner.h"
 #include "miner.h"
 
 
 // The serial I/O speed - Linux uses a define 'B115200' in bits/termios.h
 // The serial I/O speed - Linux uses a define 'B115200' in bits/termios.h
@@ -73,20 +74,12 @@ ASSERT1(sizeof(uint32_t) == 4);
 
 
 #define ICARUS_READ_TIME(baud) ((double)ICARUS_READ_SIZE * (double)8.0 / (double)(baud))
 #define ICARUS_READ_TIME(baud) ((double)ICARUS_READ_SIZE * (double)8.0 / (double)(baud))
 
 
-// Fraction of a second, USB timeout is measured in
-// i.e. 10 means 1/10 of a second
-// Right now, it MUST be 10 due to other assumptions.
-#define TIME_FACTOR 10
-// It's 10 per second, thus value = 10/TIME_FACTOR =
-#define ICARUS_READ_FAULT_DECISECONDS 1
-
 // In timing mode: Default starting value until an estimate can be obtained
 // In timing mode: Default starting value until an estimate can be obtained
 // 5 seconds allows for up to a ~840MH/s device
 // 5 seconds allows for up to a ~840MH/s device
 #define ICARUS_READ_COUNT_TIMING	(5 * TIME_FACTOR)
 #define ICARUS_READ_COUNT_TIMING	(5 * TIME_FACTOR)
 
 
 // For a standard Icarus REV3
 // For a standard Icarus REV3
 #define ICARUS_REV3_HASH_TIME 0.00000000264083
 #define ICARUS_REV3_HASH_TIME 0.00000000264083
-#define NANOSEC 1000000000.0
 
 
 // Icarus Rev3 doesn't send a completion message when it finishes
 // Icarus Rev3 doesn't send a completion message when it finishes
 // the full nonce range, so to avoid being idle we must abort the
 // the full nonce range, so to avoid being idle we must abort the
@@ -134,68 +127,14 @@ ASSERT1(sizeof(uint32_t) == 4);
 
 
 static struct timeval history_sec = { HISTORY_SEC, 0 };
 static struct timeval history_sec = { HISTORY_SEC, 0 };
 
 
-// Store the last INFO_HISTORY data sets
-// [0] = current data, not yet ready to be included as an estimate
-// Each new data set throws the last old set off the end thus
-// keeping a ongoing average of recent data
-#define INFO_HISTORY 10
-
-struct ICARUS_HISTORY {
-	struct timeval finish;
-	double sumXiTi;
-	double sumXi;
-	double sumTi;
-	double sumXi2;
-	uint32_t values;
-	uint32_t hash_count_min;
-	uint32_t hash_count_max;
-};
-
-enum timing_mode { MODE_DEFAULT, MODE_SHORT, MODE_LONG, MODE_VALUE };
-
 static const char *MODE_DEFAULT_STR = "default";
 static const char *MODE_DEFAULT_STR = "default";
 static const char *MODE_SHORT_STR = "short";
 static const char *MODE_SHORT_STR = "short";
 static const char *MODE_LONG_STR = "long";
 static const char *MODE_LONG_STR = "long";
 static const char *MODE_VALUE_STR = "value";
 static const char *MODE_VALUE_STR = "value";
 static const char *MODE_UNKNOWN_STR = "unknown";
 static const char *MODE_UNKNOWN_STR = "unknown";
 
 
-struct ICARUS_INFO {
-	// time to calculate the golden_ob
-	uint64_t golden_hashes;
-	struct timeval golden_tv;
-
-	struct ICARUS_HISTORY history[INFO_HISTORY+1];
-	uint32_t min_data_count;
-
-	// seconds per Hash
-	double Hs;
-	int read_count;
-
-	enum timing_mode timing_mode;
-	bool do_icarus_timing;
-
-	double fullnonce;
-	int count;
-	double W;
-	uint32_t values;
-	uint64_t hash_count_range;
-
-	// Determine the cost of history processing
-	// (which will only affect W)
-	uint64_t history_count;
-	struct timeval history_time;
-
-	// icarus-options
-	int baud;
-	int work_division;
-	int fpga_count;
-	uint32_t nonce_mask;
-};
-
 #define END_CONDITION 0x0000ffff
 #define END_CONDITION 0x0000ffff
-
-// One for each possible device
-static struct ICARUS_INFO **icarus_info;
+#define DEFAULT_DETECT_THRESHOLD 1
 
 
 // Looking for options in --icarus-timing and --icarus-options:
 // Looking for options in --icarus-timing and --icarus-options:
 //
 //
@@ -216,6 +155,8 @@ static int option_offset = -1;
 
 
 struct device_api icarus_api;
 struct device_api icarus_api;
 
 
+extern void convert_icarus_to_cairnsmore(struct cgpu_info *);
+
 static void rev(unsigned char *s, size_t l)
 static void rev(unsigned char *s, size_t l)
 {
 {
 	size_t i, j;
 	size_t i, j;
@@ -351,7 +292,7 @@ static const char *timing_mode_str(enum timing_mode timing_mode)
 
 
 static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 {
 {
-	struct ICARUS_INFO *info = icarus_info[icarus->device_id];
+	struct ICARUS_INFO *info = icarus->cgpu_data;
 	double Hs;
 	double Hs;
 	char buf[BUFSIZ+1];
 	char buf[BUFSIZ+1];
 	char *ptr, *comma, *eq;
 	char *ptr, *comma, *eq;
@@ -381,17 +322,14 @@ static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 		buf[max] = '\0';
 		buf[max] = '\0';
 	}
 	}
 
 
-	info->Hs = 0;
 	info->read_count = 0;
 	info->read_count = 0;
 
 
 	if (strcasecmp(buf, MODE_SHORT_STR) == 0) {
 	if (strcasecmp(buf, MODE_SHORT_STR) == 0) {
-		info->Hs = ICARUS_REV3_HASH_TIME;
 		info->read_count = ICARUS_READ_COUNT_TIMING;
 		info->read_count = ICARUS_READ_COUNT_TIMING;
 
 
 		info->timing_mode = MODE_SHORT;
 		info->timing_mode = MODE_SHORT;
 		info->do_icarus_timing = true;
 		info->do_icarus_timing = true;
 	} else if (strcasecmp(buf, MODE_LONG_STR) == 0) {
 	} else if (strcasecmp(buf, MODE_LONG_STR) == 0) {
-		info->Hs = ICARUS_REV3_HASH_TIME;
 		info->read_count = ICARUS_READ_COUNT_TIMING;
 		info->read_count = ICARUS_READ_COUNT_TIMING;
 
 
 		info->timing_mode = MODE_LONG;
 		info->timing_mode = MODE_LONG;
@@ -414,14 +352,19 @@ static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 	} else {
 	} else {
 		// Anything else in buf just uses DEFAULT mode
 		// Anything else in buf just uses DEFAULT mode
 
 
-		info->Hs = ICARUS_REV3_HASH_TIME;
 		info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
 		info->fullnonce = info->Hs * (((double)0xffffffff) + 1);
 
 
 		if ((eq = strchr(buf, '=')) != NULL)
 		if ((eq = strchr(buf, '=')) != NULL)
 			info->read_count = atoi(eq+1);
 			info->read_count = atoi(eq+1);
 
 
-		if (info->read_count < 1)
-			info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+		if (icarus->api == &icarus_api) {
+			info->do_default_detection = 0x10;
+			if (info->read_count < 1)
+				info->read_count = ICARUS_READ_COUNT_TIMING;
+		} else {
+			if (info->read_count < 1)
+				info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+		}
 
 
 		info->timing_mode = MODE_DEFAULT;
 		info->timing_mode = MODE_DEFAULT;
 		info->do_icarus_timing = false;
 		info->do_icarus_timing = false;
@@ -460,8 +403,12 @@ static uint32_t mask(int work_division)
 	return nonce_mask;
 	return nonce_mask;
 }
 }
 
 
-static void get_options(int this_option_offset, int *baud, int *work_division, int *fpga_count)
+static void get_options(int this_option_offset, struct ICARUS_INFO *info)
 {
 {
+	int *baud = &info->baud;
+	int *work_division = &info->work_division;
+	int *fpga_count = &info->fpga_count;
+
 	char err_buf[BUFSIZ+1];
 	char err_buf[BUFSIZ+1];
 	char buf[BUFSIZ+1];
 	char buf[BUFSIZ+1];
 	char *ptr, *comma, *colon, *colon2;
 	char *ptr, *comma, *colon, *colon2;
@@ -491,10 +438,6 @@ static void get_options(int this_option_offset, int *baud, int *work_division, i
 		buf[max] = '\0';
 		buf[max] = '\0';
 	}
 	}
 
 
-	*baud = ICARUS_IO_SPEED;
-	*work_division = 2;
-	*fpga_count = 2;
-
 	if (*buf) {
 	if (*buf) {
 		colon = strchr(buf, ':');
 		colon = strchr(buf, ':');
 		if (colon)
 		if (colon)
@@ -532,6 +475,11 @@ static void get_options(int this_option_offset, int *baud, int *work_division, i
 			}
 			}
 
 
 			if (colon2 && *colon2) {
 			if (colon2 && *colon2) {
+			  colon = strchr(colon2, ':');
+			  if (colon)
+					*(colon++) = '\0';
+
+			  if (*colon2) {
 				tmp = atoi(colon2);
 				tmp = atoi(colon2);
 				if (tmp > 0 && tmp <= *work_division)
 				if (tmp > 0 && tmp <= *work_division)
 					*fpga_count = tmp;
 					*fpga_count = tmp;
@@ -539,16 +487,26 @@ static void get_options(int this_option_offset, int *baud, int *work_division, i
 					sprintf(err_buf, "Invalid icarus-options for fpga_count (%s) must be >0 and <=work_division (%d)", colon2, *work_division);
 					sprintf(err_buf, "Invalid icarus-options for fpga_count (%s) must be >0 and <=work_division (%d)", colon2, *work_division);
 					quit(1, err_buf);
 					quit(1, err_buf);
 				}
 				}
+			  }
+
+			  if (colon && *colon) {
+					colon2 = strchr(colon, '-') ?: "";
+					if (*colon2)
+						*(colon2++) = '\0';
+					if (strchr(colon, 'r'))
+						info->quirk_reopen = 2;
+					if (strchr(colon2, 'r'))
+						info->quirk_reopen = 0;
+			  }
 			}
 			}
 		}
 		}
 	}
 	}
 }
 }
 
 
-static bool icarus_detect_one(const char *devpath)
+bool icarus_detect_custom(const char *devpath, struct device_api *api, struct ICARUS_INFO *info)
 {
 {
 	int this_option_offset = ++option_offset;
 	int this_option_offset = ++option_offset;
 
 
-	struct ICARUS_INFO *info;
 	struct timeval tv_start, tv_finish;
 	struct timeval tv_start, tv_finish;
 	int fd;
 	int fd;
 
 
@@ -574,9 +532,11 @@ static bool icarus_detect_one(const char *devpath)
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
 	char *nonce_hex;
 	char *nonce_hex;
 
 
-	int baud, work_division, fpga_count;
+	get_options(this_option_offset, info);
 
 
-	get_options(this_option_offset, &baud, &work_division, &fpga_count);
+	int baud = info->baud;
+	int work_division = info->work_division;
+	int fpga_count = info->fpga_count;
 
 
 	applog(LOG_DEBUG, "Icarus Detect: Attempting to open %s", devpath);
 	applog(LOG_DEBUG, "Icarus Detect: Attempting to open %s", devpath);
 
 
@@ -617,14 +577,19 @@ static bool icarus_detect_one(const char *devpath)
 	} else
 	} else
 		return false;
 		return false;
 
 
+	if (serial_claim(devpath, api)) {
+		const char *claimedby = serial_claim(devpath, api)->dname;
+		applog(LOG_DEBUG, "Icarus device %s already claimed by other driver: %s", devpath, claimedby);
+		return false;
+	}
+
 	/* We have a real Icarus! */
 	/* We have a real Icarus! */
 	struct cgpu_info *icarus;
 	struct cgpu_info *icarus;
 	icarus = calloc(1, sizeof(struct cgpu_info));
 	icarus = calloc(1, sizeof(struct cgpu_info));
-	icarus->api = &icarus_api;
+	icarus->api = api;
 	icarus->device_path = strdup(devpath);
 	icarus->device_path = strdup(devpath);
 	icarus->threads = 1;
 	icarus->threads = 1;
 	add_cgpu(icarus);
 	add_cgpu(icarus);
-	icarus_info = realloc(icarus_info, sizeof(struct ICARUS_INFO *) * (total_devices + 1));
 
 
 	applog(LOG_INFO, "Found Icarus at %s, mark as %d",
 	applog(LOG_INFO, "Found Icarus at %s, mark as %d",
 		devpath, icarus->device_id);
 		devpath, icarus->device_id);
@@ -632,19 +597,8 @@ static bool icarus_detect_one(const char *devpath)
 	applog(LOG_DEBUG, "Icarus: Init: %d baud=%d work_division=%d fpga_count=%d",
 	applog(LOG_DEBUG, "Icarus: Init: %d baud=%d work_division=%d fpga_count=%d",
 		icarus->device_id, baud, work_division, fpga_count);
 		icarus->device_id, baud, work_division, fpga_count);
 
 
-	// Since we are adding a new device on the end it needs to always be allocated
-	icarus_info[icarus->device_id] = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO));
-	if (unlikely(!(icarus_info[icarus->device_id])))
-		quit(1, "Failed to malloc ICARUS_INFO");
-
-	info = icarus_info[icarus->device_id];
-
-	// Initialise everything to zero for a new device
-	memset(info, 0, sizeof(struct ICARUS_INFO));
+	icarus->cgpu_data = info;
 
 
-	info->baud = baud;
-	info->work_division = work_division;
-	info->fpga_count = fpga_count;
 	info->nonce_mask = mask(work_division);
 	info->nonce_mask = mask(work_division);
 
 
 	info->golden_hashes = (golden_nonce_val & info->nonce_mask) * fpga_count;
 	info->golden_hashes = (golden_nonce_val & info->nonce_mask) * fpga_count;
@@ -655,6 +609,25 @@ static bool icarus_detect_one(const char *devpath)
 	return true;
 	return true;
 }
 }
 
 
+static bool icarus_detect_one(const char *devpath)
+{
+	struct ICARUS_INFO *info = calloc(1, sizeof(struct ICARUS_INFO));
+	if (unlikely(!info))
+		quit(1, "Failed to malloc ICARUS_INFO");
+
+	info->baud = ICARUS_IO_SPEED;
+	info->work_division = 2;
+	info->fpga_count = 2;
+	info->quirk_reopen = 1;
+	info->Hs = ICARUS_REV3_HASH_TIME;
+
+	if (!icarus_detect_custom(devpath, &icarus_api, info)) {
+		free(info);
+		return false;
+	}
+	return true;
+}
+
 static void icarus_detect()
 static void icarus_detect()
 {
 {
 	serial_detect(icarus_api.dname, icarus_detect_one);
 	serial_detect(icarus_api.dname, icarus_detect_one);
@@ -671,10 +644,11 @@ struct icarus_state {
 static bool icarus_prepare(struct thr_info *thr)
 static bool icarus_prepare(struct thr_info *thr)
 {
 {
 	struct cgpu_info *icarus = thr->cgpu;
 	struct cgpu_info *icarus = thr->cgpu;
+	struct ICARUS_INFO *info = icarus->cgpu_data;
 
 
 	struct timeval now;
 	struct timeval now;
 
 
-	int fd = icarus_open2(icarus->device_path, icarus_info[icarus->device_id]->baud, true);
+	int fd = icarus_open2(icarus->device_path, info->baud, true);
 	if (unlikely(-1 == fd)) {
 	if (unlikely(-1 == fd)) {
 		applog(LOG_ERR, "Failed to open Icarus on %s",
 		applog(LOG_ERR, "Failed to open Icarus on %s",
 		       icarus->device_path);
 		       icarus->device_path);
@@ -703,6 +677,21 @@ static bool icarus_prepare(struct thr_info *thr)
 	return true;
 	return true;
 }
 }
 
 
+static bool icarus_reopen(struct cgpu_info *icarus, struct icarus_state *state, int *fdp)
+{
+	struct ICARUS_INFO *info = icarus->cgpu_data;
+
+	// Reopen the serial port to workaround a USB-host-chipset-specific issue with the Icarus's buggy USB-UART
+	icarus_close(icarus->device_fd);
+	*fdp = icarus->device_fd = icarus_open(icarus->device_path, info->baud);
+	if (unlikely(-1 == *fdp)) {
+		applog(LOG_ERR, "%s %u: Failed to reopen on %s", icarus->api->name, icarus->device_id, icarus->device_path);
+		state->firstrun = true;
+		return false;
+	}
+	return true;
+}
+
 static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 				__maybe_unused int64_t max_nonce)
 				__maybe_unused int64_t max_nonce)
 {
 {
@@ -742,7 +731,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 
 	// Wait for the previous run's result
 	// Wait for the previous run's result
 	fd = icarus->device_fd;
 	fd = icarus->device_fd;
-	info = icarus_info[icarus->device_id];
+	info = icarus->cgpu_data;
 
 
 	if (!state->firstrun) {
 	if (!state->firstrun) {
 		if (state->changework)
 		if (state->changework)
@@ -754,18 +743,28 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		{
 		{
 			/* Icarus will return 4 bytes (ICARUS_READ_SIZE) nonces or nothing */
 			/* Icarus will return 4 bytes (ICARUS_READ_SIZE) nonces or nothing */
 			lret = icarus_gets(nonce_bin, fd, &state->tv_workfinish, thr, info->read_count);
 			lret = icarus_gets(nonce_bin, fd, &state->tv_workfinish, thr, info->read_count);
-			if (lret && thr->work_restart) {
+			if (lret) {
+				if (thr->work_restart) {
+
 				// The prepared work is invalid, and the current work is abandoned
 				// The prepared work is invalid, and the current work is abandoned
 				// Go back to the main loop to get the next work, and stuff
 				// Go back to the main loop to get the next work, and stuff
 				// Returning to the main loop will clear work_restart, so use a flag...
 				// Returning to the main loop will clear work_restart, so use a flag...
 				state->changework = true;
 				state->changework = true;
 				return 0;
 				return 0;
+
+				}
+				if (info->quirk_reopen == 1 && !icarus_reopen(icarus, state, &fd))
+					return 0;
 			}
 			}
+			
 		}
 		}
 
 
 		tv_start = state->tv_workstart;
 		tv_start = state->tv_workstart;
 		timersub(&state->tv_workfinish, &tv_start, &elapsed);
 		timersub(&state->tv_workfinish, &tv_start, &elapsed);
 	}
 	}
+	else
+	if (fd == -1 && !icarus_reopen(icarus, state, &fd))
+		return 0;
 
 
 #ifndef WIN32
 #ifndef WIN32
 	tcflush(fd, TCOFLUSH);
 	tcflush(fd, TCOFLUSH);
@@ -788,15 +787,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		}
 		}
 	}
 	}
 
 
-	// Reopen the serial port to workaround a USB-host-chipset-specific issue with the Icarus's buggy USB-UART
-	icarus_close(fd);
-	fd = icarus_open(icarus->device_path, icarus_info[icarus->device_id]->baud);
-	if (unlikely(-1 == fd)) {
-		applog(LOG_ERR, "Failed to reopen Icarus on %s",
-		       icarus->device_path);
+	if (info->quirk_reopen == 2 && !icarus_reopen(icarus, state, &fd))
 		return 0;
 		return 0;
-	}
-	icarus->device_fd = fd;
 
 
 	work->blk.nonce = 0xffffffff;
 	work->blk.nonce = 0xffffffff;
 
 
@@ -845,6 +837,36 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 				icarus->device_id, nonce, hash_count, elapsed.tv_sec, elapsed.tv_usec);
 				icarus->device_id, nonce, hash_count, elapsed.tv_sec, elapsed.tv_usec);
 	}
 	}
 
 
+	if (info->do_default_detection && elapsed.tv_sec >= DEFAULT_DETECT_THRESHOLD) {
+		int MHs = (double)hash_count / ((double)elapsed.tv_sec * 1e6 + (double)elapsed.tv_usec);
+		--info->do_default_detection;
+		applog(LOG_DEBUG, "%s %u: Autodetect device speed: %d MH/s", icarus->api->name, icarus->device_id, MHs);
+		if (MHs <= 370 || MHs > 420) {
+			// Not a real Icarus: enable short timing
+			applog(LOG_WARNING, "%s %u: Seems too %s to be an Icarus; calibrating with short timing", icarus->api->name, icarus->device_id, MHs>380?"fast":"slow");
+			info->timing_mode = MODE_SHORT;
+			info->do_icarus_timing = true;
+			info->do_default_detection = 0;
+		}
+		else
+		if (MHs <= 380) {
+			// Real Icarus?
+			if (!info->do_default_detection) {
+				applog(LOG_DEBUG, "%s %u: Seems to be a real Icarus", icarus->api->name, icarus->device_id);
+				info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+			}
+		}
+		else
+		if (MHs <= 420) {
+			// Enterpoint Cairnsmore1
+			const char *old_name = icarus->api->name;
+			int old_devid = icarus->device_id;
+			convert_icarus_to_cairnsmore(icarus);
+			info->do_default_detection = 0;
+			applog(LOG_WARNING, "%s %u: Detected Cairnsmore1 device, upgrading driver to %s %u", old_name, old_devid, icarus->api->name, icarus->device_id);
+		}
+	}
+
 	// ignore possible end condition values
 	// ignore possible end condition values
 	if (info->do_icarus_timing
 	if (info->do_icarus_timing
 	&&  ((nonce & info->nonce_mask) > END_CONDITION)
 	&&  ((nonce & info->nonce_mask) > END_CONDITION)
@@ -949,7 +971,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 static struct api_data *icarus_api_stats(struct cgpu_info *cgpu)
 static struct api_data *icarus_api_stats(struct cgpu_info *cgpu)
 {
 {
 	struct api_data *root = NULL;
 	struct api_data *root = NULL;
-	struct ICARUS_INFO *info = icarus_info[cgpu->device_id];
+	struct ICARUS_INFO *info = cgpu->cgpu_data;
 
 
 	// Warning, access to these is not locked - but we don't really
 	// Warning, access to these is not locked - but we don't really
 	// care since hashing performance is way more important than
 	// care since hashing performance is way more important than

+ 167 - 3
fpgautils.c

@@ -11,6 +11,7 @@
 #include "config.h"
 #include "config.h"
 
 
 #include <stdint.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <sys/types.h>
 #include <dirent.h>
 #include <dirent.h>
 #include <string.h>
 #include <string.h>
@@ -24,10 +25,26 @@
 #ifndef O_CLOEXEC
 #ifndef O_CLOEXEC
 #define O_CLOEXEC 0
 #define O_CLOEXEC 0
 #endif
 #endif
-#else
+#else  /* WIN32 */
 #include <windows.h>
 #include <windows.h>
 #include <io.h>
 #include <io.h>
-#endif
+
+#define dlsym (void*)GetProcAddress
+#define dlclose FreeLibrary
+
+typedef unsigned long FT_STATUS;
+typedef PVOID FT_HANDLE;
+__stdcall FT_STATUS (*FT_ListDevices)(PVOID pArg1, PVOID pArg2, DWORD Flags);
+__stdcall FT_STATUS (*FT_Open)(int idx, FT_HANDLE*);
+__stdcall FT_STATUS (*FT_GetComPortNumber)(FT_HANDLE, LPLONG lplComPortNumber);
+__stdcall FT_STATUS (*FT_Close)(FT_HANDLE);
+const uint32_t FT_OPEN_BY_DESCRIPTION =       2;
+const uint32_t FT_LIST_ALL         = 0x20000000;
+const uint32_t FT_LIST_NUMBER_ONLY = 0x80000000;
+enum {
+	FT_OK,
+};
+#endif  /* WIN32 */
 
 
 #ifdef HAVE_LIBUDEV
 #ifdef HAVE_LIBUDEV
 #include <libudev.h>
 #include <libudev.h>
@@ -108,13 +125,98 @@ serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
 #endif
 #endif
 }
 }
 
 
+#ifdef WIN32
+#define LOAD_SYM(sym)  do { \
+	if (!(sym = dlsym(dll, #sym))) {  \
+		applog(LOG_DEBUG, "Failed to load " #sym ", not using FTDI autodetect");  \
+		goto out;  \
+	}  \
+} while(0)
+
+int serial_autodetect_ftdi(detectone_func_t detectone, const char *needle, const char *needle2)
+{
+	char devpath[] = "\\\\.\\COMnnnnn";
+	char *devpathnum = &devpath[7];
+	char **bufptrs;
+	char *buf;
+	int found = 0;
+	int i;
+
+	FT_STATUS ftStatus;
+	DWORD numDevs;
+	HMODULE dll = LoadLibrary("FTD2XX.DLL");
+	if (!dll) {
+		applog(LOG_DEBUG, "FTD2XX.DLL failed to load, not using FTDI autodetect");
+		return 0;
+	}
+	LOAD_SYM(FT_ListDevices);
+	LOAD_SYM(FT_Open);
+	LOAD_SYM(FT_GetComPortNumber);
+	LOAD_SYM(FT_Close);
+	
+	ftStatus = FT_ListDevices(&numDevs, NULL, FT_LIST_NUMBER_ONLY);
+	if (ftStatus != FT_OK) {
+		applog(LOG_DEBUG, "FTDI device count failed, not using FTDI autodetect");
+		goto out;
+	}
+	applog(LOG_DEBUG, "FTDI reports %u devices", (unsigned)numDevs);
+
+	buf = alloca(65 * numDevs);
+	bufptrs = alloca(sizeof(*bufptrs) * (numDevs + 1));
+
+	for (i = 0; i < numDevs; ++i)
+		bufptrs[i] = &buf[i * 65];
+	bufptrs[numDevs] = NULL;
+	ftStatus = FT_ListDevices(bufptrs, &numDevs, FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION);
+	if (ftStatus != FT_OK) {
+		applog(LOG_DEBUG, "FTDI device list failed, not using FTDI autodetect");
+		goto out;
+	}
+	
+	for (i = numDevs; i > 0; ) {
+		--i;
+		bufptrs[i][64] = '\0';
+		
+		if (!(strstr(bufptrs[i], needle) && (!needle2 || strstr(bufptrs[i], needle2))))
+			continue;
+		
+		FT_HANDLE ftHandle;
+		if (FT_OK != FT_Open(i, &ftHandle))
+			continue;
+		LONG lComPortNumber;
+		ftStatus = FT_GetComPortNumber(ftHandle, &lComPortNumber);
+		FT_Close(ftHandle);
+		if (FT_OK != ftStatus || lComPortNumber < 0)
+			continue;
+		
+		sprintf(devpathnum, "%d", (int)lComPortNumber);
+		
+		if (detectone(devpath))
+			++found;
+	}
+
+out:
+	dlclose(dll);
+	return found;
+}
+#else
+int serial_autodetect_ftdi(__maybe_unused detectone_func_t detectone, __maybe_unused const char *needle, __maybe_unused const char *needle2)
+{
+	return 0;
+}
+#endif
+
+struct device_api *serial_claim(const char *devpath, struct device_api *api);
+
 int
 int
-_serial_detect(const char*dname, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto)
+_serial_detect(const char*dname, detectone_func_t detectone, autoscan_func_t autoscan, int flags)
 {
 {
 	struct string_elist *iter, *tmp;
 	struct string_elist *iter, *tmp;
 	const char*s, *p;
 	const char*s, *p;
 	bool inhibitauto = false;
 	bool inhibitauto = false;
 	char found = 0;
 	char found = 0;
+	bool forceauto = flags & 1;
+	bool hasname;
 	size_t dnamel = strlen(dname);
 	size_t dnamel = strlen(dname);
 
 
 	list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
 	list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
@@ -124,16 +226,28 @@ _serial_detect(const char*dname, detectone_func_t detectone, autoscan_func_t aut
 			if (plen != dnamel || strncasecmp(s, dname, plen))
 			if (plen != dnamel || strncasecmp(s, dname, plen))
 				continue;
 				continue;
 			s = p + 1;
 			s = p + 1;
+			hasname = true;
 		}
 		}
+		else
+			hasname = false;
 		if (!strcmp(s, "auto"))
 		if (!strcmp(s, "auto"))
 			forceauto = true;
 			forceauto = true;
 		else
 		else
 		if (!strcmp(s, "noauto"))
 		if (!strcmp(s, "noauto"))
 			inhibitauto = true;
 			inhibitauto = true;
 		else
 		else
+		if ((flags & 2) && !hasname)
+			continue;
+		else
 		if (!detectone)
 		if (!detectone)
 		{}  // do nothing
 		{}  // do nothing
 		else
 		else
+		if (serial_claim(s, NULL))
+		{
+			applog(LOG_DEBUG, "%s is already claimed... skipping probes", s);
+			string_elist_del(iter);
+		}
+		else
 		if (detectone(s)) {
 		if (detectone(s)) {
 			string_elist_del(iter);
 			string_elist_del(iter);
 			inhibitauto = true;
 			inhibitauto = true;
@@ -147,6 +261,56 @@ _serial_detect(const char*dname, detectone_func_t detectone, autoscan_func_t aut
 	return found;
 	return found;
 }
 }
 
 
+#ifndef WIN32
+typedef dev_t my_dev_t;
+#else
+typedef int my_dev_t;
+#endif
+
+struct _device_claim {
+	struct device_api *api;
+	my_dev_t dev;
+	UT_hash_handle hh;
+};
+
+struct device_api *serial_claim(const char *devpath, struct device_api *api)
+{
+	static struct _device_claim *claims = NULL;
+	struct _device_claim *c;
+	my_dev_t dev;
+
+#ifndef WIN32
+	{
+		struct stat my_stat;
+		if (stat(devpath, &my_stat))
+			return NULL;
+		dev = my_stat.st_rdev;
+	}
+#else
+	{
+		char *p = strstr(devpath, "COM"), *p2;
+		if (!p)
+			return NULL;
+		dev = strtol(&p[3], &p2, 10);
+		if (p2 == p)
+			return NULL;
+	}
+#endif
+
+	HASH_FIND(hh, claims, &dev, sizeof(dev), c);
+	if (c)
+		return c->api;
+
+	if (!api)
+		return NULL;
+
+	c = malloc(sizeof(*c));
+	c->dev = dev;
+	c->api = api;
+	HASH_ADD(hh, claims, dev, sizeof(dev), c);
+	return NULL;
+}
+
 // This code is purely for debugging but is very useful for that
 // This code is purely for debugging but is very useful for that
 // It also took quite a bit of effort so I left it in
 // It also took quite a bit of effort so I left it in
 // #define TERMIOS_DEBUG 1
 // #define TERMIOS_DEBUG 1

+ 10 - 5
fpgautils.h

@@ -17,17 +17,22 @@
 typedef bool(*detectone_func_t)(const char*);
 typedef bool(*detectone_func_t)(const char*);
 typedef int(*autoscan_func_t)();
 typedef int(*autoscan_func_t)();
 
 
-extern int _serial_detect(const char*dname, detectone_func_t, autoscan_func_t, bool force_autoscan);
+extern int _serial_detect(const char*dname, detectone_func_t, autoscan_func_t, int flags);
 #define serial_detect_fauto(dname, detectone, autoscan)  \
 #define serial_detect_fauto(dname, detectone, autoscan)  \
-	_serial_detect(dname, detectone, autoscan, true)
+	_serial_detect(dname, detectone, autoscan, 1)
 #define serial_detect_auto(dname, detectone, autoscan)  \
 #define serial_detect_auto(dname, detectone, autoscan)  \
-	_serial_detect(dname, detectone, autoscan, false)
+	_serial_detect(dname, detectone, autoscan, 0)
+#define serial_detect_auto_byname(dname, detectone, autoscan)  \
+	_serial_detect(dname, detectone, autoscan, 2)
 #define serial_detect(dname, detectone)  \
 #define serial_detect(dname, detectone)  \
-	_serial_detect(dname, detectone,     NULL, false)
+	_serial_detect(dname, detectone,     NULL, 0)
 #define noserial_detect(dname, autoscan)  \
 #define noserial_detect(dname, autoscan)  \
-	_serial_detect(dname, NULL     , autoscan, false)
+	_serial_detect(dname, NULL     , autoscan, 0)
 extern int serial_autodetect_devserial(detectone_func_t, const char*prodname);
 extern int serial_autodetect_devserial(detectone_func_t, const char*prodname);
 extern int serial_autodetect_udev     (detectone_func_t, const char*prodname);
 extern int serial_autodetect_udev     (detectone_func_t, const char*prodname);
+extern int serial_autodetect_ftdi     (detectone_func_t, const char*needle, const char *needle2);
+
+extern struct device_api *serial_claim(const char *devpath, struct device_api *);
 
 
 extern int serial_open(const char*devpath, unsigned long baud, uint8_t timeout, bool purge);
 extern int serial_open(const char*devpath, unsigned long baud, uint8_t timeout, bool purge);
 extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char*eol);
 extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char*eol);

+ 76 - 0
icarus-common.h

@@ -0,0 +1,76 @@
+#ifndef ICARUS_COMMON_H
+#define ICARUS_COMMON_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+#include "miner.h"
+
+// Fraction of a second, USB timeout is measured in
+// i.e. 10 means 1/10 of a second
+// Right now, it MUST be 10 due to other assumptions.
+#define TIME_FACTOR 10
+// It's 10 per second, thus value = 10/TIME_FACTOR =
+#define ICARUS_READ_FAULT_DECISECONDS 1
+
+#define NANOSEC 1000000000.0
+
+
+// Store the last INFO_HISTORY data sets
+// [0] = current data, not yet ready to be included as an estimate
+// Each new data set throws the last old set off the end thus
+// keeping a ongoing average of recent data
+#define INFO_HISTORY 10
+
+struct ICARUS_HISTORY {
+	struct timeval finish;
+	double sumXiTi;
+	double sumXi;
+	double sumTi;
+	double sumXi2;
+	uint32_t values;
+	uint32_t hash_count_min;
+	uint32_t hash_count_max;
+};
+
+enum timing_mode { MODE_DEFAULT, MODE_SHORT, MODE_LONG, MODE_VALUE };
+
+struct ICARUS_INFO {
+	// time to calculate the golden_ob
+	uint64_t golden_hashes;
+	struct timeval golden_tv;
+
+	struct ICARUS_HISTORY history[INFO_HISTORY+1];
+	uint32_t min_data_count;
+
+	// seconds per Hash
+	double Hs;
+	int read_count;
+
+	enum timing_mode timing_mode;
+	bool do_icarus_timing;
+	int do_default_detection;
+
+	double fullnonce;
+	int count;
+	double W;
+	uint32_t values;
+	uint64_t hash_count_range;
+
+	// Determine the cost of history processing
+	// (which will only affect W)
+	uint64_t history_count;
+	struct timeval history_time;
+
+	// icarus-options
+	int baud;
+	int work_division;
+	int fpga_count;
+	uint32_t nonce_mask;
+	bool quirk_reopen;
+};
+
+bool icarus_detect_custom(const char *devpath, struct device_api *, struct ICARUS_INFO *);
+
+#endif

+ 10 - 1
miner.c

@@ -5768,6 +5768,7 @@ extern struct device_api bitforce_api;
 #endif
 #endif
 
 
 #ifdef USE_ICARUS
 #ifdef USE_ICARUS
+extern struct device_api cairnsmore_api;
 extern struct device_api icarus_api;
 extern struct device_api icarus_api;
 #endif
 #endif
 
 
@@ -5803,7 +5804,7 @@ struct _cgpu_devid_counter {
 	UT_hash_handle hh;
 	UT_hash_handle hh;
 };
 };
 
 
-bool add_cgpu(struct cgpu_info*cgpu)
+void renumber_cgpu(struct cgpu_info *cgpu)
 {
 {
 	static struct _cgpu_devid_counter *devids = NULL;
 	static struct _cgpu_devid_counter *devids = NULL;
 	struct _cgpu_devid_counter *d;
 	struct _cgpu_devid_counter *d;
@@ -5817,6 +5818,11 @@ bool add_cgpu(struct cgpu_info*cgpu)
 		cgpu->device_id = d->lastid = 0;
 		cgpu->device_id = d->lastid = 0;
 		HASH_ADD_STR(devids, name, d);
 		HASH_ADD_STR(devids, name, d);
 	}
 	}
+}
+
+bool add_cgpu(struct cgpu_info*cgpu)
+{
+	renumber_cgpu(cgpu);
 	devices = realloc(devices, sizeof(struct cgpu_info *) * (total_devices + 2));
 	devices = realloc(devices, sizeof(struct cgpu_info *) * (total_devices + 2));
 	devices[total_devices++] = cgpu;
 	devices[total_devices++] = cgpu;
 	return true;
 	return true;
@@ -6033,7 +6039,10 @@ int main(int argc, char *argv[])
 
 
 #ifdef USE_ICARUS
 #ifdef USE_ICARUS
 	if (!opt_scrypt)
 	if (!opt_scrypt)
+	{
+		cairnsmore_api.api_detect();
 		icarus_api.api_detect();
 		icarus_api.api_detect();
+	}
 #endif
 #endif
 
 
 #ifdef USE_BITFORCE
 #ifdef USE_BITFORCE

+ 2 - 0
miner.h

@@ -372,6 +372,7 @@ struct cgpu_info {
 	bool nonce_range;
 	bool nonce_range;
 	bool polling;
 	bool polling;
 #endif
 #endif
+	void *cgpu_data;
 	pthread_mutex_t		device_mutex;
 	pthread_mutex_t		device_mutex;
 
 
 	enum dev_enable deven;
 	enum dev_enable deven;
@@ -453,6 +454,7 @@ struct cgpu_info {
 	struct cgminer_stats cgminer_stats;
 	struct cgminer_stats cgminer_stats;
 };
 };
 
 
+extern void renumber_cgpu(struct cgpu_info *);
 extern bool add_cgpu(struct cgpu_info*);
 extern bool add_cgpu(struct cgpu_info*);
 
 
 struct thread_q {
 struct thread_q {