Browse Source

dualminer: Support for mining both Scrypt and SHA2 using DualMiner GC3355 thumb sticks

Set clock frequency using --set-device dualminer:clock=frequency (default is 850 in Scrypt mode)
Mine Scrypt2 and SHA2 simultaneously with two miner processes using --dual-mode (SHA2 process must be launched first)
Nate Woolls 12 years ago
parent
commit
f0aff42709
6 changed files with 1125 additions and 0 deletions
  1. 1 0
      AUTHORS
  2. 4 0
      Makefile.am
  3. 14 0
      configure.ac
  4. 325 0
      driver-dualminer.c
  5. 715 0
      gc3355.c
  6. 66 0
      gc3355.h

+ 1 - 0
AUTHORS

@@ -1,6 +1,7 @@
 FPGA/ASIC mining and refactor: Luke Dashjr <luke-jr+bfgminer@utopios.org> 1QATWksNFGeUJCWBrN4g6hGM178Lovm7Wh
 GPU mining and refactor: Con Kolivas <kernel@kolivas.org> 15qSxP1SQcUX3o4nhkfdbgyoWEFMomJ4rZ
 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>
 Big Picture Mining and TwinFury drivers: Andreas Auer <aauer1@gmail.com>
 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
 endif
 
+if USE_DUALMINER
+bfgminer_SOURCES += driver-dualminer.c gc3355.c gc3355.h
+endif
+
 if HAS_AVALON
 bfgminer_SOURCES += driver-avalon.c driver-avalon.h hexdump.c
 endif

+ 14 - 0
configure.ac

@@ -430,6 +430,20 @@ if test "x$icarus" = xyes; then
 fi
 AM_CONDITIONAL([HAS_ICARUS], [test x$icarus = xyes])
 
+driverlist="$driverlist dualminer"
+dualminer=yes
+AC_ARG_ENABLE([dualminer],
+	[AC_HELP_STRING([--disable-dualminer],[Compile support for DualMiner (default enabled)])],
+	[dualminer=$enableval]
+	)
+if test "x$dualminer" = "xyes"; then
+	if test "x$icarus" = "xno"; then
+		AC_MSG_ERROR([You explicitly disabled Icarus and explicitly enabled DualMiner])
+	fi
+	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"
 avalon="no"
 

+ 325 - 0
driver-dualminer.c

@@ -0,0 +1,325 @@
+/*
+ * 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
+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;
+	}
+
+	if (opt_scrypt)
+		icarus->min_nonce_diff = 1./0x10000;
+
+	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_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,
+};

+ 715 - 0
gc3355.c

@@ -0,0 +1,715 @@
+/*
+ * 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[32];
+	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++)
+	{
+		memset(ob_bin, 0, sizeof(ob_bin));
+
+		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[32];
+	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++)
+		{
+			memset(ob_bin, 0, sizeof(ob_bin));
+			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