Browse Source

cairnsmore: Beginnings of new driver, with automatic upgrade from Icarus detection

CAIRNSMORE1_HASH_TIME based on 10000 samples
Luke Dashjr 13 years ago
parent
commit
8445ce898f
8 changed files with 281 additions and 117 deletions
  1. 2 1
      Makefile.am
  2. 70 0
      driver-cairnsmore.c
  3. 106 110
      driver-icarus.c
  4. 9 1
      fpgautils.c
  5. 6 4
      fpgautils.h
  6. 76 0
      icarus-common.h
  7. 10 1
      miner.c
  8. 2 0
      miner.h

+ 2 - 1
Makefile.am

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

+ 70 - 0
driver-cairnsmore.c

@@ -0,0 +1,70 @@
+/*
+ * 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;
+
+	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") ?:
+	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;
+}

+ 106 - 110
driver-icarus.c

@@ -56,6 +56,7 @@
 
 #include "elist.h"
 #include "fpgautils.h"
+#include "icarus-common.h"
 #include "miner.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))
 
-// 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
 // 5 seconds allows for up to a ~840MH/s device
 #define ICARUS_READ_COUNT_TIMING	(5 * TIME_FACTOR)
 
 // For a standard Icarus REV3
 #define ICARUS_REV3_HASH_TIME 0.00000000264083
-#define NANOSEC 1000000000.0
 
 // Icarus Rev3 doesn't send a completion message when it finishes
 // the full nonce range, so to avoid being idle we must abort the
@@ -134,69 +127,14 @@ ASSERT1(sizeof(uint32_t) == 4);
 
 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_SHORT_STR = "short";
 static const char *MODE_LONG_STR = "long";
 static const char *MODE_VALUE_STR = "value";
 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;
-	bool quirk_reopen;
-};
-
 #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:
 //
@@ -217,6 +155,8 @@ static int option_offset = -1;
 
 struct device_api icarus_api;
 
+extern void convert_icarus_to_cairnsmore(struct cgpu_info *);
+
 static void rev(unsigned char *s, size_t l)
 {
 	size_t i, j;
@@ -351,7 +291,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)
 {
-	struct ICARUS_INFO *info = icarus_info[icarus->device_id];
+	struct ICARUS_INFO *info = icarus->cgpu_data;
 	double Hs;
 	char buf[BUFSIZ+1];
 	char *ptr, *comma, *eq;
@@ -421,10 +361,12 @@ static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 			info->read_count = atoi(eq+1);
 
 		if (info->read_count < 1)
-			info->read_count = (int)(info->fullnonce * TIME_FACTOR) - 1;
+			info->read_count = ICARUS_READ_COUNT_TIMING;
 
 		info->timing_mode = MODE_DEFAULT;
 		info->do_icarus_timing = false;
+		if (icarus->api == &icarus_api)
+			info->do_default_detection = 0x10;
 	}
 
 	info->min_data_count = MIN_DATA_COUNT;
@@ -460,15 +402,18 @@ static uint32_t mask(int work_division)
 	return nonce_mask;
 }
 
-static void get_options(int this_option_offset, int *baud, int *work_division, int *fpga_count, char **quirkstr)
+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 buf[BUFSIZ+1];
 	char *ptr, *comma, *colon, *colon2;
 	size_t max;
 	int i, tmp;
 
-	*quirkstr = "";
 	if (opt_icarus_options == NULL)
 		buf[0] = '\0';
 	else {
@@ -492,10 +437,6 @@ static void get_options(int this_option_offset, int *baud, int *work_division, i
 		buf[max] = '\0';
 	}
 
-	*baud = ICARUS_IO_SPEED;
-	*work_division = 2;
-	*fpga_count = 2;
-
 	if (*buf) {
 		colon = strchr(buf, ':');
 		if (colon)
@@ -548,18 +489,23 @@ static void get_options(int this_option_offset, int *baud, int *work_division, i
 			  }
 
 			  if (colon && *colon) {
-					*quirkstr = 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;
 
-	struct ICARUS_INFO *info;
 	struct timeval tv_start, tv_finish;
 	int fd;
 
@@ -585,10 +531,11 @@ static bool icarus_detect_one(const char *devpath)
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
 	char *nonce_hex;
 
-	int baud, work_division, fpga_count;
-	char *quirkstr;
+	get_options(this_option_offset, info);
 
-	get_options(this_option_offset, &baud, &work_division, &fpga_count, &quirkstr);
+	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);
 
@@ -632,11 +579,10 @@ static bool icarus_detect_one(const char *devpath)
 	/* We have a real Icarus! */
 	struct cgpu_info *icarus;
 	icarus = calloc(1, sizeof(struct cgpu_info));
-	icarus->api = &icarus_api;
+	icarus->api = api;
 	icarus->device_path = strdup(devpath);
 	icarus->threads = 1;
 	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",
 		devpath, icarus->device_id);
@@ -644,22 +590,9 @@ static bool icarus_detect_one(const char *devpath)
 	applog(LOG_DEBUG, "Icarus: Init: %d baud=%d work_division=%d fpga_count=%d",
 		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];
+	icarus->cgpu_data = info;
 
-	// Initialise everything to zero for a new device
-	memset(info, 0, sizeof(struct ICARUS_INFO));
-
-	info->baud = baud;
-	info->work_division = work_division;
-	info->fpga_count = fpga_count;
 	info->nonce_mask = mask(work_division);
-	quirkstr = strchr(quirkstr, '-');
-	info->quirk_reopen = quirkstr ? !strchr(quirkstr, 'r') : true;
 
 	info->golden_hashes = (golden_nonce_val & info->nonce_mask) * fpga_count;
 	timersub(&tv_finish, &tv_start, &(info->golden_tv));
@@ -669,6 +602,24 @@ static bool icarus_detect_one(const char *devpath)
 	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;
+
+	if (!icarus_detect_custom(devpath, &icarus_api, info)) {
+		free(info);
+		return false;
+	}
+	return true;
+}
+
 static void icarus_detect()
 {
 	serial_detect(icarus_api.dname, icarus_detect_one);
@@ -685,10 +636,11 @@ struct icarus_state {
 static bool icarus_prepare(struct thr_info *thr)
 {
 	struct cgpu_info *icarus = thr->cgpu;
+	struct ICARUS_INFO *info = icarus->cgpu_data;
 
 	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)) {
 		applog(LOG_ERR, "Failed to open Icarus on %s",
 		       icarus->device_path);
@@ -717,6 +669,21 @@ static bool icarus_prepare(struct thr_info *thr)
 	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,
 				__maybe_unused int64_t max_nonce)
 {
@@ -756,7 +723,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 
 	// Wait for the previous run's result
 	fd = icarus->device_fd;
-	info = icarus_info[icarus->device_id];
+	info = icarus->cgpu_data;
 
 	if (!state->firstrun) {
 		if (state->changework)
@@ -765,18 +732,28 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		{
 			/* Icarus will return 4 bytes (ICARUS_READ_SIZE) nonces or nothing */
 			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
 				// 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...
 				state->changework = true;
 				return 0;
+
+				}
+				if (info->quirk_reopen == 1 && !icarus_reopen(icarus, state, &fd))
+					return 0;
 			}
+			
 		}
 
 		tv_start = state->tv_workstart;
 		timersub(&state->tv_workfinish, &tv_start, &elapsed);
 	}
+	else
+	if (fd == -1 && !icarus_reopen(icarus, state, &fd))
+		return 0;
 
 #ifndef WIN32
 	tcflush(fd, TCOFLUSH);
@@ -799,19 +776,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 		}
 	}
 
-	if (info->quirk_reopen) {
-
-	// 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;
-	}
-	icarus->device_fd = fd;
-
-	}
 
 	work->blk.nonce = 0xffffffff;
 
@@ -860,6 +826,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);
 	}
 
+	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
 	if (info->do_icarus_timing
 	&&  ((nonce & info->nonce_mask) > END_CONDITION)
@@ -964,7 +960,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 static struct api_data *icarus_api_stats(struct cgpu_info *cgpu)
 {
 	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
 	// care since hashing performance is way more important than

+ 9 - 1
fpgautils.c

@@ -109,12 +109,14 @@ serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
 }
 
 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;
 	const char*s, *p;
 	bool inhibitauto = false;
 	char found = 0;
+	bool forceauto = flags & 1;
+	bool hasname;
 	size_t dnamel = strlen(dname);
 
 	list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
@@ -124,13 +126,19 @@ _serial_detect(const char*dname, detectone_func_t detectone, autoscan_func_t aut
 			if (plen != dnamel || strncasecmp(s, dname, plen))
 				continue;
 			s = p + 1;
+			hasname = true;
 		}
+		else
+			hasname = false;
 		if (!strcmp(s, "auto"))
 			forceauto = true;
 		else
 		if (!strcmp(s, "noauto"))
 			inhibitauto = true;
 		else
+		if ((flags & 2) && !hasname)
+			continue;
+		else
 		if (detectone(s)) {
 			string_elist_del(iter);
 			inhibitauto = true;

+ 6 - 4
fpgautils.h

@@ -17,13 +17,15 @@
 typedef bool(*detectone_func_t)(const char*);
 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)  \
-	_serial_detect(dname, detectone, autoscan, true)
+	_serial_detect(dname, detectone, autoscan, 1)
 #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)  \
-	_serial_detect(dname, detectone,     NULL, false)
+	_serial_detect(dname, detectone,     NULL, 0)
 extern int serial_autodetect_devserial(detectone_func_t, const char*prodname);
 extern int serial_autodetect_udev     (detectone_func_t, const char*prodname);
 

+ 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

@@ -5691,6 +5691,7 @@ extern struct device_api bitforce_api;
 #endif
 
 #ifdef USE_ICARUS
+extern struct device_api cairnsmore_api;
 extern struct device_api icarus_api;
 #endif
 
@@ -5726,7 +5727,7 @@ struct _cgpu_devid_counter {
 	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;
 	struct _cgpu_devid_counter *d;
@@ -5740,6 +5741,11 @@ bool add_cgpu(struct cgpu_info*cgpu)
 		cgpu->device_id = d->lastid = 0;
 		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[total_devices++] = cgpu;
 	return true;
@@ -5956,7 +5962,10 @@ int main(int argc, char *argv[])
 
 #ifdef USE_ICARUS
 	if (!opt_scrypt)
+	{
+		cairnsmore_api.api_detect();
 		icarus_api.api_detect();
+	}
 #endif
 
 #ifdef USE_BITFORCE

+ 2 - 0
miner.h

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