Browse Source

Merge branch 'master' into hashfast

Con Kolivas 12 years ago
parent
commit
118f9038a0
15 changed files with 871 additions and 456 deletions
  1. 1 4
      api-example.c
  2. 1 0
      api.c
  3. 226 188
      cgminer.c
  4. 3 0
      compat/.gitignore
  5. 23 5
      configure.ac
  6. 1 1
      driver-avalon.c
  7. 9 8
      driver-bflsc.c
  8. 9 8
      driver-bitforce.c
  9. 62 14
      driver-icarus.c
  10. 14 2
      miner.h
  11. 1 0
      ocl.c
  12. 422 146
      usbutils.c
  13. 13 7
      usbutils.h
  14. 80 73
      util.c
  15. 6 0
      util.h

+ 1 - 4
api-example.c

@@ -8,7 +8,7 @@
  */
  */
 
 
 /* Compile:
 /* Compile:
- *   gcc api-example.c -I compat/jansson -o cgminer-api
+ *   gcc api-example.c -Icompat/jansson -Icompat/libusb-1.0/libusb -o cgminer-api
  */
  */
 
 
 #include "config.h"
 #include "config.h"
@@ -32,7 +32,6 @@
 	#include <arpa/inet.h>
 	#include <arpa/inet.h>
 	#include <netdb.h>
 	#include <netdb.h>
 
 
-	#define SOCKETTYPE int
 	#define SOCKETFAIL(a) ((a) < 0)
 	#define SOCKETFAIL(a) ((a) < 0)
 	#define INVSOCK -1
 	#define INVSOCK -1
 	#define CLOSESOCKET close
 	#define CLOSESOCKET close
@@ -140,8 +139,6 @@
 	#endif
 	#endif
 #endif
 #endif
 
 
-#define RECVSIZE 65500
-
 static const char SEPARATOR = '|';
 static const char SEPARATOR = '|';
 static const char COMMA = ',';
 static const char COMMA = ',';
 static const char EQ = '=';
 static const char EQ = '=';

+ 1 - 0
api.c

@@ -22,6 +22,7 @@
 #include <stdbool.h>
 #include <stdbool.h>
 #include <stdint.h>
 #include <stdint.h>
 #include <unistd.h>
 #include <unistd.h>
+#include <limits.h>
 #include <sys/types.h>
 #include <sys/types.h>
 
 
 #include "compat.h"
 #include "compat.h"

+ 226 - 188
cgminer.c

@@ -27,6 +27,7 @@
 #include <stdarg.h>
 #include <stdarg.h>
 #include <assert.h>
 #include <assert.h>
 #include <signal.h>
 #include <signal.h>
+#include <limits.h>
 
 
 #ifdef USE_USBUTILS
 #ifdef USE_USBUTILS
 #include <semaphore.h>
 #include <semaphore.h>
@@ -42,7 +43,11 @@
 #endif
 #endif
 #include <ccan/opt/opt.h>
 #include <ccan/opt/opt.h>
 #include <jansson.h>
 #include <jansson.h>
+#ifdef HAVE_LIBCURL
 #include <curl/curl.h>
 #include <curl/curl.h>
+#else
+char *curly = ":D";
+#endif
 #include <libgen.h>
 #include <libgen.h>
 #include <sha2.h>
 #include <sha2.h>
 
 
@@ -1632,6 +1637,7 @@ static struct opt_table opt_cmdline_table[] = {
 	OPT_ENDTABLE
 	OPT_ENDTABLE
 };
 };
 
 
+#ifdef HAVE_LIBCURL
 static bool jobj_binary(const json_t *obj, const char *key,
 static bool jobj_binary(const json_t *obj, const char *key,
 			void *buf, size_t buflen, bool required)
 			void *buf, size_t buflen, bool required)
 {
 {
@@ -1654,6 +1660,7 @@ static bool jobj_binary(const json_t *obj, const char *key,
 
 
 	return true;
 	return true;
 }
 }
+#endif
 
 
 static void calc_midstate(struct work *work)
 static void calc_midstate(struct work *work)
 {
 {
@@ -1702,7 +1709,10 @@ void free_work(struct work *work)
 }
 }
 
 
 static void gen_hash(unsigned char *data, unsigned char *hash, int len);
 static void gen_hash(unsigned char *data, unsigned char *hash, int len);
+static void calc_diff(struct work *work, int known);
+char *workpadding = "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000";
 
 
+#ifdef HAVE_LIBCURL
 /* Process transactions with GBT by storing the binary value of the first
 /* Process transactions with GBT by storing the binary value of the first
  * transaction, and the hashes of the remaining transactions since these
  * transaction, and the hashes of the remaining transactions since these
  * remain constant with an altered coinbase when generating work. Must be
  * remain constant with an altered coinbase when generating work. Must be
@@ -1783,7 +1793,6 @@ static unsigned char *__gbt_merkleroot(struct pool *pool)
 	return merkle_hash;
 	return merkle_hash;
 }
 }
 
 
-static void calc_diff(struct work *work, int known);
 static bool work_decode(struct pool *pool, struct work *work, json_t *val);
 static bool work_decode(struct pool *pool, struct work *work, json_t *val);
 
 
 static void update_gbt(struct pool *pool)
 static void update_gbt(struct pool *pool)
@@ -1822,8 +1831,6 @@ static void update_gbt(struct pool *pool)
 	curl_easy_cleanup(curl);
 	curl_easy_cleanup(curl);
 }
 }
 
 
-char *workpadding = "000000800000000000000000000000000000000000000000000000000000000000000000000000000000000080020000";
-
 static void gen_gbt_work(struct pool *pool, struct work *work)
 static void gen_gbt_work(struct pool *pool, struct work *work)
 {
 {
 	unsigned char *merkleroot;
 	unsigned char *merkleroot;
@@ -2030,6 +2037,13 @@ static bool work_decode(struct pool *pool, struct work *work, json_t *val)
 out:
 out:
 	return ret;
 	return ret;
 }
 }
+#else /* HAVE_LIBCURL */
+/* Always true with stratum */
+#define pool_localgen(pool) (true)
+#define json_rpc_call(curl, url, userpass, rpc_req, probe, longpoll, rolltime, pool, share) (NULL)
+#define work_decode(pool, work, val) (false)
+#define gen_gbt_work(pool, work) {}
+#endif /* HAVE_LIBCURL */
 
 
 int dev_from_id(int thr_id)
 int dev_from_id(int thr_id)
 {
 {
@@ -2197,18 +2211,6 @@ static void get_statline(char *buf, size_t bufsiz, struct cgpu_info *cgpu)
 	cgpu->drv->get_statline(buf, bufsiz, cgpu);
 	cgpu->drv->get_statline(buf, bufsiz, cgpu);
 }
 }
 
 
-static void text_print_status(int thr_id)
-{
-	struct cgpu_info *cgpu;
-	char logline[256];
-
-	cgpu = get_thr_cgpu(thr_id);
-	if (cgpu) {
-		get_statline(logline, sizeof(logline), cgpu);
-		printf("%s\n", logline);
-	}
-}
-
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 #define CURBUFSIZ 256
 #define CURBUFSIZ 256
 #define cg_mvwprintw(win, y, x, fmt, ...) do { \
 #define cg_mvwprintw(win, y, x, fmt, ...) do { \
@@ -2348,12 +2350,6 @@ static void curses_print_devstatus(struct cgpu_info *cgpu, int count)
 }
 }
 #endif
 #endif
 
 
-static void print_status(int thr_id)
-{
-	if (!curses_active)
-		text_print_status(thr_id);
-}
-
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 /* Check for window resize. Called with curses mutex locked */
 /* Check for window resize. Called with curses mutex locked */
 static inline void change_logwinsize(void)
 static inline void change_logwinsize(void)
@@ -2645,6 +2641,25 @@ share_result(json_t *val, json_t *res, json_t *err, const struct work *work,
 	}
 	}
 }
 }
 
 
+#ifdef HAVE_LIBCURL
+static void text_print_status(int thr_id)
+{
+	struct cgpu_info *cgpu;
+	char logline[256];
+
+	cgpu = get_thr_cgpu(thr_id);
+	if (cgpu) {
+		get_statline(logline, sizeof(logline), cgpu);
+		printf("%s\n", logline);
+	}
+}
+
+static void print_status(int thr_id)
+{
+	if (!curses_active)
+		text_print_status(thr_id);
+}
+
 static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
 static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
 {
 {
 	char *hexstr = NULL;
 	char *hexstr = NULL;
@@ -2829,6 +2844,62 @@ out:
 	return rc;
 	return rc;
 }
 }
 
 
+static bool get_upstream_work(struct work *work, CURL *curl)
+{
+	struct pool *pool = work->pool;
+	struct cgminer_pool_stats *pool_stats = &(pool->cgminer_pool_stats);
+	struct timeval tv_elapsed;
+	json_t *val = NULL;
+	bool rc = false;
+	char *url;
+
+	applog(LOG_DEBUG, "DBG: sending %s get RPC call: %s", pool->rpc_url, pool->rpc_req);
+
+	url = pool->rpc_url;
+
+	cgtime(&work->tv_getwork);
+
+	val = json_rpc_call(curl, url, pool->rpc_userpass, pool->rpc_req, false,
+			    false, &work->rolltime, pool, false);
+	pool_stats->getwork_attempts++;
+
+	if (likely(val)) {
+		rc = work_decode(pool, work, val);
+		if (unlikely(!rc))
+			applog(LOG_DEBUG, "Failed to decode work in get_upstream_work");
+	} else
+		applog(LOG_DEBUG, "Failed json_rpc_call in get_upstream_work");
+
+	cgtime(&work->tv_getwork_reply);
+	timersub(&(work->tv_getwork_reply), &(work->tv_getwork), &tv_elapsed);
+	pool_stats->getwork_wait_rolling += ((double)tv_elapsed.tv_sec + ((double)tv_elapsed.tv_usec / 1000000)) * 0.63;
+	pool_stats->getwork_wait_rolling /= 1.63;
+
+	timeradd(&tv_elapsed, &(pool_stats->getwork_wait), &(pool_stats->getwork_wait));
+	if (timercmp(&tv_elapsed, &(pool_stats->getwork_wait_max), >)) {
+		pool_stats->getwork_wait_max.tv_sec = tv_elapsed.tv_sec;
+		pool_stats->getwork_wait_max.tv_usec = tv_elapsed.tv_usec;
+	}
+	if (timercmp(&tv_elapsed, &(pool_stats->getwork_wait_min), <)) {
+		pool_stats->getwork_wait_min.tv_sec = tv_elapsed.tv_sec;
+		pool_stats->getwork_wait_min.tv_usec = tv_elapsed.tv_usec;
+	}
+	pool_stats->getwork_calls++;
+
+	work->pool = pool;
+	work->longpoll = false;
+	work->getwork_mode = GETWORK_MODE_POOL;
+	calc_diff(work, 0);
+	total_getworks++;
+	pool->getwork_requested++;
+
+	if (likely(val))
+		json_decref(val);
+
+	return rc;
+}
+#endif /* HAVE_LIBCURL */
+
 /* Specifies whether we can use this pool for work or not. */
 /* Specifies whether we can use this pool for work or not. */
 static bool pool_unworkable(struct pool *pool)
 static bool pool_unworkable(struct pool *pool)
 {
 {
@@ -3017,61 +3088,6 @@ static void get_benchmark_work(struct work *work)
 	calc_diff(work, 0);
 	calc_diff(work, 0);
 }
 }
 
 
-static bool get_upstream_work(struct work *work, CURL *curl)
-{
-	struct pool *pool = work->pool;
-	struct cgminer_pool_stats *pool_stats = &(pool->cgminer_pool_stats);
-	struct timeval tv_elapsed;
-	json_t *val = NULL;
-	bool rc = false;
-	char *url;
-
-	applog(LOG_DEBUG, "DBG: sending %s get RPC call: %s", pool->rpc_url, pool->rpc_req);
-
-	url = pool->rpc_url;
-
-	cgtime(&work->tv_getwork);
-
-	val = json_rpc_call(curl, url, pool->rpc_userpass, pool->rpc_req, false,
-			    false, &work->rolltime, pool, false);
-	pool_stats->getwork_attempts++;
-
-	if (likely(val)) {
-		rc = work_decode(pool, work, val);
-		if (unlikely(!rc))
-			applog(LOG_DEBUG, "Failed to decode work in get_upstream_work");
-	} else
-		applog(LOG_DEBUG, "Failed json_rpc_call in get_upstream_work");
-
-	cgtime(&work->tv_getwork_reply);
-	timersub(&(work->tv_getwork_reply), &(work->tv_getwork), &tv_elapsed);
-	pool_stats->getwork_wait_rolling += ((double)tv_elapsed.tv_sec + ((double)tv_elapsed.tv_usec / 1000000)) * 0.63;
-	pool_stats->getwork_wait_rolling /= 1.63;
-
-	timeradd(&tv_elapsed, &(pool_stats->getwork_wait), &(pool_stats->getwork_wait));
-	if (timercmp(&tv_elapsed, &(pool_stats->getwork_wait_max), >)) {
-		pool_stats->getwork_wait_max.tv_sec = tv_elapsed.tv_sec;
-		pool_stats->getwork_wait_max.tv_usec = tv_elapsed.tv_usec;
-	}
-	if (timercmp(&tv_elapsed, &(pool_stats->getwork_wait_min), <)) {
-		pool_stats->getwork_wait_min.tv_sec = tv_elapsed.tv_sec;
-		pool_stats->getwork_wait_min.tv_usec = tv_elapsed.tv_usec;
-	}
-	pool_stats->getwork_calls++;
-
-	work->pool = pool;
-	work->longpoll = false;
-	work->getwork_mode = GETWORK_MODE_POOL;
-	calc_diff(work, 0);
-	total_getworks++;
-	pool->getwork_requested++;
-
-	if (likely(val))
-		json_decref(val);
-
-	return rc;
-}
-
 #ifdef HAVE_CURSES
 #ifdef HAVE_CURSES
 static void disable_curses_windows(void)
 static void disable_curses_windows(void)
 {
 {
@@ -3239,6 +3255,7 @@ static void sighandler(int __maybe_unused sig)
 	kill_work();
 	kill_work();
 }
 }
 
 
+#ifdef HAVE_LIBCURL
 /* Called with pool_lock held. Recruit an extra curl if none are available for
 /* Called with pool_lock held. Recruit an extra curl if none are available for
  * this pool. */
  * this pool. */
 static void recruit_curl(struct pool *pool)
 static void recruit_curl(struct pool *pool)
@@ -3320,7 +3337,7 @@ static inline bool should_roll(struct work *work)
 	cgtime(&now);
 	cgtime(&now);
 	if (now.tv_sec - work->tv_staged.tv_sec > expiry)
 	if (now.tv_sec - work->tv_staged.tv_sec > expiry)
 		return false;
 		return false;
-	
+
 	return true;
 	return true;
 }
 }
 
 
@@ -3351,36 +3368,47 @@ static void roll_work(struct work *work)
 	work->id = total_work++;
 	work->id = total_work++;
 }
 }
 
 
-/* Duplicates any dynamically allocated arrays within the work struct to
- * prevent a copied work struct from freeing ram belonging to another struct */
-void __copy_work(struct work *work, struct work *base_work)
+static void *submit_work_thread(void *userdata)
 {
 {
-	int id = work->id;
+	struct work *work = (struct work *)userdata;
+	struct pool *pool = work->pool;
+	bool resubmit = false;
+	struct curl_ent *ce;
 
 
-	clean_work(work);
-	memcpy(work, base_work, sizeof(struct work));
-	/* Keep the unique new id assigned during make_work to prevent copied
-	 * work from having the same id. */
-	work->id = id;
-	if (base_work->job_id)
-		work->job_id = strdup(base_work->job_id);
-	if (base_work->nonce1)
-		work->nonce1 = strdup(base_work->nonce1);
-	if (base_work->ntime)
-		work->ntime = strdup(base_work->ntime);
-	if (base_work->coinbase)
-		work->coinbase = strdup(base_work->coinbase);
-}
+	pthread_detach(pthread_self());
 
 
-/* Generates a copy of an existing work struct, creating fresh heap allocations
- * for all dynamically allocated arrays within the struct */
-struct work *copy_work(struct work *base_work)
-{
-	struct work *work = make_work();
+	RenameThread("submit_work");
 
 
-	__copy_work(work, base_work);
+	applog(LOG_DEBUG, "Creating extra submit work thread");
 
 
-	return work;
+	ce = pop_curl_entry(pool);
+	/* submit solution to bitcoin via JSON-RPC */
+	while (!submit_upstream_work(work, ce->curl, resubmit)) {
+		if (opt_lowmem) {
+			applog(LOG_NOTICE, "Pool %d share being discarded to minimise memory cache", pool->pool_no);
+			break;
+		}
+		resubmit = true;
+		if (stale_work(work, true)) {
+			applog(LOG_NOTICE, "Pool %d share became stale while retrying submit, discarding", pool->pool_no);
+
+			mutex_lock(&stats_lock);
+			total_stale++;
+			pool->stale_shares++;
+			total_diff_stale += work->work_difficulty;
+			pool->diff_stale += work->work_difficulty;
+			mutex_unlock(&stats_lock);
+
+			free_work(work);
+			break;
+		}
+
+		/* pause, then restart work-request loop */
+		applog(LOG_INFO, "json_rpc_call failed on submit_work, retrying");
+	}
+	push_curl_entry(ce, pool);
+
+	return NULL;
 }
 }
 
 
 static struct work *make_clone(struct work *work)
 static struct work *make_clone(struct work *work)
@@ -3429,6 +3457,81 @@ out_unlock:
 	return cloned;
 	return cloned;
 }
 }
 
 
+/* Clones work by rolling it if possible, and returning a clone instead of the
+ * original work item which gets staged again to possibly be rolled again in
+ * the future */
+static struct work *clone_work(struct work *work)
+{
+	int mrs = mining_threads + opt_queue - total_staged();
+	struct work *work_clone;
+	bool cloned;
+
+	if (mrs < 1)
+		return work;
+
+	cloned = false;
+	work_clone = make_clone(work);
+	while (mrs-- > 0 && can_roll(work) && should_roll(work)) {
+		applog(LOG_DEBUG, "Pushing rolled converted work to stage thread");
+		stage_work(work_clone);
+		roll_work(work);
+		work_clone = make_clone(work);
+		/* Roll it again to prevent duplicates should this be used
+		 * directly later on */
+		roll_work(work);
+		cloned = true;
+	}
+
+	if (cloned) {
+		stage_work(work);
+		return work_clone;
+	}
+
+	free_work(work_clone);
+
+	return work;
+}
+
+#else /* HAVE_LIBCURL */
+static void *submit_work_thread(void __maybe_unused *userdata)
+{
+	pthread_detach(pthread_self());
+	return NULL;
+}
+#endif /* HAVE_LIBCURL */
+
+/* Duplicates any dynamically allocated arrays within the work struct to
+ * prevent a copied work struct from freeing ram belonging to another struct */
+void __copy_work(struct work *work, struct work *base_work)
+{
+	int id = work->id;
+
+	clean_work(work);
+	memcpy(work, base_work, sizeof(struct work));
+	/* Keep the unique new id assigned during make_work to prevent copied
+	 * work from having the same id. */
+	work->id = id;
+	if (base_work->job_id)
+		work->job_id = strdup(base_work->job_id);
+	if (base_work->nonce1)
+		work->nonce1 = strdup(base_work->nonce1);
+	if (base_work->ntime)
+		work->ntime = strdup(base_work->ntime);
+	if (base_work->coinbase)
+		work->coinbase = strdup(base_work->coinbase);
+}
+
+/* Generates a copy of an existing work struct, creating fresh heap allocations
+ * for all dynamically allocated arrays within the struct */
+struct work *copy_work(struct work *base_work)
+{
+	struct work *work = make_work();
+
+	__copy_work(work, base_work);
+
+	return work;
+}
+
 static void pool_died(struct pool *pool)
 static void pool_died(struct pool *pool)
 {
 {
 	if (!pool_tset(pool, &pool->idle)) {
 	if (!pool_tset(pool, &pool->idle)) {
@@ -3572,49 +3675,6 @@ static void rebuild_hash(struct work *work)
 
 
 static bool cnx_needed(struct pool *pool);
 static bool cnx_needed(struct pool *pool);
 
 
-static void *submit_work_thread(void *userdata)
-{
-	struct work *work = (struct work *)userdata;
-	struct pool *pool = work->pool;
-	bool resubmit = false;
-	struct curl_ent *ce;
-
-	pthread_detach(pthread_self());
-
-	RenameThread("submit_work");
-
-	applog(LOG_DEBUG, "Creating extra submit work thread");
-
-	ce = pop_curl_entry(pool);
-	/* submit solution to bitcoin via JSON-RPC */
-	while (!submit_upstream_work(work, ce->curl, resubmit)) {
-		if (opt_lowmem) {
-			applog(LOG_NOTICE, "Pool %d share being discarded to minimise memory cache", pool->pool_no);
-			break;
-		}
-		resubmit = true;
-		if (stale_work(work, true)) {
-			applog(LOG_NOTICE, "Pool %d share became stale while retrying submit, discarding", pool->pool_no);
-
-			mutex_lock(&stats_lock);
-			total_stale++;
-			pool->stale_shares++;
-			total_diff_stale += work->work_difficulty;
-			pool->diff_stale += work->work_difficulty;
-			mutex_unlock(&stats_lock);
-
-			free_work(work);
-			break;
-		}
-
-		/* pause, then restart work-request loop */
-		applog(LOG_INFO, "json_rpc_call failed on submit_work, retrying");
-	}
-	push_curl_entry(ce, pool);
-
-	return NULL;
-}
-
 /* Find the pool that currently has the highest priority */
 /* Find the pool that currently has the highest priority */
 static struct pool *priority_pool(int choice)
 static struct pool *priority_pool(int choice)
 {
 {
@@ -5761,41 +5821,6 @@ static struct work *hash_pop(void)
 	return work;
 	return work;
 }
 }
 
 
-/* Clones work by rolling it if possible, and returning a clone instead of the
- * original work item which gets staged again to possibly be rolled again in
- * the future */
-static struct work *clone_work(struct work *work)
-{
-	int mrs = mining_threads + opt_queue - total_staged();
-	struct work *work_clone;
-	bool cloned;
-
-	if (mrs < 1)
-		return work;
-
-	cloned = false;
-	work_clone = make_clone(work);
-	while (mrs-- > 0 && can_roll(work) && should_roll(work)) {
-		applog(LOG_DEBUG, "Pushing rolled converted work to stage thread");
-		stage_work(work_clone);
-		roll_work(work);
-		work_clone = make_clone(work);
-		/* Roll it again to prevent duplicates should this be used
-		 * directly later on */
-		roll_work(work);
-		cloned = true;
-	}
-
-	if (cloned) {
-		stage_work(work);
-		return work_clone;
-	}
-
-	free_work(work_clone);
-
-	return work;
-}
-
 static void gen_hash(unsigned char *data, unsigned char *hash, int len)
 static void gen_hash(unsigned char *data, unsigned char *hash, int len)
 {
 {
 	unsigned char hash1[32];
 	unsigned char hash1[32];
@@ -6468,6 +6493,7 @@ enum {
 	FAILURE_INTERVAL		= 30,
 	FAILURE_INTERVAL		= 30,
 };
 };
 
 
+#ifdef HAVE_LIBCURL
 /* Stage another work item from the work returned in a longpoll */
 /* Stage another work item from the work returned in a longpoll */
 static void convert_to_work(json_t *val, int rolltime, struct pool *pool, struct timeval *tv_lp, struct timeval *tv_lp_reply)
 static void convert_to_work(json_t *val, int rolltime, struct pool *pool, struct timeval *tv_lp, struct timeval *tv_lp_reply)
 {
 {
@@ -6538,6 +6564,7 @@ static struct pool *select_longpoll_pool(struct pool *cp)
 	}
 	}
 	return NULL;
 	return NULL;
 }
 }
+#endif /* HAVE_LIBCURL */
 
 
 /* This will make the longpoll thread wait till it's the current pool, or it
 /* This will make the longpoll thread wait till it's the current pool, or it
  * has been flagged as rejecting, before attempting to open any connections.
  * has been flagged as rejecting, before attempting to open any connections.
@@ -6553,6 +6580,7 @@ static void wait_lpcurrent(struct pool *pool)
 	}
 	}
 }
 }
 
 
+#ifdef HAVE_LIBCURL
 static void *longpoll_thread(void *userdata)
 static void *longpoll_thread(void *userdata)
 {
 {
 	struct pool *cp = (struct pool *)userdata;
 	struct pool *cp = (struct pool *)userdata;
@@ -6680,6 +6708,13 @@ out:
 
 
 	return NULL;
 	return NULL;
 }
 }
+#else /* HAVE_LIBCURL */
+static void *longpoll_thread(void __maybe_unused *userdata)
+{
+	pthread_detach(pthread_self());
+	return NULL;
+}
+#endif /* HAVE_LIBCURL */
 
 
 void reinit_device(struct cgpu_info *cgpu)
 void reinit_device(struct cgpu_info *cgpu)
 {
 {
@@ -8160,7 +8195,6 @@ begin_bench:
 		int ts, max_staged = opt_queue;
 		int ts, max_staged = opt_queue;
 		struct pool *pool, *cp;
 		struct pool *pool, *cp;
 		bool lagging = false;
 		bool lagging = false;
-		struct curl_ent *ce;
 		struct work *work;
 		struct work *work;
 
 
 		cp = current_pool();
 		cp = current_pool();
@@ -8211,6 +8245,16 @@ retry:
 			continue;
 			continue;
 		}
 		}
 
 
+		if (opt_benchmark) {
+			get_benchmark_work(work);
+			applog(LOG_DEBUG, "Generated benchmark work");
+			stage_work(work);
+			continue;
+		}
+
+#ifdef HAVE_LIBCURL
+		struct curl_ent *ce;
+
 		if (pool->has_gbt) {
 		if (pool->has_gbt) {
 			while (pool->idle) {
 			while (pool->idle) {
 				struct pool *altpool = select_pool(true);
 				struct pool *altpool = select_pool(true);
@@ -8233,13 +8277,6 @@ retry:
 			continue;
 			continue;
 		}
 		}
 
 
-		if (opt_benchmark) {
-			get_benchmark_work(work);
-			applog(LOG_DEBUG, "Generated benchmark work");
-			stage_work(work);
-			continue;
-		}
-
 		work->pool = pool;
 		work->pool = pool;
 		ce = pop_curl_entry(pool);
 		ce = pop_curl_entry(pool);
 		/* obtain new work from bitcoin via JSON-RPC */
 		/* obtain new work from bitcoin via JSON-RPC */
@@ -8262,6 +8299,7 @@ retry:
 		applog(LOG_DEBUG, "Generated getwork work");
 		applog(LOG_DEBUG, "Generated getwork work");
 		stage_work(work);
 		stage_work(work);
 		push_curl_entry(ce, pool);
 		push_curl_entry(ce, pool);
+#endif
 	}
 	}
 
 
 	return 0;
 	return 0;

+ 3 - 0
compat/.gitignore

@@ -0,0 +1,3 @@
+libusb-1.0/libusb/libusb-1.0.la
+libusb-1.0/libusb/*.lo
+libusb-1.0/libusb/os/*.lo

+ 23 - 5
configure.ac

@@ -365,15 +365,26 @@ fi
 AC_SUBST(LIBUSB_LIBS)
 AC_SUBST(LIBUSB_LIBS)
 AC_SUBST(LIBUSB_CFLAGS)
 AC_SUBST(LIBUSB_CFLAGS)
 
 
-if test "x$have_win32" != xtrue; then
-	PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.25.0], [AC_DEFINE([CURL_HAS_KEEPALIVE], [1], [Defined if version of curl supports keepalive.])],
-		[PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.18.2], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.18.2])])])
+AC_ARG_ENABLE([libcurl],
+	[AC_HELP_STRING([--disable-libcurl],[Disable building with libcurl for getwork and GBT support])],
+	[libcurl=$enableval]
+	)
+
+if test "x$libcurl" != xno; then
+	if test "x$have_win32" != xtrue; then
+		PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.25.0], [AC_DEFINE([CURL_HAS_KEEPALIVE], [1], [Defined if version of curl supports keepalive.])],
+			[PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.18.2], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.18.2])])])
+	else
+		PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.25.0], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.25.0])])
+		AC_DEFINE([CURL_HAS_KEEPALIVE], [1])
+	fi
+	AC_DEFINE([HAVE_LIBCURL], [1], [Defined to 1 if libcurl support built in])
 else
 else
-	PKG_CHECK_MODULES([LIBCURL], [libcurl >= 7.25.0], ,[AC_MSG_ERROR([Missing required libcurl dev >= 7.25.0])])
-	AC_DEFINE([CURL_HAS_KEEPALIVE], [1])
+	LIBCURL_LIBS=""
 fi
 fi
 AC_SUBST(LIBCURL_LIBS)
 AC_SUBST(LIBCURL_LIBS)
 
 
+
 #check execv signature
 #check execv signature
 AC_COMPILE_IFELSE([AC_LANG_SOURCE([
 AC_COMPILE_IFELSE([AC_LANG_SOURCE([
 		   #include <process.h>
 		   #include <process.h>
@@ -462,8 +473,15 @@ echo
 echo "Configuration Options Summary:"
 echo "Configuration Options Summary:"
 echo
 echo
 
 
+if test "x$libcurl" != xno; then
+	echo "  libcurl(GBT+getwork).: Enabled: $LIBCURL_LIBS"
+else
+	echo "  libcurl(GBT+getwork).: Disabled"
+fi
+
 echo "  curses.TUI...........: $cursesmsg"
 echo "  curses.TUI...........: $cursesmsg"
 
 
+
 if test "x$opencl" != xno; then
 if test "x$opencl" != xno; then
 	if test $found_opencl = 1; then
 	if test $found_opencl = 1; then
 		echo "  OpenCL...............: FOUND. GPU mining support enabled"
 		echo "  OpenCL...............: FOUND. GPU mining support enabled"

+ 1 - 1
driver-avalon.c

@@ -531,7 +531,7 @@ static void avalon_initialise(struct cgpu_info *avalon)
 	if (avalon->usbinfo.nodev)
 	if (avalon->usbinfo.nodev)
 		return;
 		return;
 
 
-	interface = avalon->usbdev->found->interface;
+	interface = usb_interface(avalon);
 	// Reset
 	// Reset
 	err = usb_transfer(avalon, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
 	err = usb_transfer(avalon, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
 				FTDI_VALUE_RESET, interface, C_RESET);
 				FTDI_VALUE_RESET, interface, C_RESET);

+ 9 - 8
driver-bflsc.c

@@ -452,7 +452,7 @@ static bool bflsc_qres(struct cgpu_info *bflsc, char *buf, size_t bufsiz, int de
 
 
 static void __bflsc_initialise(struct cgpu_info *bflsc)
 static void __bflsc_initialise(struct cgpu_info *bflsc)
 {
 {
-	int err;
+	int err, interface;
 
 
 // TODO: does x-link bypass the other device FTDI? (I think it does)
 // TODO: does x-link bypass the other device FTDI? (I think it does)
 //	So no initialisation required except for the master device?
 //	So no initialisation required except for the master device?
@@ -460,9 +460,10 @@ static void __bflsc_initialise(struct cgpu_info *bflsc)
 	if (bflsc->usbinfo.nodev)
 	if (bflsc->usbinfo.nodev)
 		return;
 		return;
 
 
+	interface = usb_interface(bflsc);
 	// Reset
 	// Reset
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
-				FTDI_VALUE_RESET, bflsc->usbdev->found->interface, C_RESET);
+				FTDI_VALUE_RESET, interface, C_RESET);
 
 
 	applog(LOG_DEBUG, "%s%i: reset got err %d",
 	applog(LOG_DEBUG, "%s%i: reset got err %d",
 		bflsc->drv->name, bflsc->device_id, err);
 		bflsc->drv->name, bflsc->device_id, err);
@@ -477,7 +478,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc)
 
 
 	// Set data control
 	// Set data control
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_DATA,
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_DATA,
-				FTDI_VALUE_DATA_BAS, bflsc->usbdev->found->interface, C_SETDATA);
+				FTDI_VALUE_DATA_BAS, interface, C_SETDATA);
 
 
 	applog(LOG_DEBUG, "%s%i: setdata got err %d",
 	applog(LOG_DEBUG, "%s%i: setdata got err %d",
 		bflsc->drv->name, bflsc->device_id, err);
 		bflsc->drv->name, bflsc->device_id, err);
@@ -487,7 +488,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc)
 
 
 	// Set the baud
 	// Set the baud
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_BAS,
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_BAS,
-				(FTDI_INDEX_BAUD_BAS & 0xff00) | bflsc->usbdev->found->interface,
+				(FTDI_INDEX_BAUD_BAS & 0xff00) | interface,
 				C_SETBAUD);
 				C_SETBAUD);
 
 
 	applog(LOG_DEBUG, "%s%i: setbaud got err %d",
 	applog(LOG_DEBUG, "%s%i: setbaud got err %d",
@@ -498,7 +499,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc)
 
 
 	// Set Flow Control
 	// Set Flow Control
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW,
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW,
-				FTDI_VALUE_FLOW, bflsc->usbdev->found->interface, C_SETFLOW);
+				FTDI_VALUE_FLOW, interface, C_SETFLOW);
 
 
 	applog(LOG_DEBUG, "%s%i: setflowctrl got err %d",
 	applog(LOG_DEBUG, "%s%i: setflowctrl got err %d",
 		bflsc->drv->name, bflsc->device_id, err);
 		bflsc->drv->name, bflsc->device_id, err);
@@ -508,7 +509,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc)
 
 
 	// Set Modem Control
 	// Set Modem Control
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM,
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM,
-				FTDI_VALUE_MODEM, bflsc->usbdev->found->interface, C_SETMODEM);
+				FTDI_VALUE_MODEM, interface, C_SETMODEM);
 
 
 	applog(LOG_DEBUG, "%s%i: setmodemctrl got err %d",
 	applog(LOG_DEBUG, "%s%i: setmodemctrl got err %d",
 		bflsc->drv->name, bflsc->device_id, err);
 		bflsc->drv->name, bflsc->device_id, err);
@@ -518,7 +519,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc)
 
 
 	// Clear any sent data
 	// Clear any sent data
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
-				FTDI_VALUE_PURGE_TX, bflsc->usbdev->found->interface, C_PURGETX);
+				FTDI_VALUE_PURGE_TX, interface, C_PURGETX);
 
 
 	applog(LOG_DEBUG, "%s%i: purgetx got err %d",
 	applog(LOG_DEBUG, "%s%i: purgetx got err %d",
 		bflsc->drv->name, bflsc->device_id, err);
 		bflsc->drv->name, bflsc->device_id, err);
@@ -528,7 +529,7 @@ static void __bflsc_initialise(struct cgpu_info *bflsc)
 
 
 	// Clear any received data
 	// Clear any received data
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
 	err = usb_transfer(bflsc, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
-				FTDI_VALUE_PURGE_RX, bflsc->usbdev->found->interface, C_PURGERX);
+				FTDI_VALUE_PURGE_RX, interface, C_PURGERX);
 
 
 	applog(LOG_DEBUG, "%s%i: purgerx got err %d",
 	applog(LOG_DEBUG, "%s%i: purgerx got err %d",
 		bflsc->drv->name, bflsc->device_id, err);
 		bflsc->drv->name, bflsc->device_id, err);

+ 9 - 8
driver-bitforce.c

@@ -81,7 +81,7 @@ struct device_drv bitforce_drv;
 
 
 static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
 static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
 {
 {
-	int err;
+	int err, interface;
 
 
 	if (lock)
 	if (lock)
 		mutex_lock(&bitforce->device_mutex);
 		mutex_lock(&bitforce->device_mutex);
@@ -89,9 +89,10 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
 	if (bitforce->usbinfo.nodev)
 	if (bitforce->usbinfo.nodev)
 		goto failed;
 		goto failed;
 
 
+	interface = usb_interface(bitforce);
 	// Reset
 	// Reset
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
-				FTDI_VALUE_RESET, bitforce->usbdev->found->interface, C_RESET);
+				FTDI_VALUE_RESET, interface, C_RESET);
 	if (opt_debug)
 	if (opt_debug)
 		applog(LOG_DEBUG, "%s%i: reset got err %d",
 		applog(LOG_DEBUG, "%s%i: reset got err %d",
 			bitforce->drv->name, bitforce->device_id, err);
 			bitforce->drv->name, bitforce->device_id, err);
@@ -101,7 +102,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
 
 
 	// Set data control
 	// Set data control
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_DATA,
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_DATA,
-				FTDI_VALUE_DATA_BFL, bitforce->usbdev->found->interface, C_SETDATA);
+				FTDI_VALUE_DATA_BFL, interface, C_SETDATA);
 	if (opt_debug)
 	if (opt_debug)
 		applog(LOG_DEBUG, "%s%i: setdata got err %d",
 		applog(LOG_DEBUG, "%s%i: setdata got err %d",
 			bitforce->drv->name, bitforce->device_id, err);
 			bitforce->drv->name, bitforce->device_id, err);
@@ -111,7 +112,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
 
 
 	// Set the baud
 	// Set the baud
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_BFL,
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD_BFL,
-				(FTDI_INDEX_BAUD_BFL & 0xff00) | bitforce->usbdev->found->interface,
+				(FTDI_INDEX_BAUD_BFL & 0xff00) | interface,
 				C_SETBAUD);
 				C_SETBAUD);
 	if (opt_debug)
 	if (opt_debug)
 		applog(LOG_DEBUG, "%s%i: setbaud got err %d",
 		applog(LOG_DEBUG, "%s%i: setbaud got err %d",
@@ -122,7 +123,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
 
 
 	// Set Flow Control
 	// Set Flow Control
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW,
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW,
-				FTDI_VALUE_FLOW, bitforce->usbdev->found->interface, C_SETFLOW);
+				FTDI_VALUE_FLOW, interface, C_SETFLOW);
 	if (opt_debug)
 	if (opt_debug)
 		applog(LOG_DEBUG, "%s%i: setflowctrl got err %d",
 		applog(LOG_DEBUG, "%s%i: setflowctrl got err %d",
 			bitforce->drv->name, bitforce->device_id, err);
 			bitforce->drv->name, bitforce->device_id, err);
@@ -132,7 +133,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
 
 
 	// Set Modem Control
 	// Set Modem Control
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM,
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM,
-				FTDI_VALUE_MODEM, bitforce->usbdev->found->interface, C_SETMODEM);
+				FTDI_VALUE_MODEM, interface, C_SETMODEM);
 	if (opt_debug)
 	if (opt_debug)
 		applog(LOG_DEBUG, "%s%i: setmodemctrl got err %d",
 		applog(LOG_DEBUG, "%s%i: setmodemctrl got err %d",
 			bitforce->drv->name, bitforce->device_id, err);
 			bitforce->drv->name, bitforce->device_id, err);
@@ -142,7 +143,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
 
 
 	// Clear any sent data
 	// Clear any sent data
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
-				FTDI_VALUE_PURGE_TX, bitforce->usbdev->found->interface, C_PURGETX);
+				FTDI_VALUE_PURGE_TX, interface, C_PURGETX);
 	if (opt_debug)
 	if (opt_debug)
 		applog(LOG_DEBUG, "%s%i: purgetx got err %d",
 		applog(LOG_DEBUG, "%s%i: purgetx got err %d",
 			bitforce->drv->name, bitforce->device_id, err);
 			bitforce->drv->name, bitforce->device_id, err);
@@ -152,7 +153,7 @@ static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
 
 
 	// Clear any received data
 	// Clear any received data
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
 	err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
-				FTDI_VALUE_PURGE_RX, bitforce->usbdev->found->interface, C_PURGERX);
+				FTDI_VALUE_PURGE_RX, interface, C_PURGERX);
 	if (opt_debug)
 	if (opt_debug)
 		applog(LOG_DEBUG, "%s%i: purgerx got err %d",
 		applog(LOG_DEBUG, "%s%i: purgerx got err %d",
 			bitforce->drv->name, bitforce->device_id, err);
 			bitforce->drv->name, bitforce->device_id, err);

+ 62 - 14
driver-icarus.c

@@ -102,7 +102,9 @@ ASSERT1(sizeof(uint32_t) == 4);
 #define LANCELOT_HASH_TIME 0.0000000025000
 #define LANCELOT_HASH_TIME 0.0000000025000
 #define ASICMINERUSB_HASH_TIME 0.0000000029761
 #define ASICMINERUSB_HASH_TIME 0.0000000029761
 // TODO: What is it?
 // TODO: What is it?
-#define CAIRNSMORE1_HASH_TIME 0.0000000026316
+#define CAIRNSMORE1_HASH_TIME 0.0000000027000
+// Per FPGA
+#define CAIRNSMORE2_HASH_TIME 0.0000000066600
 #define NANOSEC 1000000000.0
 #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
@@ -208,6 +210,8 @@ struct ICARUS_INFO {
 	int work_division;
 	int work_division;
 	int fpga_count;
 	int fpga_count;
 	uint32_t nonce_mask;
 	uint32_t nonce_mask;
+
+	bool initialised;
 };
 };
 
 
 #define END_CONDITION 0x0000ffff
 #define END_CONDITION 0x0000ffff
@@ -262,6 +266,7 @@ static void _transfer(struct cgpu_info *icarus, uint8_t request_type, uint8_t bR
 
 
 static void icarus_initialise(struct cgpu_info *icarus, int baud)
 static void icarus_initialise(struct cgpu_info *icarus, int baud)
 {
 {
+	struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data);
 	uint16_t wValue, wIndex;
 	uint16_t wValue, wIndex;
 	enum sub_ident ident;
 	enum sub_ident ident;
 	int interface;
 	int interface;
@@ -282,6 +287,9 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
 		case IDENT_CMR2:
 		case IDENT_CMR2:
 			usb_set_pps(icarus, BLT_PREF_PACKET);
 			usb_set_pps(icarus, BLT_PREF_PACKET);
 
 
+			if (ident == IDENT_CMR2) // Chip hack
+				interface++;
+
 			// Reset
 			// Reset
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET,
 			transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET,
 				 interface, C_RESET);
 				 interface, C_RESET);
@@ -403,6 +411,8 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
 			quit(1, "icarus_intialise() called with invalid %s cgid %i ident=%d",
 			quit(1, "icarus_intialise() called with invalid %s cgid %i ident=%d",
 				icarus->drv->name, icarus->cgminer_id, ident);
 				icarus->drv->name, icarus->cgminer_id, ident);
 	}
 	}
+
+	info->initialised = true;
 }
 }
 
 
 static void rev(unsigned char *s, size_t l)
 static void rev(unsigned char *s, size_t l)
@@ -537,11 +547,12 @@ static void set_timing_mode(int this_option_offset, struct cgpu_info *icarus)
 		case IDENT_AMU:
 		case IDENT_AMU:
 			info->Hs = ASICMINERUSB_HASH_TIME;
 			info->Hs = ASICMINERUSB_HASH_TIME;
 			break;
 			break;
-		// TODO: ?
 		case IDENT_CMR1:
 		case IDENT_CMR1:
-		case IDENT_CMR2:
 			info->Hs = CAIRNSMORE1_HASH_TIME;
 			info->Hs = CAIRNSMORE1_HASH_TIME;
 			break;
 			break;
+		case IDENT_CMR2:
+			info->Hs = CAIRNSMORE2_HASH_TIME;
+			break;
 		default:
 		default:
 			quit(1, "Icarus get_options() called with invalid %s ident=%d",
 			quit(1, "Icarus get_options() called with invalid %s ident=%d",
 				icarus->drv->name, ident);
 				icarus->drv->name, ident);
@@ -701,13 +712,16 @@ static void get_options(int this_option_offset, struct cgpu_info *icarus, int *b
 			*work_division = 1;
 			*work_division = 1;
 			*fpga_count = 1;
 			*fpga_count = 1;
 			break;
 			break;
-		// TODO: ?
 		case IDENT_CMR1:
 		case IDENT_CMR1:
-		case IDENT_CMR2:
 			*baud = ICARUS_IO_SPEED;
 			*baud = ICARUS_IO_SPEED;
 			*work_division = 2;
 			*work_division = 2;
 			*fpga_count = 2;
 			*fpga_count = 2;
 			break;
 			break;
+		case IDENT_CMR2:
+			*baud = ICARUS_IO_SPEED;
+			*work_division = 1;
+			*fpga_count = 1;
+			break;
 		default:
 		default:
 			quit(1, "Icarus get_options() called with invalid %s ident=%d",
 			quit(1, "Icarus get_options() called with invalid %s ident=%d",
 				icarus->drv->name, ident);
 				icarus->drv->name, ident);
@@ -795,6 +809,11 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
 
 
 	hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
 	hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
 
 
+	info = (struct ICARUS_INFO *)calloc(1, sizeof(struct ICARUS_INFO));
+	if (unlikely(!info))
+		quit(1, "Failed to malloc ICARUS_INFO");
+	icarus->device_data = (void *)info;
+
 	tries = 2;
 	tries = 2;
 	ok = false;
 	ok = false;
 	while (!ok && tries-- > 0) {
 	while (!ok && tries-- > 0) {
@@ -844,15 +863,6 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
 	applog(LOG_DEBUG, "%s%d: Init baud=%d work_division=%d fpga_count=%d",
 	applog(LOG_DEBUG, "%s%d: Init baud=%d work_division=%d fpga_count=%d",
 		icarus->drv->name, icarus->device_id, baud, work_division, fpga_count);
 		icarus->drv->name, icarus->device_id, baud, work_division, fpga_count);
 
 
-	info = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO));
-	if (unlikely(!info))
-		quit(1, "Failed to malloc ICARUS_INFO");
-
-	icarus->device_data = (void *)info;
-
-	// Initialise everything to zero for a new device
-	memset(info, 0, sizeof(struct ICARUS_INFO));
-
 	info->baud = baud;
 	info->baud = baud;
 	info->work_division = work_division;
 	info->work_division = work_division;
 	info->fpga_count = fpga_count;
 	info->fpga_count = fpga_count;
@@ -862,12 +872,47 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
 	timersub(&tv_finish, &tv_start, &(info->golden_tv));
 	timersub(&tv_finish, &tv_start, &(info->golden_tv));
 
 
 	set_timing_mode(this_option_offset, icarus);
 	set_timing_mode(this_option_offset, icarus);
+	
+	if (usb_ident(icarus) == IDENT_CMR2) {
+		int i;
+		for (i = 1; i < icarus->usbdev->found->intinfo_count; i++) {
+			struct cgpu_info *cgtmp;
+			struct ICARUS_INFO *intmp;
+
+			cgtmp = usb_init_intinfo(icarus, i);
+			if (!cgtmp) {
+				applog(LOG_ERR, "%s%d: Init failed initinfo %d",
+						icarus->drv->name, icarus->device_id, i);
+				continue;
+			}
+
+			cgtmp->usbinfo.usbstat = USB_NOSTAT;
+
+			if (!add_cgpu(cgtmp)) {
+				usb_uninit(cgtmp);
+				continue;
+			}
+
+			update_usb_stats(cgtmp);
+
+			intmp = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO));
+			if (unlikely(!intmp))
+				quit(1, "Failed2 to malloc ICARUS_INFO");
+
+			cgtmp->device_data = (void *)intmp;
+
+			// Initialise everything to match
+			memcpy(intmp, info, sizeof(struct ICARUS_INFO));
+		}
+	}
 
 
 	return true;
 	return true;
 
 
 unshin:
 unshin:
 
 
 	usb_uninit(icarus);
 	usb_uninit(icarus);
+	free(info);
+	icarus->device_data = NULL;
 
 
 shin:
 shin:
 
 
@@ -917,6 +962,9 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	if (icarus->usbinfo.nodev)
 	if (icarus->usbinfo.nodev)
 		return -1;
 		return -1;
 
 
+	if (!info->initialised)
+		icarus_initialise(icarus, info->baud);
+
 	elapsed.tv_sec = elapsed.tv_usec = 0;
 	elapsed.tv_sec = elapsed.tv_usec = 0;
 
 
 	memset(ob_bin, 0, sizeof(ob_bin));
 	memset(ob_bin, 0, sizeof(ob_bin));

+ 14 - 2
miner.h

@@ -8,7 +8,17 @@
 #include <sys/time.h>
 #include <sys/time.h>
 #include <pthread.h>
 #include <pthread.h>
 #include <jansson.h>
 #include <jansson.h>
+#ifdef HAVE_LIBCURL
 #include <curl/curl.h>
 #include <curl/curl.h>
+#else
+typedef char CURL;
+extern char *curly;
+#define curl_easy_init(curl) (curly)
+#define curl_easy_cleanup(curl) {}
+#define curl_global_cleanup() {}
+#define CURL_GLOBAL_ALL 0
+#define curl_global_init(X) (0)
+#endif
 #include <sched.h>
 #include <sched.h>
 
 
 #include "elist.h"
 #include "elist.h"
@@ -913,10 +923,12 @@ extern int swork_id;
 extern pthread_rwlock_t netacc_lock;
 extern pthread_rwlock_t netacc_lock;
 
 
 extern const uint32_t sha256_init_state[];
 extern const uint32_t sha256_init_state[];
+#ifdef HAVE_LIBCURL
 extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
 extern json_t *json_rpc_call(CURL *curl, const char *url, const char *userpass,
 			     const char *rpc_req, bool, bool, int *,
 			     const char *rpc_req, bool, bool, int *,
 			     struct pool *pool, bool);
 			     struct pool *pool, bool);
-extern const char *proxytype(curl_proxytype proxytype);
+#endif
+extern const char *proxytype(proxytypes_t proxytype);
 extern char *get_proxy(char *url, struct pool *pool);
 extern char *get_proxy(char *url, struct pool *pool);
 extern char *bin2hex(const unsigned char *p, size_t len);
 extern char *bin2hex(const unsigned char *p, size_t len);
 extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
 extern bool hex2bin(unsigned char *p, const char *hexstr, size_t len);
@@ -1156,7 +1168,7 @@ struct pool {
 	char *rpc_url;
 	char *rpc_url;
 	char *rpc_userpass;
 	char *rpc_userpass;
 	char *rpc_user, *rpc_pass;
 	char *rpc_user, *rpc_pass;
-	curl_proxytype rpc_proxytype;
+	proxytypes_t rpc_proxytype;
 	char *rpc_proxy;
 	char *rpc_proxy;
 
 
 	pthread_mutex_t pool_lock;
 	pthread_mutex_t pool_lock;

+ 1 - 0
ocl.c

@@ -14,6 +14,7 @@
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdio.h>
+#include <limits.h>
 #include <sys/types.h>
 #include <sys/types.h>
 
 
 #ifdef WIN32
 #ifdef WIN32

+ 422 - 146
usbutils.c

@@ -25,7 +25,23 @@
 #define NOCONTROLDEV(err) ((err) == LIBUSB_ERROR_NO_DEVICE || \
 #define NOCONTROLDEV(err) ((err) == LIBUSB_ERROR_NO_DEVICE || \
 			(err) == LIBUSB_ERROR_OTHER)
 			(err) == LIBUSB_ERROR_OTHER)
 
 
-			
+/*
+ * WARNING - these assume DEVLOCK(cgpu, pstate) is called first and
+ *  DEVUNLOCK(cgpu, pstate) in called in the same function with the same pstate
+ *  given to DEVLOCK.
+ *  You must call DEVUNLOCK(cgpu, pstate) before exiting the function or it will leave
+ *  the thread Cancelability unrestored
+ */
+#define DEVLOCK(cgpu, _pth_state) do { \
+			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &_pth_state); \
+			wr_lock(cgpu->usbinfo.devlock); \
+			} while (0)
+
+#define DEVUNLOCK(cgpu, _pth_state) do { \
+			wr_unlock(cgpu->usbinfo.devlock); \
+			pthread_setcancelstate(_pth_state, NULL); \
+			} while (0)
+
 #ifdef USE_BFLSC
 #ifdef USE_BFLSC
 #define DRV_BFLSC 1
 #define DRV_BFLSC 1
 #endif
 #endif
@@ -74,74 +90,136 @@
 
 
 #define USB_READ_MINPOLL 40
 #define USB_READ_MINPOLL 40
 
 
+#define USB_EPS(_intx, _epinfosx) { \
+		.interface = _intx, \
+		.epinfo_count = ARRAY_SIZE(_epinfosx), \
+		.epinfos = _epinfosx \
+	}
+
 #ifdef USE_BFLSC
 #ifdef USE_BFLSC
 // N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1
 // N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1
-static struct usb_endpoints bas_eps[] = {
+static struct usb_epinfo bas_epinfos[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 };
 };
+
+static struct usb_intinfo bas_ints[] = {
+	USB_EPS(0, bas_epinfos)
+};
 #endif
 #endif
 
 
 #ifdef USE_BITFORCE
 #ifdef USE_BITFORCE
 // N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1
 // N.B. transfer size is 512 with USB2.0, but only 64 with USB1.1
-static struct usb_endpoints bfl_eps[] = {
+static struct usb_epinfo bfl_epinfos[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 };
 };
+
+static struct usb_intinfo bfl_ints[] = {
+	USB_EPS(0, bfl_epinfos)
+};
 #endif
 #endif
 
 
 #ifdef USE_MODMINER
 #ifdef USE_MODMINER
-static struct usb_endpoints mmq_eps[] = {
+static struct usb_epinfo mmq_epinfos[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(3), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(3), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(3), 0 }
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(3), 0 }
 };
 };
+
+static struct usb_intinfo mmq_ints[] = {
+	USB_EPS(1, mmq_epinfos)
+};
 #endif
 #endif
 
 
 #ifdef USE_AVALON
 #ifdef USE_AVALON
-static struct usb_endpoints ava_eps[] = {
+static struct usb_epinfo ava_epinfos[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 };
 };
+
+static struct usb_intinfo ava_ints[] = {
+	USB_EPS(0, ava_epinfos)
+};
 #endif
 #endif
 
 
 #ifdef USE_ICARUS
 #ifdef USE_ICARUS
-static struct usb_endpoints ica_eps[] = {
+static struct usb_epinfo ica_epinfos[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(3), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(3), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 };
 };
-static struct usb_endpoints amu_eps[] = {
+
+static struct usb_intinfo ica_ints[] = {
+	USB_EPS(0, ica_epinfos)
+};
+
+static struct usb_epinfo amu_epinfos[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(1), 0 }
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(1), 0 }
 };
 };
-static struct usb_endpoints llt_eps[] = {
+
+static struct usb_intinfo amu_ints[] = {
+	USB_EPS(0, amu_epinfos)
+};
+
+static struct usb_epinfo llt_epinfos[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 };
 };
-static struct usb_endpoints cmr1_eps[] = {
+
+static struct usb_intinfo llt_ints[] = {
+	USB_EPS(0, llt_epinfos)
+};
+
+static struct usb_epinfo cmr1_epinfos[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
-/*
- Interface 1
+};
+
+static struct usb_intinfo cmr1_ints[] = {
+	USB_EPS(0, cmr1_epinfos)
+};
+
+static struct usb_epinfo cmr2_epinfos0[] = {
+	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
+	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
+};
+#ifndef WIN32
+static struct usb_epinfo cmr2_epinfos1[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(3), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(3), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(4), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(4), 0 },
-
- Interface 2
+};
+static struct usb_epinfo cmr2_epinfos2[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(5), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(5), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(6), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(6), 0 },
-
- Interface 3
+};
+static struct usb_epinfo cmr2_epinfos3[] = {
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(7), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(7), 0 },
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(8), 0 }
 	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(8), 0 }
-*/
 };
 };
-static struct usb_endpoints cmr2_eps[] = {
-	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPI(1), 0 },
-	{ LIBUSB_TRANSFER_TYPE_BULK,	64,	EPO(2), 0 }
+#endif
+
+static struct usb_intinfo cmr2_ints[] = {
+	USB_EPS(0, cmr2_epinfos0)
+#ifndef WIN32
+	,
+	USB_EPS(1, cmr2_epinfos1),
+	USB_EPS(2, cmr2_epinfos2),
+	USB_EPS(3, cmr2_epinfos3)
+#endif
 };
 };
 #endif
 #endif
 
 
 #define IDVENDOR_FTDI 0x0403
 #define IDVENDOR_FTDI 0x0403
 
 
+#define INTINFO(_ints) \
+		.which_intinfo = 0, \
+		.intinfo_count = ARRAY_SIZE(_ints), \
+		.intinfos = _ints
+
+#define USBEP(_usbdev, _epinfo) (_usbdev->found->intinfos[_usbdev->found->which_intinfo].epinfos[_epinfo].ep)
+#define FOUNDIF(_found) (_found->intinfos[_found->which_intinfo].interface)
+#define USBIF(_usbdev) FOUNDIF(_usbdev->found)
+
 // TODO: Add support for (at least) Isochronous endpoints
 // TODO: Add support for (at least) Isochronous endpoints
 static struct usb_find_devices find_dev[] = {
 static struct usb_find_devices find_dev[] = {
 #ifdef USE_BFLSC
 #ifdef USE_BFLSC
@@ -153,13 +231,10 @@ static struct usb_find_devices find_dev[] = {
 		.idProduct = 0x6014,
 		.idProduct = 0x6014,
 		//.iManufacturer = "Butterfly Labs",
 		//.iManufacturer = "Butterfly Labs",
 		.iProduct = "BitFORCE SHA256 SC",
 		.iProduct = "BitFORCE SHA256 SC",
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 0,
 		.timeout = BFLSC_TIMEOUT_MS,
 		.timeout = BFLSC_TIMEOUT_MS,
 		.latency = LATENCY_STD,
 		.latency = LATENCY_STD,
-		.epcount = ARRAY_SIZE(bas_eps),
-		.eps = bas_eps },
+		INTINFO(bas_ints) },
 #endif
 #endif
 #ifdef USE_BITFORCE
 #ifdef USE_BITFORCE
 	{
 	{
@@ -170,13 +245,10 @@ static struct usb_find_devices find_dev[] = {
 		.idProduct = 0x6014,
 		.idProduct = 0x6014,
 		.iManufacturer = "Butterfly Labs Inc.",
 		.iManufacturer = "Butterfly Labs Inc.",
 		.iProduct = "BitFORCE SHA256",
 		.iProduct = "BitFORCE SHA256",
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 0,
 		.timeout = BITFORCE_TIMEOUT_MS,
 		.timeout = BITFORCE_TIMEOUT_MS,
 		.latency = LATENCY_STD,
 		.latency = LATENCY_STD,
-		.epcount = ARRAY_SIZE(bfl_eps),
-		.eps = bfl_eps },
+		INTINFO(bfl_ints) },
 #endif
 #endif
 #ifdef USE_MODMINER
 #ifdef USE_MODMINER
 	{
 	{
@@ -185,13 +257,10 @@ static struct usb_find_devices find_dev[] = {
 		.ident = IDENT_MMQ,
 		.ident = IDENT_MMQ,
 		.idVendor = 0x1fc9,
 		.idVendor = 0x1fc9,
 		.idProduct = 0x0003,
 		.idProduct = 0x0003,
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 1,
 		.timeout = MODMINER_TIMEOUT_MS,
 		.timeout = MODMINER_TIMEOUT_MS,
 		.latency = LATENCY_UNUSED,
 		.latency = LATENCY_UNUSED,
-		.epcount = ARRAY_SIZE(mmq_eps),
-		.eps = mmq_eps },
+		INTINFO(mmq_ints) },
 #endif
 #endif
 #ifdef USE_AVALON
 #ifdef USE_AVALON
 	{
 	{
@@ -202,26 +271,20 @@ static struct usb_find_devices find_dev[] = {
 		.idProduct = 0x6001,
 		.idProduct = 0x6001,
 		.iManufacturer = "Burnin Electronics",
 		.iManufacturer = "Burnin Electronics",
 		.iProduct = "BitBurner",
 		.iProduct = "BitBurner",
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 0,
 		.timeout = AVALON_TIMEOUT_MS,
 		.timeout = AVALON_TIMEOUT_MS,
 		.latency = 10,
 		.latency = 10,
-		.epcount = ARRAY_SIZE(ava_eps),
-		.eps = ava_eps },
+		INTINFO(ava_ints) },
 	{
 	{
 		.drv = DRV_AVALON,
 		.drv = DRV_AVALON,
 		.name = "AVA",
 		.name = "AVA",
 		.ident = IDENT_AVA,
 		.ident = IDENT_AVA,
 		.idVendor = IDVENDOR_FTDI,
 		.idVendor = IDVENDOR_FTDI,
 		.idProduct = 0x6001,
 		.idProduct = 0x6001,
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 0,
 		.timeout = AVALON_TIMEOUT_MS,
 		.timeout = AVALON_TIMEOUT_MS,
 		.latency = 10,
 		.latency = 10,
-		.epcount = ARRAY_SIZE(ava_eps),
-		.eps = ava_eps },
+		INTINFO(ava_ints) },
 #endif
 #endif
 #ifdef USE_HASHFAST
 #ifdef USE_HASHFAST
 	{
 	{
@@ -237,26 +300,20 @@ static struct usb_find_devices find_dev[] = {
 		.ident = IDENT_ICA,
 		.ident = IDENT_ICA,
 		.idVendor = 0x067b,
 		.idVendor = 0x067b,
 		.idProduct = 0x2303,
 		.idProduct = 0x2303,
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 0,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.latency = LATENCY_UNUSED,
 		.latency = LATENCY_UNUSED,
-		.epcount = ARRAY_SIZE(ica_eps),
-		.eps = ica_eps },
+		INTINFO(ica_ints) },
 	{
 	{
 		.drv = DRV_ICARUS,
 		.drv = DRV_ICARUS,
 		.name = "AMU",
 		.name = "AMU",
 		.ident = IDENT_AMU,
 		.ident = IDENT_AMU,
 		.idVendor = 0x10c4,
 		.idVendor = 0x10c4,
 		.idProduct = 0xea60,
 		.idProduct = 0xea60,
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 0,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.latency = LATENCY_UNUSED,
 		.latency = LATENCY_UNUSED,
-		.epcount = ARRAY_SIZE(amu_eps),
-		.eps = amu_eps },
+		INTINFO(amu_ints) },
 	{
 	{
 		.drv = DRV_ICARUS,
 		.drv = DRV_ICARUS,
 		.name = "BLT",
 		.name = "BLT",
@@ -264,13 +321,10 @@ static struct usb_find_devices find_dev[] = {
 		.idVendor = IDVENDOR_FTDI,
 		.idVendor = IDVENDOR_FTDI,
 		.idProduct = 0x6001,
 		.idProduct = 0x6001,
 		.iProduct = "FT232R USB UART",
 		.iProduct = "FT232R USB UART",
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 0,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.latency = LATENCY_STD,
 		.latency = LATENCY_STD,
-		.epcount = ARRAY_SIZE(llt_eps),
-		.eps = llt_eps },
+		INTINFO(llt_ints) },
 	// For any that don't match the above "BLT"
 	// For any that don't match the above "BLT"
 	{
 	{
 		.drv = DRV_ICARUS,
 		.drv = DRV_ICARUS,
@@ -278,41 +332,32 @@ static struct usb_find_devices find_dev[] = {
 		.ident = IDENT_LLT,
 		.ident = IDENT_LLT,
 		.idVendor = IDVENDOR_FTDI,
 		.idVendor = IDVENDOR_FTDI,
 		.idProduct = 0x6001,
 		.idProduct = 0x6001,
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 0,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.latency = LATENCY_STD,
 		.latency = LATENCY_STD,
-		.epcount = ARRAY_SIZE(llt_eps),
-		.eps = llt_eps },
+		INTINFO(llt_ints) },
 	{
 	{
 		.drv = DRV_ICARUS,
 		.drv = DRV_ICARUS,
 		.name = "CMR",
 		.name = "CMR",
 		.ident = IDENT_CMR1,
 		.ident = IDENT_CMR1,
 		.idVendor = IDVENDOR_FTDI,
 		.idVendor = IDVENDOR_FTDI,
-		.idProduct = 0x8350,
+		.idProduct = 0x6014,
 		.iProduct = "Cairnsmore1",
 		.iProduct = "Cairnsmore1",
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 0,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.latency = LATENCY_STD,
 		.latency = LATENCY_STD,
-		.epcount = ARRAY_SIZE(cmr1_eps),
-		.eps = cmr1_eps },
+		INTINFO(cmr1_ints) },
 	{
 	{
 		.drv = DRV_ICARUS,
 		.drv = DRV_ICARUS,
 		.name = "CMR",
 		.name = "CMR",
 		.ident = IDENT_CMR2,
 		.ident = IDENT_CMR2,
 		.idVendor = IDVENDOR_FTDI,
 		.idVendor = IDVENDOR_FTDI,
-		.idProduct = 0x6014,
+		.idProduct = 0x8350,
 		.iProduct = "Cairnsmore1",
 		.iProduct = "Cairnsmore1",
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 0,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.timeout = ICARUS_TIMEOUT_MS,
 		.latency = LATENCY_STD,
 		.latency = LATENCY_STD,
-		.epcount = ARRAY_SIZE(cmr2_eps),
-		.eps = cmr2_eps },
+		INTINFO(cmr2_ints) },
 #endif
 #endif
 #ifdef USE_ZTEX
 #ifdef USE_ZTEX
 // This is here so cgminer -n shows them
 // This is here so cgminer -n shows them
@@ -323,15 +368,14 @@ static struct usb_find_devices find_dev[] = {
 		.ident = IDENT_ZTX,
 		.ident = IDENT_ZTX,
 		.idVendor = 0x221a,
 		.idVendor = 0x221a,
 		.idProduct = 0x0100,
 		.idProduct = 0x0100,
-		.kernel = 0,
 		.config = 1,
 		.config = 1,
-		.interface = 1,
 		.timeout = 100,
 		.timeout = 100,
 		.latency = LATENCY_UNUSED,
 		.latency = LATENCY_UNUSED,
-		.epcount = 0,
-		.eps = NULL },
+		.which_intinfo = 0,
+		.intinfo_count = 0,
+		.intinfos = NULL },
 #endif
 #endif
-	{ DRV_LAST, NULL, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, NULL }
+	{ DRV_LAST, NULL, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, NULL }
 };
 };
 
 
 #ifdef USE_BFLSC
 #ifdef USE_BFLSC
@@ -1375,7 +1419,8 @@ static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb)
 	if (cgusb->prod_string && cgusb->prod_string != BLANK)
 	if (cgusb->prod_string && cgusb->prod_string != BLANK)
 		free(cgusb->prod_string);
 		free(cgusb->prod_string);
 
 
-	free(cgusb->descriptor);
+	if (cgusb->descriptor)
+		free(cgusb->descriptor);
 
 
 	free(cgusb->found);
 	free(cgusb->found);
 
 
@@ -1387,7 +1432,7 @@ static struct cg_usb_device *free_cgusb(struct cg_usb_device *cgusb)
 	return NULL;
 	return NULL;
 }
 }
 
 
-void usb_uninit(struct cgpu_info *cgpu)
+static void _usb_uninit(struct cgpu_info *cgpu)
 {
 {
 	applog(LOG_DEBUG, "USB uninit %s%i",
 	applog(LOG_DEBUG, "USB uninit %s%i",
 			cgpu->drv->name, cgpu->device_id);
 			cgpu->drv->name, cgpu->device_id);
@@ -1396,14 +1441,28 @@ void usb_uninit(struct cgpu_info *cgpu)
 	//  if release_cgpu() was called due to a USB NODEV(err)
 	//  if release_cgpu() was called due to a USB NODEV(err)
 	if (!cgpu->usbdev)
 	if (!cgpu->usbdev)
 		return;
 		return;
-	if (!libusb_release_interface(cgpu->usbdev->handle, cgpu->usbdev->found->interface)) {
+
+	if (cgpu->usbdev->handle) {
+		libusb_release_interface(cgpu->usbdev->handle, USBIF(cgpu->usbdev));
 		cg_wlock(&cgusb_fd_lock);
 		cg_wlock(&cgusb_fd_lock);
 		libusb_close(cgpu->usbdev->handle);
 		libusb_close(cgpu->usbdev->handle);
+		cgpu->usbdev->handle = NULL;
 		cg_wunlock(&cgusb_fd_lock);
 		cg_wunlock(&cgusb_fd_lock);
 	}
 	}
 	cgpu->usbdev = free_cgusb(cgpu->usbdev);
 	cgpu->usbdev = free_cgusb(cgpu->usbdev);
 }
 }
 
 
+void usb_uninit(struct cgpu_info *cgpu)
+{
+	int pstate;
+
+	DEVLOCK(cgpu, pstate);
+
+	_usb_uninit(cgpu);
+
+	DEVUNLOCK(cgpu, pstate);
+}
+
 /*
 /*
  * N.B. this is always called inside
  * N.B. this is always called inside
  *	DEVLOCK(cgpu, pstate);
  *	DEVLOCK(cgpu, pstate);
@@ -1412,7 +1471,7 @@ static void release_cgpu(struct cgpu_info *cgpu)
 {
 {
 	struct cg_usb_device *cgusb = cgpu->usbdev;
 	struct cg_usb_device *cgusb = cgpu->usbdev;
 	struct cgpu_info *lookcgpu;
 	struct cgpu_info *lookcgpu;
-	int i;
+	int which_intinfo, i;
 
 
 	applog(LOG_DEBUG, "USB release %s%i",
 	applog(LOG_DEBUG, "USB release %s%i",
 			cgpu->drv->name, cgpu->device_id);
 			cgpu->drv->name, cgpu->device_id);
@@ -1445,16 +1504,24 @@ static void release_cgpu(struct cgpu_info *cgpu)
 		}
 		}
 	}
 	}
 
 
-	usb_uninit(cgpu);
-
-	cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address);
+	which_intinfo = cgpu->usbdev->found->which_intinfo;
+	_usb_uninit(cgpu);
+	if (which_intinfo == 0)
+		cgminer_usb_unlock_bd(cgpu->drv, cgpu->usbinfo.bus_number, cgpu->usbinfo.device_address);
 }
 }
 
 
-// Currently only used by MMQ
+/*
+ * Used by MMQ - use the same usbdev thus locking is across all 4 related devices
+ * since they must use the same USB handle since they use the same interface
+ */
 struct cgpu_info *usb_copy_cgpu(struct cgpu_info *orig)
 struct cgpu_info *usb_copy_cgpu(struct cgpu_info *orig)
 {
 {
-	struct cgpu_info *copy = calloc(1, sizeof(*copy));
+	struct cgpu_info *copy;
+	int pstate;
+
+	DEVLOCK(orig, pstate);
 
 
+	copy = calloc(1, sizeof(*copy));
 	if (unlikely(!copy))
 	if (unlikely(!copy))
 		quit(1, "Failed to calloc cgpu for %s in usb_copy_cgpu", orig->drv->dname);
 		quit(1, "Failed to calloc cgpu for %s in usb_copy_cgpu", orig->drv->dname);
 
 
@@ -1471,6 +1538,75 @@ struct cgpu_info *usb_copy_cgpu(struct cgpu_info *orig)
 
 
 	copy->usbinfo.devlock = orig->usbinfo.devlock;
 	copy->usbinfo.devlock = orig->usbinfo.devlock;
 
 
+	DEVUNLOCK(orig, pstate);
+
+	return copy;
+}
+
+/*
+ * Used by CMR - use a different usbdev - since they must use a different
+ * USB handle due to using different interfaces (libusb requirement)
+ * N.B. multiple interfaces don't as yet work in windows libusb
+ * so the CMR defines above that use them are defined out in windows
+ * Nothing else uses multiple interfaces as at 20130922
+ */
+static struct cgpu_info *usb_dup_cgpu(struct cgpu_info *orig, int intinfo)
+{
+	struct cgpu_info *copy;
+
+	copy = calloc(1, sizeof(*copy));
+	if (unlikely(!copy))
+		quit(1, "Failed to calloc cgpu for %s in usb_dup_cgpu", orig->drv->dname);
+
+	copy->name = orig->name;
+	copy->drv = copy_drv(orig->drv);
+	copy->deven = orig->deven;
+	copy->threads = orig->threads;
+
+	if (orig->usbdev) {
+		copy->usbdev = calloc(1, sizeof(*(copy->usbdev)));
+		if (unlikely(!copy->usbdev))
+			quit(1, "Failed to calloc usbdev for %s in usb_dup_cgpu", orig->drv->dname);
+
+		copy->usbdev->found = malloc(sizeof(*(copy->usbdev->found)));
+		if (unlikely(!copy->usbdev->found))
+			quit(1, "Failed to malloc found for %s in usb_dup_cgpu", orig->drv->dname);
+		memcpy(copy->usbdev->found, orig->usbdev->found, sizeof(*(copy->usbdev->found)));
+
+		copy->usbdev->found->which_intinfo = intinfo;
+
+		copy->usbdev->descriptor = NULL; // don't need it
+		copy->usbdev->usb_type = orig->usbdev->usb_type;
+		copy->usbdev->ident = orig->usbdev->ident;
+		copy->usbdev->usbver = orig->usbdev->usbver;
+		copy->usbdev->cps = orig->usbdev->cps;
+		copy->usbdev->usecps = orig->usbdev->usecps;
+		if (orig->usbdev->prod_string == BLANK)
+			copy->usbdev->prod_string = (char *)BLANK;
+		else
+			copy->usbdev->prod_string = strdup(orig->usbdev->prod_string);
+		if (orig->usbdev->manuf_string == BLANK)
+			copy->usbdev->manuf_string = (char *)BLANK;
+		else
+			copy->usbdev->manuf_string = strdup(orig->usbdev->manuf_string);
+		if (orig->usbdev->serial_string == BLANK)
+			copy->usbdev->serial_string = (char *)BLANK;
+		else
+			copy->usbdev->serial_string = strdup(orig->usbdev->serial_string);
+		copy->usbdev->fwVersion = orig->usbdev->fwVersion;
+		copy->usbdev->interfaceVersion = orig->usbdev->interfaceVersion;
+	}
+
+	memcpy(&(copy->usbinfo), &(orig->usbinfo), sizeof(copy->usbinfo));
+
+	copy->usbinfo.nodev = (copy->usbdev == NULL);
+
+	copy->usbinfo.devlock = calloc(1, sizeof(*(copy->usbinfo.devlock)));
+	if (unlikely(!copy->usbinfo.devlock))
+		quit(1, "Failed to calloc devlock for %s in usb_dup_cgpu", orig->drv->dname);
+
+	rwlock_init(copy->usbinfo.devlock);
+
 	return copy;
 	return copy;
 }
 }
 
 
@@ -1515,23 +1651,6 @@ struct cgpu_info *usb_free_cgpu_devlock(struct cgpu_info *cgpu, bool free_devloc
 #define USB_INIT_OK 1
 #define USB_INIT_OK 1
 #define USB_INIT_IGNORE 2
 #define USB_INIT_IGNORE 2
 
 
-/*
- * WARNING - these assume DEVLOCK(cgpu, pstate) is called first and
- *  DEVUNLOCK(cgpu, pstate) in called in the same function with the same pstate
- *  given to DEVLOCK.
- *  You must call DEVUNLOCK(cgpu, pstate) before exiting the function or it will leave
- *  the thread Cancelability unrestored
- */
-#define DEVLOCK(cgpu, _pth_state) do { \
-			pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &_pth_state); \
-			wr_lock(cgpu->usbinfo.devlock); \
-			} while (0)
-
-#define DEVUNLOCK(cgpu, _pth_state) do { \
-			wr_unlock(cgpu->usbinfo.devlock); \
-			pthread_setcancelstate(_pth_state, NULL); \
-			} while (0)
-
 static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found)
 static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found)
 {
 {
 	struct cg_usb_device *cgusb = NULL;
 	struct cg_usb_device *cgusb = NULL;
@@ -1541,7 +1660,7 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u
 	unsigned char strbuf[STRBUFLEN+1];
 	unsigned char strbuf[STRBUFLEN+1];
 	char devpath[32];
 	char devpath[32];
 	char devstr[STRBUFLEN+1];
 	char devstr[STRBUFLEN+1];
-	int err, i, j, k, pstate;
+	int err, ifinfo, epinfo, alt, epnum, pstate;
 	int bad = USB_INIT_FAIL;
 	int bad = USB_INIT_FAIL;
 	int cfg;
 	int cfg;
 
 
@@ -1550,9 +1669,16 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u
 	cgpu->usbinfo.bus_number = libusb_get_bus_number(dev);
 	cgpu->usbinfo.bus_number = libusb_get_bus_number(dev);
 	cgpu->usbinfo.device_address = libusb_get_device_address(dev);
 	cgpu->usbinfo.device_address = libusb_get_device_address(dev);
 
 
-	snprintf(devpath, sizeof(devpath), "%d:%d",
-		(int)(cgpu->usbinfo.bus_number),
-		(int)(cgpu->usbinfo.device_address));
+	if (found->intinfo_count > 1) {
+		snprintf(devpath, sizeof(devpath), "%d:%d-i%d",
+			(int)(cgpu->usbinfo.bus_number),
+			(int)(cgpu->usbinfo.device_address),
+			FOUNDIF(found));
+	} else {
+		snprintf(devpath, sizeof(devpath), "%d:%d",
+			(int)(cgpu->usbinfo.bus_number),
+			(int)(cgpu->usbinfo.device_address));
+	}
 
 
 	cgpu->device_path = strdup(devpath);
 	cgpu->device_path = strdup(devpath);
 
 
@@ -1609,17 +1735,17 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u
 	}
 	}
 
 
 #ifndef WIN32
 #ifndef WIN32
-	if (libusb_kernel_driver_active(cgusb->handle, found->kernel) == 1) {
+	if (libusb_kernel_driver_active(cgusb->handle, FOUNDIF(found)) == 1) {
 		applog(LOG_DEBUG, "USB init, kernel attached ... %s", devstr);
 		applog(LOG_DEBUG, "USB init, kernel attached ... %s", devstr);
-		err = libusb_detach_kernel_driver(cgusb->handle, found->kernel);
+		err = libusb_detach_kernel_driver(cgusb->handle, FOUNDIF(found));
 		if (err == 0) {
 		if (err == 0) {
 			applog(LOG_DEBUG,
 			applog(LOG_DEBUG,
-				"USB init, kernel detached successfully %s",
-				devstr);
+				"USB init, kernel detached interface %d successfully %s",
+				FOUNDIF(found), devstr);
 		} else {
 		} else {
 			applog(LOG_WARNING,
 			applog(LOG_WARNING,
-				"USB init, kernel detach failed, err %d in use? %s",
-				err, devstr);
+				"USB init, kernel detach interface %d failed, err %d in use? %s",
+				FOUNDIF(found), err, devstr);
 			goto cldame;
 			goto cldame;
 		}
 		}
 	}
 	}
@@ -1697,55 +1823,66 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u
 		goto cldame;
 		goto cldame;
 	}
 	}
 
 
-	if ((int)(config->bNumInterfaces) <= found->interface) {
-		applog(LOG_DEBUG, "USB init bNumInterfaces <= interface %s",
-		       devstr);
+	int imax = -1;
+	for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++)
+		if (found->intinfos[ifinfo].interface > imax)
+			imax = found->intinfos[ifinfo].interface;
+
+	if ((int)(config->bNumInterfaces) <= imax) {
+		applog(LOG_DEBUG, "USB init bNumInterfaces %d <= interface max %d for %s",
+		       (int)(config->bNumInterfaces), imax, devstr);
 		goto cldame;
 		goto cldame;
 	}
 	}
 
 
-	for (i = 0; i < found->epcount; i++)
-		found->eps[i].found = false;
-
-	for (i = 0; i < config->interface[found->interface].num_altsetting; i++) {
-		idesc = &(config->interface[found->interface].altsetting[i]);
-		for (j = 0; j < (int)(idesc->bNumEndpoints); j++) {
-			epdesc = &(idesc->endpoint[j]);
-			for (k = 0; k < found->epcount; k++) {
-				if (!found->eps[k].found) {
-					if (epdesc->bmAttributes == found->eps[k].att
-					&&  epdesc->wMaxPacketSize >= found->eps[k].size
-					&&  epdesc->bEndpointAddress == found->eps[k].ep) {
-						found->eps[k].found = true;
-						found->wMaxPacketSize = epdesc->wMaxPacketSize;
-						break;
+	for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++)
+		for (epinfo = 0; epinfo < found->intinfos[ifinfo].epinfo_count; epinfo++)
+			found->intinfos[ifinfo].epinfos[epinfo].found = false;
+
+	for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++) {
+		int interface = found->intinfos[ifinfo].interface;
+		for (alt = 0; alt < config->interface[interface].num_altsetting; alt++) {
+			idesc = &(config->interface[interface].altsetting[alt]);
+			for (epnum = 0; epnum < (int)(idesc->bNumEndpoints); epnum++) {
+				struct usb_epinfo *epinfos = found->intinfos[ifinfo].epinfos;
+				epdesc = &(idesc->endpoint[epnum]);
+				for (epinfo = 0; epinfo < found->intinfos[ifinfo].epinfo_count; epinfo++) {
+					if (!epinfos[epinfo].found) {
+						if (epdesc->bmAttributes == epinfos[epinfo].att
+						&&  epdesc->wMaxPacketSize >= epinfos[epinfo].size
+						&&  epdesc->bEndpointAddress == epinfos[epinfo].ep) {
+							epinfos[epinfo].found = true;
+							// TODO: it's an ep (not device) attribute
+							found->wMaxPacketSize = epdesc->wMaxPacketSize;
+							break;
+						}
 					}
 					}
 				}
 				}
 			}
 			}
 		}
 		}
 	}
 	}
 
 
-	for (i = 0; i < found->epcount; i++) {
-		if (found->eps[i].found == false) {
-			applog(LOG_DEBUG, "USB init found == false %s",
-			       devstr);
-			goto cldame;
-		}
-	}
+	for (ifinfo = 0; ifinfo < found->intinfo_count; ifinfo++)
+		for (epinfo = 0; epinfo < found->intinfos[ifinfo].epinfo_count; epinfo++)
+			if (found->intinfos[ifinfo].epinfos[epinfo].found == false) {
+				applog(LOG_DEBUG, "USB init found (%d,%d) == false %s",
+				       ifinfo, epinfo, devstr);
+				goto cldame;
+			}
 
 
-	err = libusb_claim_interface(cgusb->handle, found->interface);
+	err = libusb_claim_interface(cgusb->handle, FOUNDIF(found));
 	if (err) {
 	if (err) {
 		switch(err) {
 		switch(err) {
 			case LIBUSB_ERROR_BUSY:
 			case LIBUSB_ERROR_BUSY:
 				applog(LOG_WARNING,
 				applog(LOG_WARNING,
 					"USB init, claim interface %d in use %s",
 					"USB init, claim interface %d in use %s",
-					found->interface, devstr);
+					FOUNDIF(found), devstr);
 				break;
 				break;
 			default:
 			default:
 				applog(LOG_DEBUG,
 				applog(LOG_DEBUG,
 					"USB init, claim interface %d failed, err %d %s",
 					"USB init, claim interface %d failed, err %d %s",
-					found->interface, err, devstr);
+					FOUNDIF(found), err, devstr);
 		}
 		}
-		goto cldame;
+		goto reldame;
 	}
 	}
 
 
 	cfg = -1;
 	cfg = -1;
@@ -1812,12 +1949,13 @@ static int _usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct u
 
 
 reldame:
 reldame:
 
 
-	libusb_release_interface(cgusb->handle, found->interface);
+	libusb_release_interface(cgusb->handle, FOUNDIF(found));
 
 
 cldame:
 cldame:
 
 
 	cg_wlock(&cgusb_fd_lock);
 	cg_wlock(&cgusb_fd_lock);
 	libusb_close(cgusb->handle);
 	libusb_close(cgusb->handle);
+	cgusb->handle = NULL;
 	cg_wunlock(&cgusb_fd_lock);
 	cg_wunlock(&cgusb_fd_lock);
 
 
 dame:
 dame:
@@ -1833,6 +1971,144 @@ out_unlock:
 	return bad;
 	return bad;
 }
 }
 
 
+// To get the extra interfaces on a multi interface device
+struct cgpu_info *usb_init_intinfo(struct cgpu_info *orig, int intinfo)
+{
+	struct usb_find_devices *found;
+	struct libusb_device *dev;
+	struct cgpu_info *copy = NULL;
+	char msgstr[STRBUFLEN+1];
+	char devstr[STRBUFLEN+1];
+	char devpath[32];
+	int err, pstate;
+
+	DEVLOCK(orig, pstate);
+
+	snprintf(msgstr, sizeof(msgstr), "USB %s init_intinfo (%d:%d-i%d)",
+			orig->drv->dname,
+			(int)(orig->usbinfo.bus_number),
+			(int)(orig->usbinfo.device_address),
+			orig->usbdev->found->which_intinfo);
+
+	if (orig->usbinfo.nodev) {
+		applog(LOG_ERR, "%s cgpu has nodev", msgstr);
+		goto Hitagi;
+	}
+
+	if (orig->usbdev->found->which_intinfo != 0) {
+		applog(LOG_ERR, "%s incorrect cgpu (must be i0)", msgstr);
+		goto Hitagi;
+	}
+
+	if (orig->usbdev->found->intinfo_count < 2) {
+		applog(LOG_ERR, "%s cgpu only has 1 interface", msgstr);
+		goto Hitagi;
+	}
+
+	if (intinfo < 1 || intinfo >= orig->usbdev->found->intinfo_count) {
+		applog(LOG_ERR, "%s invalid intinfo (%d) must be > 0 && < %d",
+				msgstr, intinfo, orig->usbdev->found->intinfo_count);
+		goto Hitagi;
+	}
+
+	dev = libusb_get_device(orig->usbdev->handle);
+
+	copy = usb_dup_cgpu(orig, intinfo);
+	if (!copy)
+		goto Hitagi;
+
+	found = copy->usbdev->found;
+
+	snprintf(devpath, sizeof(devpath), "%d:%d-i%d",
+		(int)(copy->usbinfo.bus_number),
+		(int)(copy->usbinfo.device_address),
+		FOUNDIF(found));
+
+	copy->device_path = strdup(devpath);
+
+	snprintf(devstr, sizeof(devstr), "- %s device %s", found->name, devpath);
+
+	cg_wlock(&cgusb_fd_lock);
+	err = libusb_open(dev, &(copy->usbdev->handle));
+	cg_wunlock(&cgusb_fd_lock);
+	if (err) {
+		switch (err) {
+			case LIBUSB_ERROR_ACCESS:
+				applog(LOG_ERR,
+					"USB init_intinfo, open device failed, err %d, "
+					"you don't have privilege to access %s",
+					err, devstr);
+				break;
+#ifdef WIN32
+			// Windows specific message
+			case LIBUSB_ERROR_NOT_SUPPORTED:
+				applog(LOG_ERR,
+					"USB init_intinfo, open device failed, err %d, "
+					"you need to install a WinUSB driver for %s",
+					err, devstr);
+				break;
+#endif
+			default:
+				applog(LOG_DEBUG,
+					"USB init_intinfo, open failed, err %d %s",
+					err, devstr);
+		}
+		goto Hitagi;
+	}
+
+#ifndef WIN32
+	if (libusb_kernel_driver_active(copy->usbdev->handle, FOUNDIF(found)) == 1) {
+		applog(LOG_DEBUG, "USB init_intinfo, kernel attached ... %s", devstr);
+		err = libusb_detach_kernel_driver(copy->usbdev->handle, FOUNDIF(found));
+		if (err == 0) {
+			applog(LOG_DEBUG,
+				"USB init_intinfo, kernel detached interface %d successfully %s",
+				FOUNDIF(found), devstr);
+		} else {
+			applog(LOG_WARNING,
+				"USB init_intinfo, kernel detach interface %d failed, err %d in use? %s",
+				FOUNDIF(found), err, devstr);
+			goto HitagiClose;
+		}
+	}
+#endif
+
+	err = libusb_claim_interface(copy->usbdev->handle, FOUNDIF(found));
+	if (err) {
+		switch(err) {
+			case LIBUSB_ERROR_BUSY:
+				applog(LOG_WARNING,
+					"USB init_intinfo, claim interface %d in use %s",
+					FOUNDIF(found), devstr);
+				break;
+			default:
+				applog(LOG_DEBUG,
+					"USB init_intinfo, claim interface %d failed, err %d %s",
+					FOUNDIF(found), err, devstr);
+		}
+		goto HitagiClose;
+	}
+
+	goto Hitagi;
+
+HitagiClose:
+
+	cg_wlock(&cgusb_fd_lock);
+	libusb_close(copy->usbdev->handle);
+	copy->usbdev->handle = NULL;
+	cg_wunlock(&cgusb_fd_lock);
+
+	copy->usbdev = free_cgusb(copy->usbdev);
+
+	copy = usb_free_cgpu(copy);
+
+Hitagi:
+
+	DEVUNLOCK(orig, pstate);
+
+	return copy;
+}
+
 bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found_match)
 bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found_match)
 {
 {
 	struct usb_find_devices *found_use = NULL;
 	struct usb_find_devices *found_use = NULL;
@@ -2391,7 +2667,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle,
 	return err;
 	return err;
 }
 }
 
 
-int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, enum usb_cmds cmd, bool readonce)
+int _usb_read(struct cgpu_info *cgpu, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, enum usb_cmds cmd, bool readonce)
 {
 {
 	struct cg_usb_device *usbdev;
 	struct cg_usb_device *usbdev;
 	bool ftdi;
 	bool ftdi;
@@ -2419,7 +2695,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro
 	usbdev = cgpu->usbdev;
 	usbdev = cgpu->usbdev;
 	ftdi = (usbdev->usb_type == USB_TYPE_FTDI);
 	ftdi = (usbdev->usb_type == USB_TYPE_FTDI);
 
 
-	USBDEBUG("USB debug: _usb_read(%s (nodev=%s),ep=%d,buf=%p,bufsiz=%zu,proc=%p,timeout=%u,end=%s,cmd=%s,ftdi=%s,readonce=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), ep, buf, bufsiz, processed, timeout, end ? (char *)str_text((char *)end) : "NULL", usb_cmdname(cmd), bool_str(ftdi), bool_str(readonce));
+	USBDEBUG("USB debug: _usb_read(%s (nodev=%s),epinfo=%d,buf=%p,bufsiz=%zu,proc=%p,timeout=%u,end=%s,cmd=%s,ftdi=%s,readonce=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), epinfo, buf, bufsiz, processed, timeout, end ? (char *)str_text((char *)end) : "NULL", usb_cmdname(cmd), bool_str(ftdi), bool_str(readonce));
 
 
 	if (bufsiz > USB_MAX_READ)
 	if (bufsiz > USB_MAX_READ)
 		quit(1, "%s USB read request %d too large (max=%d)", cgpu->drv->name, (int)bufsiz, USB_MAX_READ);
 		quit(1, "%s USB read request %d too large (max=%d)", cgpu->drv->name, (int)bufsiz, USB_MAX_READ);
@@ -2473,7 +2749,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro
 				}
 				}
 			}
 			}
 			err = usb_bulk_transfer(usbdev->handle,
 			err = usb_bulk_transfer(usbdev->handle,
-						usbdev->found->eps[ep].ep,
+						USBEP(usbdev, epinfo),
 						ptr, usbbufread, &got, timeout,
 						ptr, usbbufread, &got, timeout,
 						cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1);
 						cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1);
 			cgtime(&tv_finish);
 			cgtime(&tv_finish);
@@ -2516,7 +2792,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro
 		// N.B. usbdev->buffer was emptied before the while() loop
 		// N.B. usbdev->buffer was emptied before the while() loop
 		if (usbdev->buffer && tot > (int)bufsiz) {
 		if (usbdev->buffer && tot > (int)bufsiz) {
 			usbdev->bufamt = tot - bufsiz;
 			usbdev->bufamt = tot - bufsiz;
-			memcpy(usbdev->buffer, ptr + bufsiz, usbdev->bufamt);
+			memcpy(usbdev->buffer, usbbuf + bufsiz, usbdev->bufamt);
 			tot -= usbdev->bufamt;
 			tot -= usbdev->bufamt;
 			usbbuf[tot] = '\0';
 			usbbuf[tot] = '\0';
 			applog(LOG_ERR, "USB: %s%i read1 buffering %d extra bytes",
 			applog(LOG_ERR, "USB: %s%i read1 buffering %d extra bytes",
@@ -2577,7 +2853,7 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro
 			}
 			}
 		}
 		}
 		err = usb_bulk_transfer(usbdev->handle,
 		err = usb_bulk_transfer(usbdev->handle,
-					usbdev->found->eps[ep].ep, ptr,
+					USBEP(usbdev, epinfo), ptr,
 					usbbufread, &got, timeout,
 					usbbufread, &got, timeout,
 					cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1);
 					cgpu, MODE_BULK_READ, cmd, first ? SEQ0 : SEQ1);
 		cgtime(&tv_finish);
 		cgtime(&tv_finish);
@@ -2664,7 +2940,7 @@ out_unlock:
 	return err;
 	return err;
 }
 }
 
 
-int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds cmd)
+int _usb_write(struct cgpu_info *cgpu, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds cmd)
 {
 {
 	struct cg_usb_device *usbdev;
 	struct cg_usb_device *usbdev;
 	struct timeval read_start, tv_finish;
 	struct timeval read_start, tv_finish;
@@ -2675,7 +2951,7 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr
 
 
 	DEVLOCK(cgpu, pstate);
 	DEVLOCK(cgpu, pstate);
 
 
-	USBDEBUG("USB debug: _usb_write(%s (nodev=%s),ep=%d,buf='%s',bufsiz=%zu,proc=%p,timeout=%u,cmd=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), ep, (char *)str_text(buf), bufsiz, processed, timeout, usb_cmdname(cmd));
+	USBDEBUG("USB debug: _usb_write(%s (nodev=%s),epinfo=%d,buf='%s',bufsiz=%zu,proc=%p,timeout=%u,cmd=%s)", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), epinfo, (char *)str_text(buf), bufsiz, processed, timeout, usb_cmdname(cmd));
 
 
 	*processed = 0;
 	*processed = 0;
 
 
@@ -2718,7 +2994,7 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr
 			usbdev->last_write_siz = bufsiz;
 			usbdev->last_write_siz = bufsiz;
 		}
 		}
 		err = usb_bulk_transfer(usbdev->handle,
 		err = usb_bulk_transfer(usbdev->handle,
-					usbdev->found->eps[ep].ep,
+					USBEP(usbdev, epinfo),
 					(unsigned char *)buf, bufsiz, &sent,
 					(unsigned char *)buf, bufsiz, &sent,
 					timeout, cgpu, MODE_BULK_WRITE, cmd, first ? SEQ0 : SEQ1);
 					timeout, cgpu, MODE_BULK_WRITE, cmd, first ? SEQ0 : SEQ1);
 		cgtime(&tv_finish);
 		cgtime(&tv_finish);
@@ -2956,7 +3232,7 @@ int usb_ftdi_set_latency(struct cgpu_info *cgpu)
 		if (!err)
 		if (!err)
 			err = __usb_transfer(cgpu, FTDI_TYPE_OUT, FTDI_REQUEST_LATENCY,
 			err = __usb_transfer(cgpu, FTDI_TYPE_OUT, FTDI_REQUEST_LATENCY,
 						cgpu->usbdev->found->latency,
 						cgpu->usbdev->found->latency,
-						cgpu->usbdev->found->interface,
+						USBIF(cgpu->usbdev),
 						NULL, 0, DEVTIMEOUT, C_LATENCY);
 						NULL, 0, DEVTIMEOUT, C_LATENCY);
 	}
 	}
 
 
@@ -3083,7 +3359,7 @@ int usb_interface(struct cgpu_info *cgpu)
 	DEVLOCK(cgpu, pstate);
 	DEVLOCK(cgpu, pstate);
 
 
 	if (cgpu->usbdev)
 	if (cgpu->usbdev)
-		interface = cgpu->usbdev->found->interface;
+		interface = USBIF(cgpu->usbdev);
 
 
 	DEVUNLOCK(cgpu, pstate);
 	DEVUNLOCK(cgpu, pstate);
 
 

+ 13 - 7
usbutils.h

@@ -109,18 +109,24 @@
 // Use the device defined timeout
 // Use the device defined timeout
 #define DEVTIMEOUT 0
 #define DEVTIMEOUT 0
 
 
-// For endpoints defined in usb_find_devices.eps,
-// the first two must be the default IN and OUT
+// For endpoints defined in usb_find_devices.intinfos.epinfos,
+// the first two must be the default IN and OUT and both must always exist
 #define DEFAULT_EP_IN 0
 #define DEFAULT_EP_IN 0
 #define DEFAULT_EP_OUT 1
 #define DEFAULT_EP_OUT 1
 
 
-struct usb_endpoints {
+struct usb_epinfo {
 	uint8_t att;
 	uint8_t att;
 	uint16_t size;
 	uint16_t size;
 	unsigned char ep;
 	unsigned char ep;
 	bool found;
 	bool found;
 };
 };
 
 
+struct usb_intinfo {
+	int interface;
+	int epinfo_count;
+	struct usb_epinfo *epinfos;
+};
+
 enum sub_ident {
 enum sub_ident {
 	IDENT_UNK = 0,
 	IDENT_UNK = 0,
 	IDENT_BAJ,
 	IDENT_BAJ,
@@ -149,14 +155,13 @@ struct usb_find_devices {
 	uint16_t idProduct;
 	uint16_t idProduct;
 	char *iManufacturer;
 	char *iManufacturer;
 	char *iProduct;
 	char *iProduct;
-	int kernel;
 	int config;
 	int config;
-	int interface;
 	unsigned int timeout;
 	unsigned int timeout;
 	uint16_t wMaxPacketSize;
 	uint16_t wMaxPacketSize;
 	uint16_t latency;
 	uint16_t latency;
-	int epcount;
-	struct usb_endpoints *eps;
+	int which_intinfo;
+	int intinfo_count;
+	struct usb_intinfo *intinfos;
 };
 };
 
 
 /* Latency is set to 32ms to prevent a transfer ever being more than 512 bytes
 /* Latency is set to 32ms to prevent a transfer ever being more than 512 bytes
@@ -343,6 +348,7 @@ struct cgpu_info *usb_alloc_cgpu(struct device_drv *drv, int threads);
 struct cgpu_info *usb_free_cgpu_devlock(struct cgpu_info *cgpu, bool free_devlock);
 struct cgpu_info *usb_free_cgpu_devlock(struct cgpu_info *cgpu, bool free_devlock);
 #define usb_free_cgpu(cgpu) usb_free_cgpu_devlock(cgpu, true)
 #define usb_free_cgpu(cgpu) usb_free_cgpu_devlock(cgpu, true)
 void usb_uninit(struct cgpu_info *cgpu);
 void usb_uninit(struct cgpu_info *cgpu);
+struct cgpu_info *usb_init_intinfo(struct cgpu_info *orig,  int intinfo);
 bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found);
 bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found);
 void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *));
 void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *));
 struct api_data *api_usb_stats(int *count);
 struct api_data *api_usb_stats(int *count);

+ 80 - 73
util.c

@@ -16,7 +16,9 @@
 #include <stdarg.h>
 #include <stdarg.h>
 #include <string.h>
 #include <string.h>
 #include <jansson.h>
 #include <jansson.h>
+#ifdef HAVE_LIBCURL
 #include <curl/curl.h>
 #include <curl/curl.h>
+#endif
 #include <time.h>
 #include <time.h>
 #include <errno.h>
 #include <errno.h>
 #include <unistd.h>
 #include <unistd.h>
@@ -45,6 +47,44 @@
 #define DEFAULT_SOCKWAIT 60
 #define DEFAULT_SOCKWAIT 60
 
 
 bool successful_connect = false;
 bool successful_connect = false;
+static void keep_sockalive(SOCKETTYPE fd)
+{
+	const int tcp_one = 1;
+#ifndef WIN32
+	const int tcp_keepidle = 45;
+	const int tcp_keepintvl = 30;
+	int flags = fcntl(fd, F_GETFL, 0);
+
+	fcntl(fd, F_SETFL, O_NONBLOCK | flags);
+#else
+	u_long flags = 1;
+
+	ioctlsocket(fd, FIONBIO, &flags);
+#endif
+
+	setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&tcp_one, sizeof(tcp_one));
+	if (!opt_delaynet)
+#ifndef __linux
+		setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&tcp_one, sizeof(tcp_one));
+#else /* __linux */
+		setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&tcp_one, sizeof(tcp_one));
+	setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &tcp_one, sizeof(tcp_one));
+	setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle));
+	setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl));
+#endif /* __linux */
+
+#ifdef __APPLE_CC__
+	setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &tcp_keepintvl, sizeof(tcp_keepintvl));
+#endif /* __APPLE_CC__ */
+
+}
+
+struct tq_ent {
+	void			*data;
+	struct list_head	q_node;
+};
+
+#ifdef HAVE_LIBCURL
 struct timeval nettime;
 struct timeval nettime;
 
 
 struct data_buffer {
 struct data_buffer {
@@ -67,11 +107,6 @@ struct header_info {
 	bool		hadexpire;
 	bool		hadexpire;
 };
 };
 
 
-struct tq_ent {
-	void			*data;
-	struct list_head	q_node;
-};
-
 static void databuf_free(struct data_buffer *db)
 static void databuf_free(struct data_buffer *db)
 {
 {
 	if (!db)
 	if (!db)
@@ -202,36 +237,19 @@ out:
 	return ptrlen;
 	return ptrlen;
 }
 }
 
 
-static void keep_sockalive(SOCKETTYPE fd)
+static void last_nettime(struct timeval *last)
 {
 {
-	const int tcp_one = 1;
-#ifndef WIN32
-	const int tcp_keepidle = 45;
-	const int tcp_keepintvl = 30;
-	int flags = fcntl(fd, F_GETFL, 0);
-
-	fcntl(fd, F_SETFL, O_NONBLOCK | flags);
-#else
-	u_long flags = 1;
-
-	ioctlsocket(fd, FIONBIO, &flags);
-#endif
-
-	setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&tcp_one, sizeof(tcp_one));
-	if (!opt_delaynet)
-#ifndef __linux
-		setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&tcp_one, sizeof(tcp_one));
-#else /* __linux */
-		setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&tcp_one, sizeof(tcp_one));
-	setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &tcp_one, sizeof(tcp_one));
-	setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle));
-	setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl));
-#endif /* __linux */
-
-#ifdef __APPLE_CC__
-	setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &tcp_keepintvl, sizeof(tcp_keepintvl));
-#endif /* __APPLE_CC__ */
+	rd_lock(&netacc_lock);
+	last->tv_sec = nettime.tv_sec;
+	last->tv_usec = nettime.tv_usec;
+	rd_unlock(&netacc_lock);
+}
 
 
+static void set_nettime(void)
+{
+	wr_lock(&netacc_lock);
+	cgtime(&nettime);
+	wr_unlock(&netacc_lock);
 }
 }
 
 
 #if CURL_HAS_KEEPALIVE
 #if CURL_HAS_KEEPALIVE
@@ -255,21 +273,6 @@ static void keep_curlalive(CURL *curl)
 }
 }
 #endif
 #endif
 
 
-static void last_nettime(struct timeval *last)
-{
-	rd_lock(&netacc_lock);
-	last->tv_sec = nettime.tv_sec;
-	last->tv_usec = nettime.tv_usec;
-	rd_unlock(&netacc_lock);
-}
-
-static void set_nettime(void)
-{
-	wr_lock(&netacc_lock);
-	cgtime(&nettime);
-	wr_unlock(&netacc_lock);
-}
-
 static int curl_debug_cb(__maybe_unused CURL *handle, curl_infotype type,
 static int curl_debug_cb(__maybe_unused CURL *handle, curl_infotype type,
 			 __maybe_unused char *data, size_t size, void *userdata)
 			 __maybe_unused char *data, size_t size, void *userdata)
 {
 {
@@ -513,29 +516,35 @@ err_out:
 	curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
 	curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
 	return NULL;
 	return NULL;
 }
 }
+#define PROXY_HTTP	CURLPROXY_HTTP
+#define PROXY_HTTP_1_0	CURLPROXY_HTTP_1_0
+#define PROXY_SOCKS4	CURLPROXY_SOCKS4
+#define PROXY_SOCKS5	CURLPROXY_SOCKS5
+#define PROXY_SOCKS4A	CURLPROXY_SOCKS4A
+#define PROXY_SOCKS5H	CURLPROXY_SOCKS5_HOSTNAME
+#else /* HAVE_LIBCURL */
+#define PROXY_HTTP	0
+#define PROXY_HTTP_1_0	1
+#define PROXY_SOCKS4	2
+#define PROXY_SOCKS5	3
+#define PROXY_SOCKS4A	4
+#define PROXY_SOCKS5H	5
+#endif /* HAVE_LIBCURL */
 
 
-#if (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 10) || (LIBCURL_VERSION_MAJOR > 7)
 static struct {
 static struct {
 	const char *name;
 	const char *name;
-	curl_proxytype proxytype;
+	proxytypes_t proxytype;
 } proxynames[] = {
 } proxynames[] = {
-	{ "http:",	CURLPROXY_HTTP },
-#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR > 19) || (LIBCURL_VERSION_MINOR == 19 && LIBCURL_VERSION_PATCH >= 4)
-	{ "http0:",	CURLPROXY_HTTP_1_0 },
-#endif
-#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR > 15) || (LIBCURL_VERSION_MINOR == 15 && LIBCURL_VERSION_PATCH >= 2)
-	{ "socks4:",	CURLPROXY_SOCKS4 },
-#endif
-	{ "socks5:",	CURLPROXY_SOCKS5 },
-#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MINOR >= 18)
-	{ "socks4a:",	CURLPROXY_SOCKS4A },
-	{ "socks5h:",	CURLPROXY_SOCKS5_HOSTNAME },
-#endif
+	{ "http:",	PROXY_HTTP },
+	{ "http0:",	PROXY_HTTP_1_0 },
+	{ "socks4:",	PROXY_SOCKS4 },
+	{ "socks5:",	PROXY_SOCKS5 },
+	{ "socks4a:",	PROXY_SOCKS4A },
+	{ "socks5h:",	PROXY_SOCKS5H },
 	{ NULL,	0 }
 	{ NULL,	0 }
 };
 };
-#endif
 
 
-const char *proxytype(curl_proxytype proxytype)
+const char *proxytype(proxytypes_t proxytype)
 {
 {
 	int i;
 	int i;
 
 
@@ -550,7 +559,6 @@ char *get_proxy(char *url, struct pool *pool)
 {
 {
 	pool->rpc_proxy = NULL;
 	pool->rpc_proxy = NULL;
 
 
-#if (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 10) || (LIBCURL_VERSION_MAJOR > 7)
 	char *split;
 	char *split;
 	int plen, len, i;
 	int plen, len, i;
 
 
@@ -573,7 +581,6 @@ char *get_proxy(char *url, struct pool *pool)
 			break;
 			break;
 		}
 		}
 	}
 	}
-#endif
 	return url;
 	return url;
 }
 }
 
 
@@ -1948,7 +1955,7 @@ static bool setup_stratum_socket(struct pool *pool)
 	if (!pool->rpc_proxy && opt_socks_proxy) {
 	if (!pool->rpc_proxy && opt_socks_proxy) {
 		pool->rpc_proxy = opt_socks_proxy;
 		pool->rpc_proxy = opt_socks_proxy;
 		extract_sockaddr(pool->rpc_proxy, &pool->sockaddr_proxy_url, &pool->sockaddr_proxy_port);
 		extract_sockaddr(pool->rpc_proxy, &pool->sockaddr_proxy_url, &pool->sockaddr_proxy_port);
-		pool->rpc_proxytype = CURLPROXY_SOCKS5;
+		pool->rpc_proxytype = PROXY_SOCKS5;
 	}
 	}
 
 
 	if (pool->rpc_proxy) {
 	if (pool->rpc_proxy) {
@@ -1995,24 +2002,24 @@ static bool setup_stratum_socket(struct pool *pool)
 
 
 	if (pool->rpc_proxy) {
 	if (pool->rpc_proxy) {
 		switch (pool->rpc_proxytype) {
 		switch (pool->rpc_proxytype) {
-			case CURLPROXY_HTTP_1_0:
+			case PROXY_HTTP_1_0:
 				if (!http_negotiate(pool, sockd, true))
 				if (!http_negotiate(pool, sockd, true))
 					return false;
 					return false;
 				break;
 				break;
-			case CURLPROXY_HTTP:
+			case PROXY_HTTP:
 				if (!http_negotiate(pool, sockd, false))
 				if (!http_negotiate(pool, sockd, false))
 					return false;
 					return false;
 				break;
 				break;
-			case CURLPROXY_SOCKS5:
-			case CURLPROXY_SOCKS5_HOSTNAME:
+			case PROXY_SOCKS5:
+			case PROXY_SOCKS5H:
 				if (!socks5_negotiate(pool, sockd))
 				if (!socks5_negotiate(pool, sockd))
 					return false;
 					return false;
 				break;
 				break;
-			case CURLPROXY_SOCKS4:
+			case PROXY_SOCKS4:
 				if (!socks4_negotiate(pool, sockd, false))
 				if (!socks4_negotiate(pool, sockd, false))
 					return false;
 					return false;
 				break;
 				break;
-			case CURLPROXY_SOCKS4A:
+			case PROXY_SOCKS4A:
 				if (!socks4_negotiate(pool, sockd, true))
 				if (!socks4_negotiate(pool, sockd, true))
 					return false;
 					return false;
 				break;
 				break;

+ 6 - 0
util.h

@@ -52,6 +52,12 @@
 #define JSON_LOADS(str, err_ptr) json_loads((str), (err_ptr))
 #define JSON_LOADS(str, err_ptr) json_loads((str), (err_ptr))
 #endif
 #endif
 
 
+#ifdef HAVE_LIBCURL
+typedef curl_proxytype proxytypes_t;
+#else
+typedef int proxytypes_t;
+#endif /* HAVE_LIBCURL */
+
 /* cgminer specific unnamed semaphore implementations to cope with osx not
 /* cgminer specific unnamed semaphore implementations to cope with osx not
  * implementing them. */
  * implementing them. */
 #ifdef __APPLE__
 #ifdef __APPLE__