Browse Source

Merge branch 'dualminer' into bfgminer

Luke Dashjr 12 years ago
parent
commit
5ae0f9196a
9 changed files with 1230 additions and 48 deletions
  1. 1 0
      AUTHORS
  2. 4 0
      Makefile.am
  3. 20 0
      configure.ac
  4. 334 0
      driver-dualminer.c
  5. 73 36
      driver-icarus.c
  6. 712 0
      gc3355.c
  7. 66 0
      gc3355.h
  8. 13 1
      icarus-common.h
  9. 7 11
      miner.c

+ 1 - 0
AUTHORS

@@ -1,6 +1,7 @@
 FPGA/ASIC mining and refactor: Luke Dashjr <luke-jr+bfgminer@utopios.org> 1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh
 FPGA/ASIC mining and refactor: Luke Dashjr <luke-jr+bfgminer@utopios.org> 1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh
 GPU mining and refactor: Con Kolivas <kernel@kolivas.org> 15qSxP1SQcUX3o4nhkfdbgyoWEFMomJ4rZ
 GPU mining and refactor: Con Kolivas <kernel@kolivas.org> 15qSxP1SQcUX3o4nhkfdbgyoWEFMomJ4rZ
 AntMiner driver: Nate Woolls <nwoolls@gmail.com> and Lingchao Xu <lingchao.xu@bitmaintech.com>
 AntMiner driver: Nate Woolls <nwoolls@gmail.com> and Lingchao Xu <lingchao.xu@bitmaintech.com>
+DualMiner driver: Nate Woolls <nwoolls@gmail.com> and Dualminer Team <dualminer@broadeng.net>
 Bitfury GPIO-based drivers: Bitfury and Anatoly Legkodymov <legko777@fastmail.fm>
 Bitfury GPIO-based drivers: Bitfury and Anatoly Legkodymov <legko777@fastmail.fm>
 Big Picture Mining and TwinFury drivers: Andreas Auer <aauer1@gmail.com>
 Big Picture Mining and TwinFury drivers: Andreas Auer <aauer1@gmail.com>
 Avalon and Icarus drivers: Xiangfu <xiangfu@openmobilefree.net>
 Avalon and Icarus drivers: Xiangfu <xiangfu@openmobilefree.net>

+ 4 - 0
Makefile.am

@@ -235,6 +235,10 @@ bfgminer_SOURCES += driver-erupter.c
 bfgminer_SOURCES += driver-antminer.c
 bfgminer_SOURCES += driver-antminer.c
 endif
 endif
 
 
+if USE_DUALMINER
+bfgminer_SOURCES += driver-dualminer.c gc3355.c gc3355.h
+endif
+
 if HAS_AVALON
 if HAS_AVALON
 bfgminer_SOURCES += driver-avalon.c driver-avalon.h hexdump.c
 bfgminer_SOURCES += driver-avalon.c driver-avalon.h hexdump.c
 endif
 endif

+ 20 - 0
configure.ac

@@ -430,6 +430,26 @@ if test "x$icarus" = xyes; then
 fi
 fi
 AM_CONDITIONAL([HAS_ICARUS], [test x$icarus = xyes])
 AM_CONDITIONAL([HAS_ICARUS], [test x$icarus = xyes])
 
 
+driverlist="$driverlist dualminer"
+AC_ARG_ENABLE([dualminer],
+	[AC_HELP_STRING([--disable-dualminer],[Compile support for DualMiner (default enabled)])],
+	[dualminer=$enableval],
+	[dualminer=auto]
+	)
+if test "x$dualminer" = "xno"; then
+	true
+elif test "x$icarus" = "xyes"; then
+	dualminer=yes
+elif test "x$dualminer" = "xyes"; then
+	AC_MSG_ERROR([You explicitly disabled Icarus and explicitly enabled DualMiner])
+else
+	dualminer=no
+fi
+if test "x$dualminer" = "xyes"; then
+	AC_DEFINE([USE_DUALMINER], [1], [Defined to 1 if DualMiner support is wanted])
+fi
+AM_CONDITIONAL([USE_DUALMINER], [test x$dualminer = xyes])
+
 driverlist="$driverlist avalon"
 driverlist="$driverlist avalon"
 avalon="no"
 avalon="no"
 
 

+ 334 - 0
driver-dualminer.c

@@ -0,0 +1,334 @@
+/*
+ * Copyright 2013 Luke Dashjr
+ * Copyright 2014 Nate Woolls
+ * Copyright 2014 Dualminer Team
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include "miner.h"
+#include "icarus-common.h"
+#include "lowlevel.h"
+#include "lowl-vcom.h"
+#include "deviceapi.h"
+#include "logging.h"
+#include "util.h"
+#include "gc3355.h"
+
+#ifndef WIN32
+  #include <sys/ioctl.h>
+#else
+  #include <io.h>
+#endif
+
+#define DUALMINER_IO_SPEED 115200
+
+#define DUALMINER_SCRYPT_HASH_TIME		0.00001428571429
+#define DUALMINER_SCRYPT_DM_HASH_TIME	0.00003333333333
+#define DUALMINER_SHA2_HASH_TIME		0.00000000300000
+
+#define DUALMINER_SCRYPT_READ_COUNT 48  // 4.8s to read
+#define DUALMINER_SHA2_READ_COUNT	16  // 1.6s to read
+
+static
+const char sha2_golden_ob[] =
+	"55aa0f00a08701004a548fe471fa3a9a"
+	"1371144556c3f64d2500b4826008fe4b"
+	"bf7698c94eba7946ce22a72f4f672614"
+	"1a0b3287";
+
+static
+const char sha2_golden_nonce[] = "a2870100";
+
+static
+const char scrypt_golden_ob[] =
+	"55aa1f00000000000000000000000000"
+	"000000000000000000000000aaaaaaaa"
+	"711c0000603ebdb6e35b05223c54f815"
+	"5ac33123006b4192e7aafafbeb9ef654"
+	"4d2973d700000002069b9f9e3ce8a677"
+	"8dea3d7a00926cd6eaa9585502c9b83a"
+	"5601f198d7fbf09be9559d6335ebad36"
+	"3e4f147a8d9934006963030b4e54c408"
+	"c837ebc2eeac129852a55fee1b1d88f6"
+	"000c050000000600";
+
+static
+const char scrypt_golden_nonce[] = "dd0c0500";
+
+enum
+{
+	RTS_LOW = 0,
+	RTS_HIGH = 1
+};
+
+BFG_REGISTER_DRIVER(dualminer_drv)
+static
+const struct bfg_set_device_definition dualminer_set_device_funcs[];
+
+// device helper functions
+
+static
+void dualminer_bootstrap_device(int fd)
+{
+	gc3355_dual_reset(fd);
+
+	if (opt_scrypt && !opt_dual_mode)
+		gc3355_opt_scrypt_only_init(fd);
+	else
+		gc3355_dualminer_init(fd);
+
+	usleep(1000);
+}
+
+static
+void dualminer_teardown_device(int fd)
+{
+	if (opt_scrypt)
+		gc3355_open_scrypt_unit(fd, SCRYPT_UNIT_CLOSE);
+	else
+		gc3355_open_sha2_unit(fd, "0");
+
+	gc3355_set_rts_status(fd, RTS_LOW);
+}
+
+static
+bool dualminer_init(struct thr_info * const thr)
+{
+	struct cgpu_info * const cgpu = thr->cgpu;
+	
+	if (opt_scrypt)
+		cgpu->min_nonce_diff = 1./0x10000;
+	
+	return icarus_init(thr);
+}
+
+static
+void dualminer_init_firstrun(struct cgpu_info *icarus)
+{
+	struct ICARUS_INFO *info = icarus->device_data;
+	int fd = icarus->device_fd;
+
+	dualminer_bootstrap_device(fd);
+
+	if (opt_scrypt)
+		gc3355_set_rts_status(fd, RTS_HIGH);
+
+	gc3355_init(fd, opt_dualminer_sha2_gating, !opt_dual_mode);
+	applog(LOG_DEBUG, "%"PRIpreprv": scrypt: %d, scrypt only: %d; have fan: %d\n", icarus->proc_repr, opt_scrypt, opt_scrypt, opt_hubfans);
+
+	if (gc3355_get_cts_status(fd) != 1)
+	{
+		// Scrypt + SHA2 mode
+		if (opt_scrypt)
+			info->Hs = DUALMINER_SCRYPT_DM_HASH_TIME;
+	}
+
+	applog(LOG_DEBUG, "%"PRIpreprv": dualminer: Init: pll=%d, sha2num=%d", icarus->proc_repr, opt_pll_freq, opt_sha2_number);
+}
+
+// ICARUS_INFO functions - icarus-common.h
+
+static
+bool dualminer_detect_init(const char *devpath, int fd, struct ICARUS_INFO * __maybe_unused info)
+{
+	dualminer_bootstrap_device(fd);
+
+	return true;
+}
+
+static
+bool dualminer_job_start(struct thr_info * const thr)
+{
+	struct cgpu_info *icarus = thr->cgpu;
+	struct icarus_state * const state = thr->cgpu_data;
+	int fd = icarus->device_fd;
+
+	if (state->firstrun)
+		dualminer_init_firstrun(icarus);
+
+	if (opt_scrypt)
+	{
+		if (opt_dual_mode)
+			gc3355_dualminer_init(fd);
+		else
+			gc3355_opt_scrypt_init(fd);
+	}
+
+	return icarus_job_start(thr);
+}
+
+// device detection
+
+static
+bool dualminer_detect_one(const char *devpath)
+{
+	struct device_drv *drv = &dualminer_drv;
+
+	struct ICARUS_INFO *info = calloc(1, sizeof(struct ICARUS_INFO));
+	if (unlikely(!info))
+		quit(1, "Failed to malloc ICARUS_INFO");
+
+	*info = (struct ICARUS_INFO){
+		.baud = DUALMINER_IO_SPEED,
+		.timing_mode = MODE_DEFAULT,
+		.do_icarus_timing = false,
+		.nonce_littleendian = true,
+		.work_division = 2,
+		.fpga_count = 2,
+		.detect_init_func = dualminer_detect_init,
+		.job_start_func = dualminer_job_start
+	};
+
+	if (opt_scrypt)
+	{
+		info->golden_ob = (char*)scrypt_golden_ob;
+		info->golden_nonce = (char*)scrypt_golden_nonce;
+		info->Hs = DUALMINER_SCRYPT_HASH_TIME;
+	}
+	else
+	{
+		info->golden_ob = (char*)sha2_golden_ob;
+		info->golden_nonce = (char*)sha2_golden_nonce;
+		info->Hs = DUALMINER_SHA2_HASH_TIME;
+	}
+
+	drv_set_defaults(drv, dualminer_set_device_funcs, info, devpath, detectone_meta_info.serial, 1);
+
+	if (!icarus_detect_custom(devpath, drv, info))
+	{
+		free(info);
+		return false;
+	}
+
+	if (opt_scrypt)
+		info->read_count = DUALMINER_SCRYPT_READ_COUNT; // 4.8s to read
+	else
+		info->read_count = DUALMINER_SHA2_READ_COUNT; // 1.6s to read
+
+	return true;
+}
+
+// support for --set-device dualminer:dual_mode=1
+// most be set before probing the device
+
+static
+const char *dualminer_set_dual_mode(struct cgpu_info * const proc, const char * const option, const char * const setting, char * const replybuf, enum bfg_set_device_replytype * const success)
+{
+	int val = atoi(setting);
+	opt_dual_mode = val == 1;
+	return NULL;
+}
+
+static
+const struct bfg_set_device_definition dualminer_set_device_funcs[] = {
+	{"dual_mode", dualminer_set_dual_mode, "set to 1 to enable dual algorithm mining with two BFGMiner processes"},
+	{NULL},
+};
+
+// device_drv functions - miner.h
+
+static
+bool dualminer_lowl_probe(const struct lowlevel_device_info * const info)
+{
+	return vcom_lowl_probe_wrapper(info, dualminer_detect_one);
+}
+
+static
+void dualminer_thread_shutdown(struct thr_info *thr)
+{
+	// dualminer teardown
+	dualminer_teardown_device(thr->cgpu->device_fd);
+
+	// icarus teardown
+	do_icarus_close(thr);
+	free(thr->cgpu_data);
+}
+
+static
+bool dualminer_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused uint64_t max_nonce)
+{
+	struct cgpu_info * const icarus = thr->cgpu;
+	struct icarus_state * const state = thr->cgpu_data;
+	struct ICARUS_INFO * const info = icarus->device_data;
+
+	memset(state->ob_bin, 0, info->ob_size);
+
+	if (opt_scrypt)
+	{
+		state->ob_bin[0] = 0x55;
+		state->ob_bin[1] = 0xaa;
+		state->ob_bin[2] = 0x1f;
+		state->ob_bin[3] = 0x00;
+		memcpy(state->ob_bin + 4, work->target, 32);
+		memcpy(state->ob_bin + 36, work->midstate, 32);
+		memcpy(state->ob_bin + 68, work->data, 80);
+		state->ob_bin[148] = 0xff;
+		state->ob_bin[149] = 0xff;
+		state->ob_bin[150] = 0xff;
+		state->ob_bin[151] = 0xff;
+	}
+	else
+	{
+		uint8_t temp_bin[64];
+		memset(temp_bin, 0, 64);
+		memcpy(temp_bin, work->midstate, 32);
+		memcpy(temp_bin+52, work->data + 64, 12);
+		state->ob_bin[0] = 0x55;
+		state->ob_bin[1] = 0xaa;
+		state->ob_bin[2] = 0x0f;
+		state->ob_bin[3] = 0x00;
+		memcpy(state->ob_bin + 8, temp_bin, 32);
+		memcpy(state->ob_bin + 40, temp_bin + 52, 12);
+	}
+
+	return true;
+}
+
+// support for --set-device dualminer:clock=freq
+static
+char *dualminer_set_device(struct cgpu_info *cgpu, char *option, char *setting, char *replybuf)
+{
+	if (strcasecmp(option, "clock") == 0)
+	{
+		int val = atoi(setting);
+		opt_pll_freq = val;
+		return NULL;
+	}
+
+	sprintf(replybuf, "Unknown option: %s", option);
+	return replybuf;
+}
+
+// device_drv definition - miner.h
+
+static
+void dualminer_drv_init()
+{
+	dualminer_drv = icarus_drv;
+	dualminer_drv.dname = "dualminer";
+	dualminer_drv.name = "DMU";
+	dualminer_drv.lowl_probe = dualminer_lowl_probe;
+	dualminer_drv.thread_init = dualminer_init;
+	dualminer_drv.thread_shutdown = dualminer_thread_shutdown;
+	dualminer_drv.job_prepare = dualminer_job_prepare;
+	dualminer_drv.set_device = dualminer_set_device;
+	++dualminer_drv.probe_priority;
+}
+
+struct device_drv dualminer_drv =
+{
+	.drv_init = dualminer_drv_init,
+};

+ 73 - 36
driver-icarus.c

@@ -163,9 +163,23 @@ static void rev(unsigned char *s, size_t l)
 	}
 	}
 }
 }
 
 
+static inline
+uint32_t icarus_nonce32toh(const struct ICARUS_INFO * const info, const uint32_t nonce)
+{
+	return info->nonce_littleendian ? le32toh(nonce) : be32toh(nonce);
+}
+
 #define icarus_open2(devpath, baud, purge)  serial_open(devpath, baud, ICARUS_READ_FAULT_DECISECONDS, purge)
 #define icarus_open2(devpath, baud, purge)  serial_open(devpath, baud, ICARUS_READ_FAULT_DECISECONDS, purge)
 #define icarus_open(devpath, baud)  icarus_open2(devpath, baud, false)
 #define icarus_open(devpath, baud)  icarus_open2(devpath, baud, false)
 
 
+static
+void icarus_log_protocol(int fd, const void *buf, size_t bufLen, const char *prefix)
+{
+	char hex[(bufLen * 2) + 1];
+	bin2hex(hex, buf, bufLen);
+	applog(LOG_DEBUG, "%s fd=%d: DEVPROTO: %s %s", icarus_drv.dname, fd, prefix, hex);
+}
+
 int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count, int read_size)
 int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct thr_info *thr, int read_count, int read_size)
 {
 {
 	ssize_t ret = 0;
 	ssize_t ret = 0;
@@ -231,6 +245,10 @@ int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, struct th
 		{
 		{
 			if (epollfd != -1)
 			if (epollfd != -1)
 				close(epollfd);
 				close(epollfd);
+
+			if (opt_dev_protocol && opt_debug)
+				icarus_log_protocol(fd, buf, read_size, "RECV");
+
 			return ICA_GETS_OK;
 			return ICA_GETS_OK;
 		}
 		}
 
 
@@ -264,6 +282,9 @@ int icarus_write(int fd, const void *buf, size_t bufLen)
 {
 {
 	size_t ret;
 	size_t ret;
 
 
+	if (opt_dev_protocol && opt_debug)
+		icarus_log_protocol(fd, buf, bufLen, "SEND");
+
 	if (unlikely(fd == -1))
 	if (unlikely(fd == -1))
 		return 1;
 		return 1;
 	
 	
@@ -276,7 +297,7 @@ int icarus_write(int fd, const void *buf, size_t bufLen)
 
 
 #define icarus_close(fd) serial_close(fd)
 #define icarus_close(fd) serial_close(fd)
 
 
-static void do_icarus_close(struct thr_info *thr)
+void do_icarus_close(struct thr_info *thr)
 {
 {
 	struct cgpu_info *icarus = thr->cgpu;
 	struct cgpu_info *icarus = thr->cgpu;
 	const int fd = icarus->device_fd;
 	const int fd = icarus->device_fd;
@@ -453,25 +474,7 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 	struct timeval tv_start, tv_finish;
 	struct timeval tv_start, tv_finish;
 	int fd;
 	int fd;
 
 
-	// Block 171874 nonce = (0xa2870100) = 0x000187a2
-	// N.B. golden_ob MUST take less time to calculate
-	//	than the timeout set in icarus_open()
-	//	This one takes ~0.53ms on Rev3 Icarus
-	const char golden_ob[] =
-		"4679ba4ec99876bf4bfe086082b40025"
-		"4df6c356451471139a3afa71e48f544a"
-		"00000000000000000000000000000000"
-		"0000000087320b1a1426674f2fa722ce";
-	/* NOTE: This gets sent to basically every port specified in --scan-serial,
-	 *       even ones that aren't Icarus; be sure they can all handle it, when
-	 *       this is changed...
-	 *       BitForce: Ignores entirely
-	 *       ModMiner: Starts (useless) work, gets back to clean state
-	 */
-
-	const char golden_nonce[] = "000187a2";
-
-	unsigned char ob_bin[64], nonce_bin[ICARUS_NONCE_SIZE];
+	unsigned char nonce_bin[ICARUS_NONCE_SIZE];
 	char nonce_hex[(sizeof(nonce_bin) * 2) + 1];
 	char nonce_hex[(sizeof(nonce_bin) * 2) + 1];
 
 
 	drv_set_defaults(api, icarus_set_device_funcs, info, devpath, detectone_meta_info.serial, 1);
 	drv_set_defaults(api, icarus_set_device_funcs, info, devpath, detectone_meta_info.serial, 1);
@@ -492,8 +495,36 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 	// e.g. Cairnsmore
 	// e.g. Cairnsmore
 	if (info->read_size == 0)
 	if (info->read_size == 0)
 		info->read_size = ICARUS_DEFAULT_READ_SIZE;
 		info->read_size = ICARUS_DEFAULT_READ_SIZE;
+	
+	if (!info->golden_ob)
+	{
+		// Block 171874 nonce = (0xa2870100) = 0x000187a2
+		// NOTE: this MUST take less time to calculate
+		//	than the timeout set in icarus_open()
+		//	This one takes ~0.53ms on Rev3 Icarus
+		info->golden_ob =
+			"4679ba4ec99876bf4bfe086082b40025"
+			"4df6c356451471139a3afa71e48f544a"
+			"00000000000000000000000000000000"
+			"0000000087320b1a1426674f2fa722ce";
+		/* NOTE: This gets sent to basically every port specified in --scan-serial,
+		 *       even ones that aren't Icarus; be sure they can all handle it, when
+		 *       this is changed...
+		 *       BitForce: Ignores entirely
+		 *       ModMiner: Starts (useless) work, gets back to clean state
+		 */
+		
+		info->golden_nonce = "000187a2";
+	}
 
 
-	hex2bin(ob_bin, golden_ob, sizeof(ob_bin));
+	if (info->detect_init_func)
+		info->detect_init_func(devpath, fd, info);
+	
+	int ob_size = strlen(info->golden_ob) / 2;
+	unsigned char ob_bin[ob_size];
+	BFGINIT(info->ob_size, ob_size);
+	
+	hex2bin(ob_bin, info->golden_ob, sizeof(ob_bin));
 	icarus_write(fd, ob_bin, sizeof(ob_bin));
 	icarus_write(fd, ob_bin, sizeof(ob_bin));
 	cgtime(&tv_start);
 	cgtime(&tv_start);
 
 
@@ -509,12 +540,13 @@ bool icarus_detect_custom(const char *devpath, struct device_drv *api, struct IC
 	icarus_close(fd);
 	icarus_close(fd);
 
 
 	bin2hex(nonce_hex, nonce_bin, sizeof(nonce_bin));
 	bin2hex(nonce_hex, nonce_bin, sizeof(nonce_bin));
-	if (strncmp(nonce_hex, golden_nonce, 8)) {
+	if (strncmp(nonce_hex, info->golden_nonce, 8))
+	{
 		applog(LOG_DEBUG,
 		applog(LOG_DEBUG,
 			"%s: "
 			"%s: "
 			"Test failed at %s: get %s, should: %s",
 			"Test failed at %s: get %s, should: %s",
 			api->dname,
 			api->dname,
-			devpath, nonce_hex, golden_nonce);
+			devpath, nonce_hex, info->golden_nonce);
 		return false;
 		return false;
 	}
 	}
 		
 		
@@ -628,12 +660,16 @@ static bool icarus_prepare(struct thr_info *thr)
 	return true;
 	return true;
 }
 }
 
 
-static bool icarus_init(struct thr_info *thr)
+bool icarus_init(struct thr_info *thr)
 {
 {
 	struct cgpu_info *icarus = thr->cgpu;
 	struct cgpu_info *icarus = thr->cgpu;
 	struct ICARUS_INFO *info = icarus->device_data;
 	struct ICARUS_INFO *info = icarus->device_data;
+	struct icarus_state * const state = thr->cgpu_data;
 	int fd = icarus->device_fd;
 	int fd = icarus->device_fd;
 	
 	
+	BFGINIT(info->job_start_func, icarus_job_start);
+	BFGINIT(state->ob_bin, malloc(info->ob_size));
+	
 	if (!info->work_division)
 	if (!info->work_division)
 	{
 	{
 		struct timeval tv_finish;
 		struct timeval tv_finish;
@@ -657,7 +693,7 @@ static bool icarus_init(struct thr_info *thr)
 		if (ICA_GETS_OK == icarus_gets(res_bin, fd, &tv_finish, NULL, info->read_count, info->read_size))
 		if (ICA_GETS_OK == icarus_gets(res_bin, fd, &tv_finish, NULL, info->read_count, info->read_size))
 		{
 		{
 			memcpy(&res, res_bin, sizeof(res));
 			memcpy(&res, res_bin, sizeof(res));
-			res = be32toh(res);
+			res = icarus_nonce32toh(info, res);
 		}
 		}
 		else
 		else
 			res = 0;
 			res = 0;
@@ -728,7 +764,7 @@ bool icarus_job_prepare(struct thr_info *thr, struct work *work, __maybe_unused
 	return true;
 	return true;
 }
 }
 
 
-static bool icarus_job_start(struct thr_info *thr)
+bool icarus_job_start(struct thr_info *thr)
 {
 {
 	struct cgpu_info *icarus = thr->cgpu;
 	struct cgpu_info *icarus = thr->cgpu;
 	struct ICARUS_INFO *info = icarus->device_data;
 	struct ICARUS_INFO *info = icarus->device_data;
@@ -746,7 +782,7 @@ static bool icarus_job_start(struct thr_info *thr)
 	
 	
 	cgtime(&state->tv_workstart);
 	cgtime(&state->tv_workstart);
 
 
-	ret = icarus_write(fd, ob_bin, 64);
+	ret = icarus_write(fd, ob_bin, info->ob_size);
 	if (ret) {
 	if (ret) {
 		do_icarus_close(thr);
 		do_icarus_close(thr);
 		applog(LOG_ERR, "%"PRIpreprv": Comms error (werr=%d)", icarus->proc_repr, ret);
 		applog(LOG_ERR, "%"PRIpreprv": Comms error (werr=%d)", icarus->proc_repr, ret);
@@ -755,8 +791,8 @@ static bool icarus_job_start(struct thr_info *thr)
 	}
 	}
 
 
 	if (opt_debug) {
 	if (opt_debug) {
-		char ob_hex[129];
-		bin2hex(ob_hex, ob_bin, 64);
+		char ob_hex[(info->ob_size * 2) + 1];
+		bin2hex(ob_hex, ob_bin, info->ob_size);
 		applog(LOG_DEBUG, "%"PRIpreprv" sent: %s",
 		applog(LOG_DEBUG, "%"PRIpreprv" sent: %s",
 			icarus->proc_repr,
 			icarus->proc_repr,
 			ob_hex);
 			ob_hex);
@@ -766,9 +802,9 @@ static bool icarus_job_start(struct thr_info *thr)
 }
 }
 
 
 static
 static
-struct work *icarus_process_worknonce(struct icarus_state *state, uint32_t *nonce)
+struct work *icarus_process_worknonce(const struct ICARUS_INFO * const info, struct icarus_state *state, uint32_t *nonce)
 {
 {
-	*nonce = be32toh(*nonce);
+	*nonce = icarus_nonce32toh(info, *nonce);
 	if (test_nonce(state->last_work, *nonce, false))
 	if (test_nonce(state->last_work, *nonce, false))
 		return state->last_work;
 		return state->last_work;
 	if (likely(state->last2_work && test_nonce(state->last2_work, *nonce, false)))
 	if (likely(state->last2_work && test_nonce(state->last2_work, *nonce, false)))
@@ -814,7 +850,7 @@ void handle_identify(struct thr_info * const thr, int ret, const bool was_first_
 			if (ret == ICA_GETS_OK)
 			if (ret == ICA_GETS_OK)
 			{
 			{
 				memcpy(&nonce, nonce_bin, sizeof(nonce));
 				memcpy(&nonce, nonce_bin, sizeof(nonce));
-				nonce = be32toh(nonce);
+				nonce = icarus_nonce32toh(info, nonce);
 				submit_nonce(thr, state->last_work, nonce);
 				submit_nonce(thr, state->last_work, nonce);
 			}
 			}
 		}
 		}
@@ -837,7 +873,7 @@ void handle_identify(struct thr_info * const thr, int ret, const bool was_first_
 	if (!state->firstrun)
 	if (!state->firstrun)
 	{
 	{
 		applog(LOG_DEBUG, "%"PRIpreprv": Identify: Starting next job", icarus->proc_repr);
 		applog(LOG_DEBUG, "%"PRIpreprv": Identify: Starting next job", icarus->proc_repr);
-		if (!icarus_job_start(thr))
+		if (!info->job_start_func(thr))
 no_job_start:
 no_job_start:
 			state->firstrun = true;
 			state->firstrun = true;
 	}
 	}
@@ -887,7 +923,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
 	struct icarus_state *state = thr->cgpu_data;
 	struct icarus_state *state = thr->cgpu_data;
 	was_first_run = state->firstrun;
 	was_first_run = state->firstrun;
 
 
-	icarus_job_prepare(thr, work, max_nonce);
+	icarus->drv->job_prepare(thr, work, max_nonce);
 
 
 	// Wait for the previous run's result
 	// Wait for the previous run's result
 	fd = icarus->device_fd;
 	fd = icarus->device_fd;
@@ -955,7 +991,7 @@ keepwaiting:
 	if (ret == ICA_GETS_OK)
 	if (ret == ICA_GETS_OK)
 	{
 	{
 		memcpy(&nonce, nonce_bin, sizeof(nonce));
 		memcpy(&nonce, nonce_bin, sizeof(nonce));
-		nonce_work = icarus_process_worknonce(state, &nonce);
+		nonce_work = icarus_process_worknonce(info, state, &nonce);
 		if (likely(nonce_work))
 		if (likely(nonce_work))
 		{
 		{
 			if (nonce_work == state->last2_work)
 			if (nonce_work == state->last2_work)
@@ -1004,7 +1040,7 @@ keepwaiting:
 		// Delay job start until later...
 		// Delay job start until later...
 	}
 	}
 	else
 	else
-	if (unlikely(icarus->deven != DEV_ENABLED || !icarus_job_start(thr)))
+	if (unlikely(icarus->deven != DEV_ENABLED || !info->job_start_func(thr)))
 		state->firstrun = true;
 		state->firstrun = true;
 
 
 	if (info->reopen_mode == IRM_CYCLE && !icarus_reopen(icarus, state, &fd))
 	if (info->reopen_mode == IRM_CYCLE && !icarus_reopen(icarus, state, &fd))
@@ -1329,6 +1365,7 @@ struct device_drv icarus_drv = {
 	.thread_prepare = icarus_prepare,
 	.thread_prepare = icarus_prepare,
 	.thread_init = icarus_init,
 	.thread_init = icarus_init,
 	.scanhash = icarus_scanhash,
 	.scanhash = icarus_scanhash,
+	.job_prepare = icarus_job_prepare,
 	.thread_disable = close_device_fd,
 	.thread_disable = close_device_fd,
 	.thread_shutdown = icarus_shutdown,
 	.thread_shutdown = icarus_shutdown,
 };
 };

+ 712 - 0
gc3355.c

@@ -0,0 +1,712 @@
+/*
+ * Copyright 2014 Nate Woolls
+ * Copyright 2014 Dualminer Team
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "gc3355.h"
+
+#include <string.h>
+#include "miner.h"
+#include "icarus-common.h"
+#include "logging.h"
+
+#ifndef WIN32
+  #include <sys/ioctl.h>
+#else
+  #include <io.h>
+#endif
+
+#define DEFAULT_DELAY_TIME 2000
+
+#define HUBFANS_0_9V_sha2 "60"
+#define HUBFANS_1_2V_sha2 "0"
+#define DEFAULT_0_9V_sha2 "60"
+#define DEFAULT_1_2V_sha2 "0"
+
+static
+const char *pll_freq_1200M_cmd[] =
+{
+	"55AAEF000500E085",
+	"55AA0FFFB02800C0",
+	"",
+};
+
+static
+const char *pll_freq_1100M_cmd[] =
+{
+	"55AAEF0005006085",
+	"55AA0FFF4C2500C0",
+	"",
+};
+
+static
+const char *pll_freq_1000M_cmd[] =
+{
+	"55AAEF000500E084",
+	"55AA0FFFE82100C0",
+	"",
+};
+
+static
+const char *pll_freq_950M_cmd[] =
+{
+	"55AAEF000500A084",
+	"55AA0FFF362000C0",
+	"",
+};
+
+static
+const char *pll_freq_900M_cmd[] =
+{
+	"55AAEF0005006084",
+	"55AA0FFF841E00C0",
+	"",
+};
+
+static
+const char *pll_freq_850M_cmd[] =
+{
+	"55AAEF0005002084",
+	"55AA0FFFD21C00C0",
+	"",
+};
+
+static
+const char *pll_freq_800M_cmd[] =
+{
+	"55AAEF000500E083",
+	"55AA0FFF201B00C0",
+	"",
+};
+
+static
+const char *pll_freq_750M_cmd[] =
+{
+	"55AAEF000500A083",
+	"55AA0FFF6E1900C0",
+	"",
+};
+
+static
+const char *pll_freq_700M_cmd[] =
+{
+	"55AAEF0005006083",
+	"55AA0FFFBC1700C0",
+	"",
+};
+
+static
+const char *pll_freq_650M_cmd[] =
+{
+	"55AAEF0005002083",
+	"55AA0FFF0A1600C0",
+	"",
+};
+
+static
+const char *pll_freq_600M_cmd[] =
+{
+	"55AAEF000500E082",
+	"55AA0FFF581400C0",
+	"",
+};
+
+static
+const char *pll_freq_550M_cmd[] =
+{
+	"55AAEF000500A082",
+	"55AA0FFFA61200C0",
+	"",
+};
+
+static
+const char *pll_freq_500M_cmd[] =
+{
+	"55AAEF0005006082",
+	"55AA0FFFF41000C0",
+	"",
+};
+
+static
+const char *pll_freq_400M_cmd[] =
+{
+	"55AAEF000500E081",
+	"55AA0FFF900D00C0",
+	"",
+};
+
+static
+const char *sha2_gating[] =
+{
+	"55AAEF0200000000",
+	"55AAEF0300000000",
+	"55AAEF0400000000",
+	"55AAEF0500000000",
+	"55AAEF0600000000",
+	"",
+};
+
+static
+const char *sha2_single_open[] =
+{
+	"55AAEF0200000001",
+	"55AAEF0200000003",
+	"55AAEF0200000007",
+	"55AAEF020000000F",
+	"55AAEF020000001F",
+	"55AAEF020000003F",
+	"55AAEF020000007F",
+	"55AAEF02000000FF",
+	"55AAEF02000001FF",
+	"55AAEF02000003FF",
+	"55AAEF02000007FF",
+	"55AAEF0200000FFF",
+	"55AAEF0200001FFF",
+	"55AAEF0200003FFF",
+	"55AAEF0200007FFF",
+	"55AAEF020000FFFF",
+	"55AAEF020001FFFF",
+	"55AAEF020003FFFF",
+	"55AAEF020007FFFF",
+	"55AAEF02000FFFFF",
+	"55AAEF02001FFFFF",
+	"55AAEF02003FFFFF",
+	"55AAEF02007FFFFF",
+	"55AAEF0200FFFFFF",
+	"55AAEF0201FFFFFF",
+	"55AAEF0203FFFFFF",
+	"55AAEF0207FFFFFF",
+	"55AAEF020FFFFFFF",
+	"55AAEF021FFFFFFF",
+	"55AAEF023FFFFFFF",
+	"55AAEF027FFFFFFF",
+	"55AAEF02FFFFFFFF",
+	"55AAEF0300000001",
+	"55AAEF0300000003",
+	"55AAEF0300000007",
+	"55AAEF030000000F",
+	"55AAEF030000001F",
+	"55AAEF030000003F",
+	"55AAEF030000007F",
+	"55AAEF03000000FF",
+	"55AAEF03000001FF",
+	"55AAEF03000003FF",
+	"55AAEF03000007FF",
+	"55AAEF0300000FFF",
+	"55AAEF0300001FFF",
+	"55AAEF0300003FFF",
+	"55AAEF0300007FFF",
+	"55AAEF030000FFFF",
+	"55AAEF030001FFFF",
+	"55AAEF030003FFFF",
+	"55AAEF030007FFFF",
+	"55AAEF03000FFFFF",
+	"55AAEF03001FFFFF",
+	"55AAEF03003FFFFF",
+	"55AAEF03007FFFFF",
+	"55AAEF0300FFFFFF",
+	"55AAEF0301FFFFFF",
+	"55AAEF0303FFFFFF",
+	"55AAEF0307FFFFFF",
+	"55AAEF030FFFFFFF",
+	"55AAEF031FFFFFFF",
+	"55AAEF033FFFFFFF",
+	"55AAEF037FFFFFFF",
+	"55AAEF03FFFFFFFF",
+	"55AAEF0400000001",
+	"55AAEF0400000003",
+	"55AAEF0400000007",
+	"55AAEF040000000F",
+	"55AAEF040000001F",
+	"55AAEF040000003F",
+	"55AAEF040000007F",
+	"55AAEF04000000FF",
+	"55AAEF04000001FF",
+	"55AAEF04000003FF",
+	"55AAEF04000007FF",
+	"55AAEF0400000FFF",
+	"55AAEF0400001FFF",
+	"55AAEF0400003FFF",
+	"55AAEF0400007FFF",
+	"55AAEF040000FFFF",
+	"55AAEF040001FFFF",
+	"55AAEF040003FFFF",
+	"55AAEF040007FFFF",
+	"55AAEF04000FFFFF",
+	"55AAEF04001FFFFF",
+	"55AAEF04003FFFFF",
+	"55AAEF04007FFFFF",
+	"55AAEF0400FFFFFF",
+	"55AAEF0401FFFFFF",
+	"55AAEF0403FFFFFF",
+	"55AAEF0407FFFFFF",
+	"55AAEF040FFFFFFF",
+	"55AAEF041FFFFFFF",
+	"55AAEF043FFFFFFF",
+	"55AAEF047FFFFFFF",
+	"55AAEF04FFFFFFFF",
+	"55AAEF0500000001",
+	"55AAEF0500000003",
+	"55AAEF0500000007",
+	"55AAEF050000000F",
+	"55AAEF050000001F",
+	"55AAEF050000003F",
+	"55AAEF050000007F",
+	"55AAEF05000000FF",
+	"55AAEF05000001FF",
+	"55AAEF05000003FF",
+	"55AAEF05000007FF",
+	"55AAEF0500000FFF",
+	"55AAEF0500001FFF",
+	"55AAEF0500003FFF",
+	"55AAEF0500007FFF",
+	"55AAEF050000FFFF",
+	"55AAEF050001FFFF",
+	"55AAEF050003FFFF",
+	"55AAEF050007FFFF",
+	"55AAEF05000FFFFF",
+	"55AAEF05001FFFFF",
+	"55AAEF05003FFFFF",
+	"55AAEF05007FFFFF",
+	"55AAEF0500FFFFFF",
+	"55AAEF0501FFFFFF",
+	"55AAEF0503FFFFFF",
+	"55AAEF0507FFFFFF",
+	"55AAEF050FFFFFFF",
+	"55AAEF051FFFFFFF",
+	"55AAEF053FFFFFFF",
+	"55AAEF057FFFFFFF",
+	"55AAEF05FFFFFFFF",
+	"55AAEF0600000001",
+	"55AAEF0600000003",
+	"55AAEF0600000007",
+	"55AAEF060000000F",
+	"55AAEF060000001F",
+	"55AAEF060000003F",
+	"55AAEF060000007F",
+	"55AAEF06000000FF",
+	"55AAEF06000001FF",
+	"55AAEF06000003FF",
+	"55AAEF06000007FF",
+	"55AAEF0600000FFF",
+	"55AAEF0600001FFF",
+	"55AAEF0600003FFF",
+	"55AAEF0600007FFF",
+	"55AAEF060000FFFF",
+	"55AAEF060001FFFF",
+	"55AAEF060003FFFF",
+	"55AAEF060007FFFF",
+	"55AAEF06000FFFFF",
+	"55AAEF06001FFFFF",
+	"55AAEF06003FFFFF",
+	"55AAEF06007FFFFF",
+	"55AAEF0600FFFFFF",
+	"55AAEF0601FFFFFF",
+	"55AAEF0603FFFFFF",
+	"55AAEF0607FFFFFF",
+	"55AAEF060FFFFFFF",
+	"55AAEF061FFFFFFF",
+	"55AAEF063FFFFFFF",
+	"55AAEF067FFFFFFF",
+	"55AAEF06FFFFFFFF",
+	"",
+};
+
+static
+const char *scrypt_only_init[] =
+{
+	"55AAEF0200000000",
+	"55AAEF0300000000",
+	"55AAEF0400000000",
+	"55AAEF0500000000",
+	"55AAEF0600000000",
+	"55AAEF3040000000",
+	"55AA1F2810000000",
+	"55AA1F2813000000",
+	"",
+};
+
+char *opt_dualminer_sha2_gating = NULL;
+int opt_pll_freq = 0; // default is set in gc3355_pll_freq_init2
+int opt_sha2_number = 160;
+bool opt_hubfans = false;
+bool opt_dual_mode = false;
+
+void gc3355_dual_reset(int fd)
+{
+#ifdef WIN32
+	DCB dcb;
+
+	memset(&dcb, 0, sizeof(DCB));
+	GetCommState(_get_osfhandle(fd), &dcb);
+	dcb.fDtrControl = DTR_CONTROL_ENABLE;
+	SetCommState(_get_osfhandle(fd), &dcb);
+	Sleep(1);
+	GetCommState(_get_osfhandle(fd), &dcb);
+	dcb.fDtrControl = DTR_CONTROL_DISABLE;
+	SetCommState(_get_osfhandle(fd), &dcb);
+
+#else
+
+	int dtr_flag = 0;
+	ioctl(fd, TIOCMGET, &dtr_flag);
+	dtr_flag |= TIOCM_DTR;
+	ioctl(fd, TIOCMSET, &dtr_flag);
+	usleep(1000);
+	ioctl(fd, TIOCMGET, &dtr_flag);
+	dtr_flag &= ~TIOCM_DTR;
+	ioctl(fd, TIOCMSET, &dtr_flag);
+
+#endif
+
+}
+
+static
+void gc3355_send_cmds(int fd, const char *cmds[])
+{
+	int i = 0;
+	unsigned char ob_bin[32];
+	for(i = 0 ;; i++)
+	{
+		memset(ob_bin, 0, sizeof(ob_bin));
+
+		if (cmds[i][0] == 0)
+			break;
+
+		hex2bin(ob_bin, cmds[i], strlen(cmds[i]) / 2);
+		icarus_write(fd, ob_bin, 8);
+		usleep(DEFAULT_DELAY_TIME);
+	}
+}
+
+void gc3355_opt_scrypt_init(int fd)
+{
+	const char *initscrypt_ob[] =
+	{
+		"55AA1F2810000000",
+		"55AA1F2813000000",
+		""
+	};
+
+	gc3355_send_cmds(fd, initscrypt_ob);
+}
+
+int gc3355_get_cts_status(int fd)
+{
+	int ret;
+	int status = 0;
+#ifdef WIN32
+	GetCommModemStatus(_get_osfhandle(fd), &status);
+	applog(LOG_DEBUG, "Get CTS Status is : %d [Windows: 0 is 1.2; 16 is 0.9]\n", status);
+	ret = (status == 0) ? 1 : 0;
+	return ret;
+#else
+	ioctl(fd, TIOCMGET, &status);
+	ret = (status & 0x20) ? 0 : 1;
+	applog(LOG_DEBUG, "Get CTS Status is : %d [Linux: 1 is 1.2; 0 is 0.9]\n", ret);
+	return ret;
+#endif
+}
+
+void gc3355_set_rts_status(int fd, unsigned int value)
+{
+#ifdef WIN32
+	DCB dcb;
+	memset(&dcb, 0, sizeof(DCB));
+	GetCommState(_get_osfhandle(fd), &dcb);
+	if (value != 0)
+		dcb.fRtsControl = RTS_CONTROL_ENABLE;
+	else
+		dcb.fRtsControl = RTS_CONTROL_DISABLE;
+	SetCommState(_get_osfhandle(fd), &dcb);
+#else
+	int rts_flag = 0;
+	ioctl(fd, TIOCMGET, &rts_flag);
+	if (value != 0)
+		rts_flag |= TIOCM_RTS;
+	else
+		rts_flag &= ~TIOCM_RTS;
+	ioctl(fd, TIOCMSET, &rts_flag);
+#endif
+}
+
+static
+void gc3355_pll_freq_init2(int fd, int pll_freq)
+{
+	switch(pll_freq)
+	{
+		case 400:
+		{
+			gc3355_send_cmds(fd, pll_freq_400M_cmd);
+			break;
+		}
+		case 500:
+		{
+			gc3355_send_cmds(fd, pll_freq_500M_cmd);
+			break;
+		}
+		case 550:
+		{
+			gc3355_send_cmds(fd, pll_freq_550M_cmd);
+			break;
+		}
+		case 600:
+		{
+			gc3355_send_cmds(fd, pll_freq_600M_cmd);
+			break;
+		}
+		case 650:
+		{
+			gc3355_send_cmds(fd, pll_freq_650M_cmd);
+			break;
+		}
+		case 700:
+		{
+			gc3355_send_cmds(fd, pll_freq_700M_cmd);
+			break;
+		}
+		case 750:
+		{
+			gc3355_send_cmds(fd, pll_freq_750M_cmd);
+			break;
+		}
+		case 800:
+		{
+			gc3355_send_cmds(fd, pll_freq_800M_cmd);
+			break;
+		}
+		case 850:
+		{
+			gc3355_send_cmds(fd, pll_freq_850M_cmd);
+			break;
+		}
+		case 900:
+		{
+			gc3355_send_cmds(fd, pll_freq_900M_cmd);
+			break;
+		}
+		case 950:
+		{
+			gc3355_send_cmds(fd, pll_freq_950M_cmd);
+			break;
+		}
+		case 1000:
+		{
+			gc3355_send_cmds(fd, pll_freq_1000M_cmd);
+			break;
+		}
+		case 1100:
+		{
+			gc3355_send_cmds(fd, pll_freq_1100M_cmd);
+			break;
+		}
+		case 1200:
+		{
+			gc3355_send_cmds(fd, pll_freq_1200M_cmd);
+			break;
+		}
+		default:
+		{
+			if (gc3355_get_cts_status(fd) == 1)
+				//1.2v - Scrypt mode
+				gc3355_send_cmds(fd, pll_freq_850M_cmd);
+			else
+				//0.9v - Scrypt + SHA mode
+				gc3355_send_cmds(fd, pll_freq_550M_cmd);
+		}
+	}
+}
+
+
+void gc3355_open_sha2_unit(int fd, char *opt_sha2_gating)
+{
+	unsigned char ob_bin[8];
+	int i;
+
+	//---sha2 unit---
+	char sha2_gating[5][17] =
+	{
+		"55AAEF0200000000",
+		"55AAEF0300000000",
+		"55AAEF0400000000",
+		"55AAEF0500000000",
+		"55AAEF0600000000",
+	};
+	union
+	{
+	    unsigned int i32[5];
+	    unsigned char c8[20] ;
+	}sha2_group;
+
+	int sha2_number=0;
+	if (opt_sha2_gating== NULL)
+	    sha2_number = 70;
+	else
+	{
+	    if (atoi(opt_sha2_gating) <= 160 && atoi(opt_sha2_gating) >= 0)
+			sha2_number = atoi(opt_sha2_gating);
+		else
+			sha2_number = 70;
+	}
+
+	for(i = 0; i < 5; i++)
+		sha2_group.i32[i] = 0;
+
+	for(i = 0; i < sha2_number; i++)
+		sha2_group.i32[i / 32] += 1 << ( i % 32);
+
+	for(i = 0; i < 20; i++)
+		sprintf(&sha2_gating[i / 4][8 + (i % 4) * 2], "%02x", sha2_group.c8[i]);
+	//---sha2 unit end---
+
+	for(i = 0; i < 5; i++)
+	{
+		if (sha2_gating[i][0] == '\0')
+			break;
+
+		hex2bin(ob_bin, sha2_gating[i], sizeof(ob_bin));
+		icarus_write(fd, ob_bin, 8);
+		usleep(DEFAULT_DELAY_TIME);
+	}
+
+	opt_sha2_number = sha2_number;
+}
+
+static
+void gc3355_open_sha2_unit_one_by_one(int fd, char *opt_sha2_gating)
+{
+	int unit_count = 0;
+	unsigned char ob_bin[8];
+	int i;
+
+	unit_count = atoi(opt_sha2_gating);
+
+	if (unit_count < 0)
+		unit_count = 0;
+	if (unit_count > 160)
+		unit_count = 160;
+
+	if (unit_count > 0 && unit_count <= 160)
+	{
+		for(i = 0; i <= unit_count; i++)
+		{
+			hex2bin(ob_bin, sha2_single_open[i], sizeof(ob_bin));
+			icarus_write(fd, ob_bin, 8);
+			usleep(DEFAULT_DELAY_TIME * 2);
+		}
+		opt_sha2_number = unit_count;
+	}
+	else if (unit_count == 0)
+		gc3355_send_cmds(fd, sha2_gating);
+}
+
+void gc3355_opt_scrypt_only_init(int fd)
+{
+	gc3355_send_cmds(fd, scrypt_only_init);
+
+	gc3355_pll_freq_init2(fd, opt_pll_freq);
+}
+
+
+void gc3355_open_scrypt_unit(int fd, int status)
+{
+	const char *scrypt_only_ob[] =
+	{
+		"55AA1F2810000000",
+		"",
+	};
+
+	const char *scrypt_ob[] =
+	{
+		"55AA1F2814000000",
+		"",
+	};
+
+	if (status == SCRYPT_UNIT_OPEN)
+	{
+		if (opt_dual_mode)
+			gc3355_opt_scrypt_init(fd);
+		else
+			gc3355_opt_scrypt_only_init(fd);
+	}
+	else
+	{
+		if (opt_dual_mode)
+			gc3355_send_cmds(fd, scrypt_ob);
+		else
+			gc3355_send_cmds(fd, scrypt_only_ob);
+	}
+}
+
+void gc3355_dualminer_init(int fd)
+{
+
+	const char *init_ob[] =
+	{
+#if 1
+		"55AAEF0200000000",
+		"55AAEF0300000000",
+		"55AAEF0400000000",
+		"55AAEF0500000000",
+		"55AAEF0600000000",
+#endif
+		"55AAEF3020000000",
+		"55AA1F2817000000",
+		""
+	};
+	const char *initscrypt_ob[] =
+	{
+		"55AA1F2814000000",
+		"55AA1F2817000000",
+		""
+	};
+
+	if (opt_scrypt)
+		gc3355_send_cmds(fd, initscrypt_ob);
+	else
+		gc3355_send_cmds(fd, init_ob);
+
+	if (!opt_scrypt)
+		gc3355_pll_freq_init2(fd, opt_pll_freq);
+}
+
+void gc3355_init(int fd, char *sha2_unit, bool is_scrypt_only)
+{
+	if (gc3355_get_cts_status(fd) == 1)
+	{
+		//1.2v - Scrypt mode
+		if (opt_scrypt)
+		{
+			if (is_scrypt_only)
+				gc3355_opt_scrypt_only_init(fd);
+		}
+		else
+		{
+			if (opt_hubfans)
+				((sha2_unit == NULL) ? gc3355_open_sha2_unit_one_by_one(fd, HUBFANS_1_2V_sha2) : gc3355_open_sha2_unit_one_by_one(fd, sha2_unit));
+			else
+				((sha2_unit == NULL) ? gc3355_open_sha2_unit_one_by_one(fd, DEFAULT_1_2V_sha2) : gc3355_open_sha2_unit_one_by_one(fd, sha2_unit));
+		}
+	}
+	else
+	{
+		//0.9v - Scrypt + SHA mode
+		if (opt_scrypt)
+		{
+			if (is_scrypt_only)
+				gc3355_opt_scrypt_only_init(fd);
+		}
+		else
+		{
+			if (opt_hubfans)
+				((sha2_unit == NULL) ? gc3355_open_sha2_unit_one_by_one(fd, HUBFANS_0_9V_sha2) : gc3355_open_sha2_unit_one_by_one(fd, sha2_unit));
+			else
+				((sha2_unit == NULL) ? gc3355_open_sha2_unit_one_by_one(fd, DEFAULT_0_9V_sha2) : gc3355_open_sha2_unit_one_by_one(fd, sha2_unit));
+		}
+	}
+}

+ 66 - 0
gc3355.h

@@ -0,0 +1,66 @@
+/*
+ * Copyright 2014 Nate Woolls
+ * Copyright 2014 Dualminer Team
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#ifndef bfgminer_gc3355_h
+#define bfgminer_gc3355_h
+
+#include <stdbool.h>
+
+#define SCRYPT_UNIT_OPEN  0
+#define SCRYPT_UNIT_CLOSE 1
+
+extern
+char *opt_dualminer_sha2_gating;
+
+extern
+int opt_pll_freq;
+
+//once this is made an option, needs to be >= 0 and <= 160
+//already enforced in gc3355 but no stdout yet
+extern
+int opt_sha2_number;
+
+//mining both Scrypt & SHA2 at the same time with two processes
+//SHA2 process must be run first, no arg requirements, first serial port will be used
+//Scrypt process must be launched after, --scrypt and --dual-mode args required
+extern
+bool opt_dual_mode;
+
+extern
+bool opt_hubfans;
+
+extern
+void gc3355_dual_reset(int fd);
+
+extern
+void gc3355_opt_scrypt_only_init(int fd);
+
+extern
+void gc3355_dualminer_init(int fd);
+
+extern
+void gc3355_opt_scrypt_init(int fd);
+
+extern
+void gc3355_init(int fd, char *sha2_unit, bool is_scrypt_only);
+
+extern
+void gc3355_open_sha2_unit(int fd, char *opt_sha2_gating);
+
+extern
+void gc3355_open_scrypt_unit(int fd, int status);
+
+extern
+int gc3355_get_cts_status(int fd);
+
+extern
+void gc3355_set_rts_status(int fd, unsigned int value);
+
+#endif

+ 13 - 1
icarus-common.h

@@ -109,6 +109,15 @@ struct ICARUS_INFO {
 	
 	
 	// Bytes to read from Icarus for nonce
 	// Bytes to read from Icarus for nonce
 	int read_size;
 	int read_size;
+	
+	size_t ob_size;
+	const char *golden_ob;
+	const char *golden_nonce;
+	bool nonce_littleendian;
+	
+	// Custom driver functions
+	bool (*detect_init_func)(const char *devpath, int fd, struct ICARUS_INFO *);
+	bool (*job_start_func)(struct thr_info *);
 };
 };
 
 
 struct icarus_state {
 struct icarus_state {
@@ -120,11 +129,14 @@ struct icarus_state {
 	bool changework;
 	bool changework;
 	bool identify;
 	bool identify;
 	
 	
-	uint8_t ob_bin[64];
+	uint8_t *ob_bin;
 };
 };
 
 
 bool icarus_detect_custom(const char *devpath, struct device_drv *, struct ICARUS_INFO *);
 bool icarus_detect_custom(const char *devpath, struct device_drv *, struct ICARUS_INFO *);
 extern int icarus_gets(unsigned char *, int fd, struct timeval *tv_finish, struct thr_info *, int read_count, int read_size);
 extern int icarus_gets(unsigned char *, int fd, struct timeval *tv_finish, struct thr_info *, int read_count, int read_size);
 extern int icarus_write(int fd, const void *buf, size_t bufLen);
 extern int icarus_write(int fd, const void *buf, size_t bufLen);
+extern bool icarus_init(struct thr_info *);
+extern void do_icarus_close(struct thr_info *thr);
+extern bool icarus_job_start(struct thr_info *);
 
 
 #endif
 #endif

+ 7 - 11
miner.c

@@ -10515,15 +10515,12 @@ rescan:
 	bfg_need_detect_rescan = false;
 	bfg_need_detect_rescan = false;
 	
 	
 #ifdef HAVE_BFG_LOWLEVEL
 #ifdef HAVE_BFG_LOWLEVEL
-	if (!opt_scrypt)
-	{
-		struct lowlevel_device_info * const infolist = lowlevel_scan(), *info, *infotmp;
-		
-		LL_FOREACH_SAFE(infolist, info, infotmp)
-			probe_device(info);
-		LL_FOREACH_SAFE(infolist, info, infotmp)
-			pthread_join(info->probe_pth, NULL);
-	}
+	struct lowlevel_device_info * const infolist = lowlevel_scan(), *info, *infotmp;
+	
+	LL_FOREACH_SAFE(infolist, info, infotmp)
+		probe_device(info);
+	LL_FOREACH_SAFE(infolist, info, infotmp)
+		pthread_join(info->probe_pth, NULL);
 #endif
 #endif
 	
 	
 	struct driver_registration *reg, *tmp;
 	struct driver_registration *reg, *tmp;
@@ -10538,8 +10535,7 @@ rescan:
 	}
 	}
 
 
 #ifdef HAVE_BFG_LOWLEVEL
 #ifdef HAVE_BFG_LOWLEVEL
-	if (!opt_scrypt)
-		lowlevel_scan_free();
+	lowlevel_scan_free();
 #endif
 #endif
 	
 	
 	if (bfg_need_detect_rescan)
 	if (bfg_need_detect_rescan)