Browse Source

Merge branch 'gridseed' into bfgminer

Conflicts:
	README
	driver-nanofury.c
Luke Dashjr 11 years ago
parent
commit
39461ee7a9
15 changed files with 1040 additions and 359 deletions
  1. 1 0
      AUTHORS
  2. 9 1
      Makefile.am
  3. 4 2
      README
  4. 29 12
      configure.ac
  5. 1 1
      driver-avalon.h
  6. 70 67
      driver-dualminer.c
  7. 452 0
      driver-gridseed.c
  8. 11 11
      driver-nanofury.c
  9. 392 198
      gc3355.c
  10. 30 29
      gc3355.h
  11. 20 20
      lowl-vcom.c
  12. 4 3
      lowl-vcom.h
  13. 7 7
      mcp2210.c
  14. 2 8
      mcp2210.h
  15. 8 0
      util.h

+ 1 - 0
AUTHORS

@@ -2,6 +2,7 @@ FPGA/ASIC mining and refactor: Luke Dashjr <luke-jr+bfgminer@utopios.org> 1QATWk
 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>
+GridSeed driver: Nate Woolls <nwoolls@gmail.com> and GridSeed Team <develop@gridseed.com>
 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>

+ 9 - 1
Makefile.am

@@ -239,8 +239,16 @@ bfgminer_SOURCES += driver-erupter.c
 bfgminer_SOURCES += driver-antminer.c
 endif
 
+if USE_GC3355
+bfgminer_SOURCES += gc3355.c gc3355.h
+endif
+
+if USE_GRIDSEED
+bfgminer_SOURCES += driver-gridseed.c
+endif
+
 if USE_DUALMINER
-bfgminer_SOURCES += driver-dualminer.c gc3355.c gc3355.h
+bfgminer_SOURCES += driver-dualminer.c
 endif
 
 if HAS_AVALON

+ 4 - 2
README

@@ -147,6 +147,8 @@ BFGMiner driver configuration options:
 	--enable-cpumining      Build with CPU mining support (default disabled)
 	--disable-drillbit      Compile support for DrillBit (default enabled)
 	--disable-dualminer     Compile support for DualMiner (default enabled)
+	--disable-gridseed      Compile support for GridSeed (default enabled with
+	                        scrypt)
 	--disable-hashbuster    Compile support for HashBuster Nano (default
 	                        enabled)
 	--disable-hashbusterusb Compile support for HashBuster Micro (default if
@@ -851,8 +853,8 @@ To permanently give your account the 'video' group:
 Then logout and back in again.
 
 Q: Can I mine scrypt with FPGAs or ASICs?
-A: BFGMiner supports scrypt mining using DualMiner USB sticks, based on the
-Gridseed GC3355 ASIC.
+A: BFGMiner supports scrypt mining with GridSeed GC3355 ASICs, using either
+DualMiner USB sticks or the 5-chip orb.
 
 Q: Why does BFGMiner show a fractional difficulty when mining scrypt?
 A: BFGMiner consistently uses pdiff measurement for difficulty everywhere,

+ 29 - 12
configure.ac

@@ -122,6 +122,7 @@ has_fpga=no
 has_asic=no
 need_binloader=no
 need_dynclock=no
+need_gc3355=no
 need_lowl_vcom=no
 need_lowlevel=no
 need_lowl_ftdi=no
@@ -238,6 +239,16 @@ AC_ARG_ENABLE([other-drivers],
 )
 
 
+algolist="$algolist scrypt"
+AC_ARG_ENABLE([scrypt],
+	[AC_HELP_STRING([--enable-scrypt],[Compile support for scrypt mining (default disabled)])],
+	[scrypt=$enableval],
+	[scrypt=no])
+if test "x$scrypt" = xyes; then
+	AC_DEFINE([USE_SCRYPT], [1], [Defined to 1 if scrypt support is wanted])
+fi
+
+
 lowl_pci=no
 if test "x$ac_cv_header_sys_mman_h" = "xyes"; then
 	AC_ARG_WITH([uio],
@@ -463,9 +474,26 @@ else
 fi
 if test "x$dualminer" = "xyes"; then
 	AC_DEFINE([USE_DUALMINER], [1], [Defined to 1 if DualMiner support is wanted])
+	need_gc3355=yes
 fi
 AM_CONDITIONAL([USE_DUALMINER], [test x$dualminer = xyes])
 
+driverlist="$driverlist gridseed"
+AC_ARG_ENABLE([gridseed],
+	[AC_HELP_STRING([--disable-gridseed],[Compile support for GridSeed (default enabled with scrypt)])],
+	[gridseed=$enableval],
+	[gridseed=$scrypt])
+if test "x$gridseed" = "xyes"; then
+	if test "x$scrypt" = "xno"; then
+		AC_MSG_ERROR([You explicitly enabled GridSeed, but did not enable scrypt (SHA2 not supported)])
+	fi
+	AC_DEFINE([USE_GRIDSEED], [1], [Defined to 1 if GridSeed support is wanted])
+	need_gc3355=yes
+	need_lowl_vcom=yes
+	has_asic=yes
+fi
+AM_CONDITIONAL([USE_GRIDSEED], [test x$gridseed = xyes])
+
 driverlist="$driverlist avalon"
 avalon="no"
 
@@ -1038,18 +1066,6 @@ if test "x$libusb" = xyes; then
 fi
 
 
-algolist="$algolist scrypt"
-scrypt="no"
-
-AC_ARG_ENABLE([scrypt],
-	[AC_HELP_STRING([--enable-scrypt],[Compile support for scrypt mining (default disabled)])],
-	[scrypt=$enableval]
-	)
-if test "x$scrypt" = xyes; then
-	AC_DEFINE([USE_SCRYPT], [1], [Defined to 1 if scrypt support is wanted])
-fi
-
-
 if test x$need_lowl_vcom = xyes; then
 	AC_DEFINE([NEED_BFG_LOWL_VCOM], [1], [Defined to 1 if lowlevel VCOM drivers are being used])
 	need_lowlevel=yes
@@ -1304,6 +1320,7 @@ fi
 AM_CONDITIONAL([NEED_LIBBLKMAKER], [test x$with_system_libblkmaker != xyes])
 AM_CONDITIONAL([NEED_BFG_BINLOADER], [test x$need_binloader = xyes])
 AM_CONDITIONAL([NEED_DYNCLOCK], [test x$need_dynclock = xyes])
+AM_CONDITIONAL([USE_GC3355], [test x$need_gc3355 = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_VCOM], [test x$need_lowl_vcom = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_FTDI], [test x$need_lowl_ftdi = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWL_HID], [test x$need_lowl_hid = xyes])

+ 1 - 1
driver-avalon.h

@@ -128,7 +128,7 @@ struct avalon_info {
 #define avalon_open(devpath, baud)  avalon_open2(devpath, baud, true)
 #define avalon_close(fd) close(fd)
 
-#define avalon_buffer_full(fd)	get_serial_cts(fd)
+#define avalon_buffer_full(fd)	(get_serial_cts(fd) != BGV_LOW)
 
 #define AVALON_READ_TIME(baud) ((double)AVALON_READ_SIZE * (double)8.0 / (double)(baud))
 #define ASSERT1(condition) __maybe_unused static char sizeof_uint32_t_must_be_4[(condition)?1:-1]

+ 70 - 67
driver-dualminer.c

@@ -33,15 +33,26 @@
   #include <io.h>
 #endif
 
+// 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
+bool opt_dual_mode = false;
+
 #define DUALMINER_IO_SPEED 115200
 
-#define DUALMINER_SCRYPT_HASH_TIME		0.00001428571429
+#define DUALMINER_SCRYPT_SM_HASH_TIME   0.00001428571429
 #define DUALMINER_SCRYPT_DM_HASH_TIME	0.00003333333333
-#define DUALMINER_SHA2_HASH_TIME		0.00000000300000
+#define DUALMINER_SHA2_DM_HASH_TIME     0.00000000300000
 
 #define DUALMINER_SCRYPT_READ_COUNT 48  // 4.8s to read
 #define DUALMINER_SHA2_READ_COUNT	16  // 1.6s to read
 
+#define DUALMINER_0_9V_SHA2_UNITS  60
+#define DUALMINER_1_2V_SHA2_UNITS   0
+
+#define DUALMINER_DM_DEFAULT_FREQUENCY  550
+#define DUALMINER_SM_DEFAULT_FREQUENCY  850
+
 static
 const char sha2_golden_ob[] =
 	"55aa0f00a08701004a548fe471fa3a9a"
@@ -68,12 +79,6 @@ const char scrypt_golden_ob[] =
 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[];
@@ -81,27 +86,25 @@ const struct bfg_set_device_definition dualminer_set_device_funcs[];
 // device helper functions
 
 static
-void dualminer_bootstrap_device(int fd)
+void dualminer_teardown_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);
+	// set data terminal ready (DTR) status
+	set_serial_dtr(fd, BGV_HIGH);
+	// set request to send (RTS) status
+	set_serial_rts(fd, BGV_LOW);
 }
 
 static
-void dualminer_teardown_device(int fd)
+void dualminer_init_hashrate(struct cgpu_info * const cgpu)
 {
-	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);
+	int fd = cgpu->device_fd;
+	struct ICARUS_INFO *info = cgpu->device_data;
+
+	// get clear to send (CTS) status
+	if ((gc3355_get_cts_status(fd) != 1) &&  // 0.9v - dip-switch set to B
+		(opt_scrypt))
+		// adjust hash-rate for voltage
+		info->Hs = DUALMINER_SCRYPT_DM_HASH_TIME;
 }
 
 static
@@ -115,40 +118,62 @@ bool dualminer_init(struct thr_info * const thr)
 	return icarus_init(thr);
 }
 
+// runs when job starts and the device has been reset (or first run)
 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_usbstick(fd, opt_pll_freq, !opt_dual_mode, false);
+	
+	dualminer_init_hashrate(icarus);
 
-	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);
+	applog(LOG_DEBUG, "%"PRIpreprv": dualminer: Init: pll=%d, scrypt: %d, scrypt only: %d",
+		   icarus->proc_repr,
+		   opt_pll_freq,
+		   opt_scrypt,
+		   opt_scrypt && !opt_dual_mode);
+}
 
-	if (gc3355_get_cts_status(fd) != 1)
+// set defaults for options that the user didn't specify
+static
+void dualminer_set_defaults(int fd)
+{
+	// set opt_sha2_units defaults depending on dip-switch
+	if (opt_sha2_units == -1)
 	{
-		// Scrypt + SHA2 mode
-		if (opt_scrypt)
-			info->Hs = DUALMINER_SCRYPT_DM_HASH_TIME;
+		// get clear to send (CTS) status
+		if (gc3355_get_cts_status(fd) == 1)
+			opt_sha2_units = DUALMINER_1_2V_SHA2_UNITS;  // dip-switch in L position
+		else
+			opt_sha2_units = DUALMINER_0_9V_SHA2_UNITS;  // dip-switch in B position
+	}
+	
+	// set opt_pll_freq defaults depending on dip-switch
+	if (opt_pll_freq <= 0)
+	{
+		// get clear to send (CTS) status
+		if (gc3355_get_cts_status(fd) == 1)
+			opt_pll_freq = DUALMINER_SM_DEFAULT_FREQUENCY; // 1.2v - dip-switch in L position
+		else
+			opt_pll_freq = DUALMINER_DM_DEFAULT_FREQUENCY; // 0.9v - dip-switch in B position
 	}
-
-	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
 
+// runs after fd is opened but before the device detection code
 static
 bool dualminer_detect_init(const char *devpath, int fd, struct ICARUS_INFO * __maybe_unused info)
 {
-	dualminer_bootstrap_device(fd);
+	dualminer_set_defaults(fd);
+	
+	gc3355_init_usbstick(fd, opt_pll_freq, !opt_dual_mode, true);
 
 	return true;
 }
 
+// runs each time a job starts
 static
 bool dualminer_job_start(struct thr_info * const thr)
 {
@@ -157,14 +182,15 @@ bool dualminer_job_start(struct thr_info * const thr)
 	int fd = icarus->device_fd;
 
 	if (state->firstrun)
+		// runs when job starts and the device has been reset (or first run)
 		dualminer_init_firstrun(icarus);
 
 	if (opt_scrypt)
 	{
 		if (opt_dual_mode)
-			gc3355_dualminer_init(fd);
+			gc3355_scrypt_reset(fd);
 		else
-			gc3355_opt_scrypt_init(fd);
+			gc3355_scrypt_only_reset(fd);
 	}
 
 	return icarus_job_start(thr);
@@ -196,13 +222,13 @@ bool dualminer_detect_one(const char *devpath)
 	{
 		info->golden_ob = (char*)scrypt_golden_ob;
 		info->golden_nonce = (char*)scrypt_golden_nonce;
-		info->Hs = DUALMINER_SCRYPT_HASH_TIME;
+		info->Hs = DUALMINER_SCRYPT_SM_HASH_TIME;
 	}
 	else
 	{
 		info->golden_ob = (char*)sha2_golden_ob;
 		info->golden_nonce = (char*)sha2_golden_nonce;
-		info->Hs = DUALMINER_SHA2_HASH_TIME;
+		info->Hs = DUALMINER_SHA2_DM_HASH_TIME;
 	}
 
 	drv_set_defaults(drv, dualminer_set_device_funcs, info, devpath, detectone_meta_info.serial, 1);
@@ -267,32 +293,9 @@ bool dualminer_job_prepare(struct thr_info *thr, struct work *work, __maybe_unus
 	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;
-	}
+		gc3355_scrypt_prepare_work(state->ob_bin, work);
 	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);
-	}
+		gc3355_sha2_prepare_work(state->ob_bin, work, false);
 
 	return true;
 }

+ 452 - 0
driver-gridseed.c

@@ -0,0 +1,452 @@
+/*
+ * Copyright 2014 Luke Dashjr
+ * Copyright 2014 Nate Woolls
+ * Copyright 2014 GridSeed 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 "deviceapi.h"
+#include "lowlevel.h"
+#include "lowl-vcom.h"
+#include "gc3355.h"
+
+#define GRIDSEED_DEFAULT_FREQUENCY  600
+#define GRIDSEED_MAX_QUEUED          10
+
+BFG_REGISTER_DRIVER(gridseed_drv)
+
+/*
+ * helper functions
+ */
+
+static
+struct cgpu_info *gridseed_alloc_device(const char *path, struct device_drv *driver, struct gc3355_orb_info *info)
+{
+	struct cgpu_info *device = calloc(1, sizeof(struct cgpu_info));
+	if (unlikely(!device))
+		quit(1, "Failed to malloc cgpu_info");
+	
+	device->drv = driver;
+	device->device_path = strdup(path);
+	device->device_fd = -1;
+	device->threads = 1;
+	device->procs = GC3355_ORB_DEFAULT_CHIPS;
+	device->device_data = info;
+	
+	return device;
+}
+
+static
+struct gc3355_orb_info *gridseed_alloc_info()
+{
+	struct gc3355_orb_info *info = calloc(1, sizeof(struct gc3355_orb_info));
+	if (unlikely(!info))
+		quit(1, "Failed to malloc gc3355_orb_info");
+	
+	info->freq = GRIDSEED_DEFAULT_FREQUENCY;
+	
+	return info;
+}
+
+static
+void gridseed_empty_work(int fd)
+{
+	unsigned char buf[GC3355_READ_SIZE];
+	gc3355_read(fd, (char *)buf, GC3355_READ_SIZE);
+}
+
+/*
+ * device detection
+ */
+
+static
+bool gridseed_detect_custom(const char *path, struct device_drv *driver, struct gc3355_orb_info *info)
+{
+	int fd = gc3355_open(path);
+	if(fd < 0)
+		return false;
+	
+	gridseed_empty_work(fd);
+	
+	uint32_t fw_version = gc3355_get_firmware_version(fd);
+	
+	if (fw_version == -1)
+	{
+		applog(LOG_ERR, "%s: Invalid detect response from %s", gridseed_drv.dname, path);
+		gc3355_close(fd);
+		return false;
+	}
+	
+	struct cgpu_info *device = gridseed_alloc_device(path, driver, info);
+	
+	if (serial_claim_v(path, driver))
+		return false;
+	
+	if (!add_cgpu(device))
+		return false;
+	
+	device->device_fd = fd;
+	
+	gc3355_init_usborb(device->device_fd, info->freq, false, false);
+	
+	applog(LOG_INFO, "Found %"PRIpreprv" at %s", device->proc_repr, path);
+	applog(LOG_DEBUG, "%"PRIpreprv": Init: firmware=%d", device->proc_repr, fw_version);
+	
+	return true;
+}
+
+static
+bool gridseed_detect_one(const char *path)
+{
+	struct gc3355_orb_info *info = gridseed_alloc_info();
+	
+	if (!gridseed_detect_custom(path, &gridseed_drv, info))
+	{
+		free(info);
+		return false;
+	}
+	return true;
+}
+
+static
+bool gridseed_lowl_probe(const struct lowlevel_device_info * const info)
+{
+	return vcom_lowl_probe_wrapper(info, gridseed_detect_one);
+}
+
+/*
+ * setup & shutdown
+ */
+
+static
+bool gridseed_thread_prepare(struct thr_info *thr)
+{
+	thr->cgpu_data = calloc(1, sizeof(*thr->cgpu_data));
+	
+	if (opt_scrypt)
+	{
+		struct cgpu_info *device = thr->cgpu;
+		device->min_nonce_diff = 1./0x10000;
+	}
+	
+	return true;
+}
+
+static
+bool gridseed_set_queue_full(const struct cgpu_info * const device, int needwork);
+
+static
+bool gridseed_thread_init(struct thr_info *master_thr)
+{
+	struct cgpu_info * const device = master_thr->cgpu;
+	gridseed_set_queue_full(device, 0);
+	timer_set_now(&master_thr->tv_poll);
+	
+	// kick off queue minerloop
+	gridseed_set_queue_full(device, device->procs * 2);
+	
+	return true;
+}
+
+static
+void gridseed_thread_shutdown(struct thr_info *thr)
+{
+	struct cgpu_info *device = thr->cgpu;
+	gc3355_close(device->device_fd);
+	
+	free(thr->cgpu_data);
+}
+
+static
+void gridseed_reinit_device(struct cgpu_info * const proc)
+{
+	timer_set_now(&proc->thr[0]->tv_poll);
+}
+
+/*
+ * queued mining loop
+ */
+
+static
+bool gridseed_set_queue_full(const struct cgpu_info * const device, int needwork)
+{
+	struct gc3355_orb_info * const info = device->device_data;
+	struct thr_info * const master_thr = device->thr[0];
+	
+	if (needwork != -1)
+		info->needwork = needwork;
+	
+	const bool full = (device->device_fd == -1 || !info->needwork);
+	
+	if (full == master_thr->queue_full)
+		return full;
+	
+	for (const struct cgpu_info *proc = device; proc; proc = proc->next_proc)
+	{
+		struct thr_info * const thr = proc->thr[0];
+		thr->queue_full = full;
+	}
+	
+	return full;
+}
+
+static
+bool gridseed_send_work(const struct cgpu_info * const device, struct work *work)
+{
+	int work_size = opt_scrypt ? 156 : 52;
+	unsigned char cmd[work_size];
+	
+	if (opt_scrypt)
+	{
+		gc3355_scrypt_reset(device->device_fd);
+		gc3355_scrypt_prepare_work(cmd, work);
+	}
+	else
+		gc3355_sha2_prepare_work(cmd, work, true);
+	
+	// send work
+	if (sizeof(cmd) != gc3355_write(device->device_fd, cmd, sizeof(cmd)))
+	{
+		applog(LOG_ERR, "%s: Failed to send work", device->dev_repr);
+		return false;
+	}
+	
+	return true;
+}
+
+static
+void gridseed_prune_queue(const struct cgpu_info * const device, struct work *work)
+{
+	struct thr_info * const master_thr = device->thr[0];
+	
+	// prune queue
+	int prunequeue = HASH_COUNT(master_thr->work_list) - GRIDSEED_MAX_QUEUED;
+	if (prunequeue > 0)
+	{
+		struct work *tmp;
+		applog(LOG_DEBUG, "%s: Pruning %d old work item%s",
+		       device->dev_repr, prunequeue, prunequeue == 1 ? "" : "s");
+		HASH_ITER(hh, master_thr->work_list, work, tmp)
+		{
+			HASH_DEL(master_thr->work_list, work);
+			free_work(work);
+			if (--prunequeue < 1)
+				break;
+		}
+	}
+}
+
+// send work to the device & queue work
+static
+bool gridseed_queue_append(struct thr_info * const thr, struct work *work)
+{
+	const struct cgpu_info * const device = thr->cgpu->device;
+	struct gc3355_orb_info * const info = device->device_data;
+	struct thr_info * const master_thr = device->thr[0];
+	
+	// if queue is full (-1 is a check flag) do not append new work
+	if (gridseed_set_queue_full(device, -1))
+		return false;
+	
+	// send work
+	if (!gridseed_send_work(device, work))
+		return false;
+	
+	// store work in queue
+	HASH_ADD(hh, master_thr->work_list, id, sizeof(work->id), work);
+	
+	// prune queue
+	gridseed_prune_queue(device, work);
+	
+	// sets info->needwork equal to 2nd arg and updates "full" flags
+	gridseed_set_queue_full(device, info->needwork - 1);
+	
+	return true;
+}
+
+static
+void gridseed_queue_flush(struct thr_info * const thr)
+{
+	const struct cgpu_info *device = thr->cgpu;
+	if (device != device->device)
+		return;
+	
+	gridseed_set_queue_full(device, device->procs);
+}
+
+static
+const struct cgpu_info *gridseed_proc_by_id(const struct cgpu_info * const dev, int procid)
+{
+	const struct cgpu_info *proc = dev;
+	for (int i = 0; i < procid; ++i)
+	{
+		proc = proc->next_proc;
+		if (unlikely(!proc))
+			return NULL;
+	}
+	return proc;
+}
+
+static
+void gridseed_submit_nonce(struct thr_info * const master_thr, const unsigned char buf[GC3355_READ_SIZE])
+{
+	struct work *work;
+	uint32_t nonce;
+	int workid;
+	struct cgpu_info * const device = master_thr->cgpu;
+	struct gc3355_orb_info * const info = device->device_data;
+	
+	// extract workid from buffer
+	memcpy(&workid, buf + 8, 4);
+	// extract nonce from buffer
+	memcpy(&nonce, buf + 4, 4);
+	// extract chip # from nonce
+	const int chip = nonce / ((uint32_t)0xffffffff / GC3355_ORB_DEFAULT_CHIPS);
+	// find processor by device & chip
+	const struct cgpu_info *proc = gridseed_proc_by_id(device, chip);
+	// default process to device
+	if (unlikely(!proc))
+		proc = device;
+	// the thread specific to the ASIC chip:
+	struct thr_info * thr = proc->thr[0];
+	
+	nonce = htole32(nonce);
+	
+	// find the queued work for this nonce, by workid
+	HASH_FIND(hh, master_thr->work_list, &workid, sizeof(workid), work);
+	if (work)
+	{
+		submit_nonce(thr, work, nonce);
+		
+		HASH_DEL(master_thr->work_list, work);
+		
+		gridseed_set_queue_full(device, info->needwork + 2);
+	}
+}
+
+static
+void gridseed_estimate_hashes(const struct cgpu_info * const device)
+{
+	const struct cgpu_info *proc = device;
+	const struct gc3355_orb_info *info = device->device_data;
+	
+	while (true)
+	{
+		hashes_done2(proc->thr[0], info->freq * 0xA4, NULL);
+		proc = proc->next_proc;
+		if (unlikely(!proc))
+			return;
+	}
+}
+
+#define GRIDSEED_SHORT_WORK_DELAY_MS  20
+#define GRIDSEED_LONG_WORK_DELAY_MS   30
+
+// read from device for nonce or command
+static
+void gridseed_poll(struct thr_info * const master_thr)
+{
+	struct cgpu_info * const device = master_thr->cgpu;
+	unsigned char buf[GC3355_READ_SIZE];
+	int read = 0;
+	struct timeval tv_timeout;
+	timer_set_delay_from_now(&tv_timeout, GRIDSEED_LONG_WORK_DELAY_MS * 1000);  // X MS
+	
+	while (!master_thr->work_restart && (read = gc3355_read(device->device_fd, (char *)buf, GC3355_READ_SIZE)) > 0)
+	{
+		if (buf[0] == 0x55)
+		{
+			switch(buf[1]) {
+				case 0xaa:
+					// Queue length result
+					// could watch for watchdog reset here
+					break;
+				case 0x10: // BTC result
+				case 0x20: // LTC result
+				{
+					gridseed_submit_nonce(master_thr, buf);
+					break;
+				}
+			}
+		} else
+		{
+			applog(LOG_ERR, "%"PRIpreprv": Unrecognized response", device->proc_repr);
+			break;
+		}
+		
+		if (timer_passed(&tv_timeout, NULL))
+		{
+			// allow work to be sent to the device
+			applog(LOG_DEBUG, "%s poll: timeout met", device->dev_repr);
+			break;
+		}
+	}
+	
+	gridseed_estimate_hashes(device);
+	
+	// allow work to be sent to the device
+	timer_set_delay_from_now(&master_thr->tv_poll, GRIDSEED_SHORT_WORK_DELAY_MS * 1000); // X MS
+}
+
+/*
+ * specify settings / options
+ */
+
+// support for --set-device dualminer:clock=freq
+static
+char *gridseed_set_device(struct cgpu_info *device, char *option, char *setting, char *replybuf)
+{
+	if (strcasecmp(option, "clock") == 0)
+	{
+		int val = atoi(setting);
+		
+		struct gc3355_orb_info *info = (struct gc3355_orb_info *)(device->device_data);
+		info->freq = val;
+		int fd = device->device_fd;
+		
+		gc3355_set_pll_freq(fd, val);
+		
+		return NULL;
+	}
+	
+	sprintf(replybuf, "Unknown option: %s", option);
+	return replybuf;
+}
+
+struct device_drv gridseed_drv =
+{
+	// metadata
+	.dname = "gridseed",
+	.name = "GSD",
+	.supported_algos = POW_SCRYPT,
+	
+	// detect device
+	.lowl_probe = gridseed_lowl_probe,
+	
+	// initialize device
+	.thread_prepare = gridseed_thread_prepare,
+	.thread_init = gridseed_thread_init,
+	.reinit_device = gridseed_reinit_device,
+	
+	// specify mining type - scanhash
+	.minerloop = minerloop_queue,
+	
+	// queued mining hooks
+	.queue_append = gridseed_queue_append,
+	.queue_flush = gridseed_queue_flush,
+	.poll = gridseed_poll,
+	
+	// teardown device
+	.thread_shutdown = gridseed_thread_shutdown,
+	
+	// specify settings / options
+	.set_device = gridseed_set_device,
+};

+ 11 - 11
driver-nanofury.c

@@ -53,14 +53,14 @@ bool nanofury_spi_reset(struct mcp2210_device * const mcp)
 	char buf[1];
 	
 	// SCK_OVRRIDE
-	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_SCK_OVR, MGV_HIGH))
+	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_SCK_OVR, BGV_HIGH))
 		return false;
 	
 	for (r = 0; r < 16; ++r)
 		if (!mcp2210_spi_transfer(mcp, tx, buf, 1))
 			return false;
 	
-	if (mcp2210_get_gpio_input(mcp, NANOFURY_GP_PIN_SCK_OVR) == MGV_ERROR)
+	if (mcp2210_get_gpio_input(mcp, NANOFURY_GP_PIN_SCK_OVR) == BGV_ERROR)
 		return false;
 	
 	return true;
@@ -126,7 +126,7 @@ static
 void nanofury_send_led_gpio(struct nanofury_state * const state)
 {
 	struct mcp2210_device * const mcp = state->mcp;
-	mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_LED, state->ledvalue ? MGV_HIGH : MGV_LOW);
+	mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_LED, state->ledvalue ? BGV_HIGH : BGV_LOW);
 }
 
 static
@@ -147,10 +147,10 @@ void nanofury_device_off(struct mcp2210_device * const mcp)
 static
 bool nanofury_power_enable(struct mcp2210_device * const mcp, const bool poweron)
 {
-	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_PWR_EN, poweron ? MGV_HIGH : MGV_LOW))
+	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_PWR_EN, poweron ? BGV_HIGH : BGV_LOW))
 		return false;
 	
-	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_PWR_EN0, poweron ? MGV_LOW : MGV_HIGH))
+	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_PWR_EN0, poweron ? BGV_LOW : BGV_HIGH))
 		return false;
 	
 	return true;
@@ -165,13 +165,13 @@ bool nanofury_checkport(struct mcp2210_device * const mcp, const unsigned long b
 	
 	// default: set everything to input
 	for (i = 0; i < 9; ++i)
-		if (MGV_ERROR == mcp2210_get_gpio_input(mcp, i))
+		if (BGV_ERROR == mcp2210_get_gpio_input(mcp, i))
 			goto fail;
 	
 	// configure the pins that we need:
 	
 	// LED
-	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_LED, MGV_HIGH))
+	if (!mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_LED, BGV_HIGH))
 		goto fail;
 	
 	nanofury_power_enable(mcp, true);
@@ -191,7 +191,7 @@ bool nanofury_checkport(struct mcp2210_device * const mcp, const unsigned long b
 	
 	// after this command SCK_OVRRIDE should read the same as current SCK value (which for mode 0 should be 0)
 	
-	if (mcp2210_get_gpio_input(mcp, NANOFURY_GP_PIN_SCK_OVR) != MGV_LOW)
+	if (mcp2210_get_gpio_input(mcp, NANOFURY_GP_PIN_SCK_OVR) != BGV_LOW)
 		goto fail;
 	
 	// switch SCK to polarity (default SCK=1 in mode 2)
@@ -202,7 +202,7 @@ bool nanofury_checkport(struct mcp2210_device * const mcp, const unsigned long b
 	
 	// after this command SCK_OVRRIDE should read the same as current SCK value (which for mode 2 should be 1)
 	
-	if (mcp2210_get_gpio_input(mcp, NANOFURY_GP_PIN_SCK_OVR) != MGV_HIGH)
+	if (mcp2210_get_gpio_input(mcp, NANOFURY_GP_PIN_SCK_OVR) != BGV_HIGH)
 		goto fail;
 	
 	// switch SCK to polarity (default SCK=0 in mode 0)
@@ -211,7 +211,7 @@ bool nanofury_checkport(struct mcp2210_device * const mcp, const unsigned long b
 	if (!mcp2210_spi_transfer(mcp, &tmp, &tmprx, 1))
 		goto fail;
 	
-	if (mcp2210_get_gpio_input(mcp, NANOFURY_GP_PIN_SCK_OVR) != MGV_LOW)
+	if (mcp2210_get_gpio_input(mcp, NANOFURY_GP_PIN_SCK_OVR) != BGV_LOW)
 		goto fail;
 	
 	return true;
@@ -435,7 +435,7 @@ void nanofury_poll(struct thr_info * const thr)
 	if (state->identify_requested)
 	{
 		if (!timer_isset(&state->identify_started))
-			mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_LED, state->ledvalue ? MGV_LOW : MGV_HIGH);
+			mcp2210_set_gpio_output(mcp, NANOFURY_GP_PIN_LED, state->ledvalue ? BGV_LOW : BGV_HIGH);
 		timer_set_delay_from_now(&state->identify_started, 5000000);
 		state->identify_requested = false;
 	}

+ 392 - 198
gc3355.c

@@ -1,5 +1,7 @@
 /*
  * Copyright 2014 Nate Woolls
+ * Copyright 2013 Luke Dashjr
+ * Copyright 2014 GridSeed Team
  * Copyright 2014 Dualminer Team
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -24,26 +26,46 @@
   #include <io.h>
 #endif
 
-#define DEFAULT_DELAY_TIME 2000
+// options configurable by the end-user
 
-#define HUBFANS_0_9V_sha2 "60"
-#define HUBFANS_1_2V_sha2 "0"
-#define DEFAULT_0_9V_sha2 "60"
-#define DEFAULT_1_2V_sha2 "0"
+int opt_sha2_units = -1;
+int opt_pll_freq = 0; // default is set in gc3355_set_pll_freq
+
+#define GC3355_CHIP_NAME  "gc3355"
+#define DEFAULT_ORB_SHA2_CORES  16
+
+
+// General GC3355 commands
 
 static
-const char *sha2_gating[] =
+const char *firmware_request_cmd[] =
 {
-	"55AAEF0200000000",
-	"55AAEF0300000000",
-	"55AAEF0400000000",
-	"55AAEF0500000000",
-	"55AAEF0600000000",
-	"",
+	"55AAC000909090900000000001000000",  // get firmware version of GC3355
+	NULL
+};
+
+static
+const char *no_fifo_cmd[] = {
+	"55AAC000D0D0D0D00000000001000000",
+	NULL
 };
 
+// SHA-2 commands
+
+static
+const char *sha2_gating_cmd[] =
+{
+	"55AAEF0200000000",  // Chip 1 - power down SHA-2 (unless masked w/PLL)
+	"55AAEF0300000000",  // Chip 2
+	"55AAEF0400000000",  // Chip 3
+	"55AAEF0500000000",  // Chip 4
+	"55AAEF0600000000",  // Chip 5
+	NULL
+};
+
+// maps the above SHA chip gating with SHA-2 units
 static
-const char *sha2_single_open[] =
+const char *sha2_open_cmd[] =
 {
 	"55AAEF0200000001",
 	"55AAEF0200000003",
@@ -205,11 +227,50 @@ const char *sha2_single_open[] =
 	"55AAEF063FFFFFFF",
 	"55AAEF067FFFFFFF",
 	"55AAEF06FFFFFFFF",
-	"",
+	NULL
 };
 
 static
-const char *scrypt_only_init[] =
+const char *multichip_init_cmd[] =
+{
+	"55AAC000C0C0C0C00500000001000000",  // set number of sub-chips (05 in this case)
+	"55AAEF020000000000000000000000000000000000000000",  // power down all SHA-2 modules
+	"55AAEF3020000000",  // Enable SHA-2 OR NOT - NO SCRYPT ACCEPTS WITHOUT THIS???
+	NULL
+};
+
+static
+const char *sha2_init_cmd[] =
+{
+	"55AAEF3020000000",  // Enable SHA-2
+	"55AA1F2817000000",  // Enable GCP
+	NULL
+};
+
+// called when initializing GridSeed device
+// called while initializing DualMiner when mining in scrypt+sha (dual-mode)
+static
+const char *scrypt_init_cmd[] =
+{
+	"55AA1F2814000000",  // Enable Scrypt
+	"55AA1F2817000000",  // Enable GCP
+	NULL
+};
+
+// called before job start by GridSeed when mining scrypt
+// called before job start by DualMiner when mining scrypt in scrypt+sha (dual-mode)
+static
+const char *scrypt_reset_cmd[] =
+{
+	// faster, for start of each job:
+	"55AA1F2816000000",  // Reset Scrypt(?)
+	"55AA1F2817000000",  // Enable GCP(?)
+	NULL
+};
+
+// called while initializing DualMiner when mining scrypt in scrypt-only (not dual-mode)
+static
+const char *scrypt_only_init_cmd[] =
 {
 	"55AAEF0200000000",
 	"55AAEF0300000000",
@@ -219,20 +280,40 @@ const char *scrypt_only_init[] =
 	"55AAEF3040000000",
 	"55AA1F2810000000",
 	"55AA1F2813000000",
-	"",
+	NULL
 };
 
-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;
+// called before job start by DualMiner when mining scrypt in scrypt-only (not dual-mode)
+// called while initializing DualMiner when mining scrypt in scrypt-only (not dual-mode)
+static
+const char *scrypt_only_reset_cmd[] =
+{
+	"55AA1F2810000000",  // Close Scrypt(?)
+	"55AA1F2813000000",  // Open Scrypt(?)
+	NULL
+};
+
+static
+const char *gcp_chip_reset_cmd[] =
+{
+	"55AAC000808080800000000001000000",  // GCP (GridChip) reset
+	NULL
+};
 
-void gc3355_dual_reset(int fd)
+static
+const char *sha2_chip_reset_cmd[] =
 {
-	set_serial_dtr(fd, 1);
-	cgsleep_ms(1000);
-	set_serial_dtr(fd, 0);
+	"55AAC000E0E0E0E00000000001000000",  // SHA2 reset
+	NULL
+};
+
+
+void gc3355_reset_dtr(int fd)
+{
+	// set data terminal ready (DTR) status
+	set_serial_dtr(fd, BGV_HIGH);
+	cgsleep_ms(GC3355_COMMAND_DELAY_MS);
+	set_serial_dtr(fd, BGV_LOW);
 }
 
 static
@@ -305,252 +386,365 @@ void gc3355_config_sha256d(uint8_t * const buf, const uint8_t chipaddr, const fl
 }
 
 static
-int gc3355_write(const int fd, const void * const buf, const size_t bufsz)
+void gc3355_log_protocol(int fd, const char *buf, size_t size, const char *prefix)
+{
+	char hex[(size * 2) + 1];
+	bin2hex(hex, buf, size);
+	applog(LOG_DEBUG, "%s fd=%d: DEVPROTO: %s(%3lu) %s",
+	       GC3355_CHIP_NAME, fd, prefix, (unsigned long)size, hex);
+}
+
+int gc3355_read(int fd, char *buf, size_t size)
 {
-	const int rv = icarus_write(fd, buf, bufsz);
-	usleep(DEFAULT_DELAY_TIME);
-	return rv;
+	size_t read;
+	int tries = 20;
+	
+	while (tries > 0)
+	{
+		read = serial_read(fd, buf, size);
+		if (read > 0)
+			break;
+		
+		tries--;
+	}
+	
+	if (unlikely(tries == 0))
+		return -1;
+	
+	if ((read > 0) && opt_dev_protocol)
+		gc3355_log_protocol(fd, buf, read, "RECV");
+	
+	return read;
+}
+
+ssize_t gc3355_write(int fd, const void * const buf, const size_t size)
+{
+	if (opt_dev_protocol)
+		gc3355_log_protocol(fd, buf, size, "SEND");
+	
+	return write(fd, buf, size);
 }
 
 static
-void gc3355_send_cmds(int fd, const char *cmds[])
+void _gc3355_send_cmds_bin(int fd, const char *cmds[], bool is_bin, int size)
 {
 	int i = 0;
-	unsigned char ob_bin[32];
-	for(i = 0 ;; i++)
+	unsigned char ob_bin[512];
+	for (i = 0; ; i++)
 	{
-		memset(ob_bin, 0, sizeof(ob_bin));
-
-		if (cmds[i][0] == 0)
+		const char *cmd = cmds[i];
+		if (cmd == NULL)
 			break;
 
-		hex2bin(ob_bin, cmds[i], strlen(cmds[i]) / 2);
-		icarus_write(fd, ob_bin, 8);
-		usleep(DEFAULT_DELAY_TIME);
+		if (is_bin)
+			gc3355_write(fd, cmd, size);
+		else
+		{
+			int bin_size = strlen(cmd) / 2;
+			hex2bin(ob_bin, cmd, bin_size);
+			gc3355_write(fd, ob_bin, bin_size);
+		}
+		
+		cgsleep_ms(GC3355_COMMAND_DELAY_MS);
 	}
 }
 
-void gc3355_opt_scrypt_init(int fd)
-{
-	const char *initscrypt_ob[] =
-	{
-		"55AA1F2810000000",
-		"55AA1F2813000000",
-		""
-	};
+#define gc3355_send_cmds_bin(fd, cmds, size)  _gc3355_send_cmds_bin(fd, cmds, true, size)
+#define gc3355_send_cmds(fd, cmds)  _gc3355_send_cmds_bin(fd, cmds, false, -1)
 
-	gc3355_send_cmds(fd, initscrypt_ob);
+void gc3355_scrypt_only_reset(int fd)
+{
+	gc3355_send_cmds(fd, scrypt_only_reset_cmd);
 }
 
-static
-void gc3355_pll_freq_init2(int fd, int pll_freq)
+void gc3355_set_pll_freq(int fd, int pll_freq)
 {
 	const uint8_t chipaddr = 0xf;
 	const uint32_t baud = 115200;  // FIXME: Make this configurable
 	uint8_t buf[8];
 	
-	if (!pll_freq)
-	{
-		if (gc3355_get_cts_status(fd) == 1)
-			//1.2v - Scrypt mode
-			pll_freq = 850;
-		else
-			//0.9v - Scrypt + SHA mode
-			pll_freq = 550;
-	}
-	
 	gc3355_config_cpm(buf, chipaddr, pll_freq);
 	gc3355_write(fd, buf, sizeof(buf));
 	
+	cgsleep_ms(GC3355_COMMAND_DELAY_MS);
+	
 	gc3355_config_sha256d(buf, chipaddr, pll_freq, baud);
 	gc3355_write(fd, buf, sizeof(buf));
 }
 
-
-void gc3355_open_sha2_unit(int fd, char *opt_sha2_gating)
+static
+void gc3355_open_sha2_units(int fd, int sha2_units)
 {
+	int unit_count = 0;
 	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;
+	// should be 0 - 160
+	unit_count = sha2_units < 0 ? 0 : sha2_units > 160 ? 160 : sha2_units;
 
-	int sha2_number=0;
-	if (opt_sha2_gating== NULL)
-	    sha2_number = 70;
-	else
+	if (unit_count > 0)
 	{
-	    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 <= unit_count; i++)
+		{
+			hex2bin(ob_bin, sha2_open_cmd[i], sizeof(ob_bin));
+			gc3355_write(fd, ob_bin, 8);
+			cgsleep_ms(GC3355_COMMAND_DELAY_MS);
+		}
 	}
+	else if (unit_count == 0)
+		gc3355_send_cmds(fd, sha2_gating_cmd);
+}
 
-	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---
+void gc3355_scrypt_init(int fd)
+{
+	gc3355_send_cmds(fd, scrypt_init_cmd);
+}
 
-	for(i = 0; i < 5; i++)
-	{
-		if (sha2_gating[i][0] == '\0')
-			break;
+static
+void gc3355_scrypt_only_init(int fd)
+{
+	gc3355_send_cmds(fd, sha2_gating_cmd);
+	gc3355_send_cmds(fd, scrypt_only_init_cmd);
+	gc3355_scrypt_only_reset(fd);
+}
 
-		hex2bin(ob_bin, sha2_gating[i], sizeof(ob_bin));
-		icarus_write(fd, ob_bin, 8);
-		usleep(DEFAULT_DELAY_TIME);
+static
+void gc3355_open_sha2_cores(int fd, int sha2_cores)
+{
+	unsigned char cmd[24], c1, c2;
+	uint16_t	mask;
+	int i;
+	
+	mask = 0x00;
+	for (i = 0; i < sha2_cores; i++)
+		mask = mask << 1 | 0x01;
+	
+	if (mask == 0)
+		return;
+	
+	c1 = mask & 0x00ff;
+	c2 = mask >> 8;
+	
+	memset(cmd, 0, sizeof(cmd));
+	memcpy(cmd, "\x55\xaa\xef\x02", 4);
+	for (i = 4; i < 24; i++) {
+		cmd[i] = ((i % 2) == 0) ? c1 : c2;
+		gc3355_write(fd, cmd, sizeof(cmd));
+		cgsleep_ms(GC3355_COMMAND_DELAY_MS);
 	}
-
-	opt_sha2_number = sha2_number;
+	return;
 }
 
 static
-void gc3355_open_sha2_unit_one_by_one(int fd, char *opt_sha2_gating)
+void gc3355_init_sha2_nonce(int fd)
 {
-	int unit_count = 0;
-	unsigned char ob_bin[8];
+	char **cmds, *p;
+	uint32_t nonce, step;
 	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)
+	
+	cmds = calloc(sizeof(char *) *(GC3355_ORB_DEFAULT_CHIPS + 1), 1);
+	
+	if (unlikely(!cmds))
+		quit(1, "Failed to calloc init nonce commands data array");
+	
+	step = 0xffffffff / GC3355_ORB_DEFAULT_CHIPS;
+	
+	for (i = 0; i < GC3355_ORB_DEFAULT_CHIPS; i++)
 	{
-		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;
+		p = calloc(8, 1);
+		
+		if (unlikely(!p))
+			quit(1, "Failed to calloc init nonce commands data");
+		
+		memcpy(p, "\x55\xaa\x00\x00", 4);
+		
+		p[2] = i;
+		nonce = htole32(step * i);
+		memcpy(p + 4, &nonce, sizeof(nonce));
+		cmds[i] = p;
 	}
-	else if (unit_count == 0)
-		gc3355_send_cmds(fd, sha2_gating);
+	
+	cmds[i] = NULL;
+	gc3355_send_cmds_bin(fd, (const char **)cmds, 8);
+	
+	for (i = 0; i < GC3355_ORB_DEFAULT_CHIPS; i++)
+		free(cmds[i]);
+	
+	free(cmds);
+	return;
 }
 
-void gc3355_opt_scrypt_only_init(int fd)
+void gc3355_sha2_init(int fd)
 {
-	gc3355_send_cmds(fd, scrypt_only_init);
-
-	gc3355_pll_freq_init2(fd, opt_pll_freq);
+	gc3355_send_cmds(fd, sha2_gating_cmd);
+	gc3355_send_cmds(fd, sha2_init_cmd);
 }
 
+static
+void gc3355_reset_chips(int fd)
+{
+	// reset chips
+	gc3355_send_cmds(fd, gcp_chip_reset_cmd);
+	gc3355_send_cmds(fd, sha2_chip_reset_cmd);
+}
 
-void gc3355_open_scrypt_unit(int fd, int status)
+void gc3355_init_device(int fd, int pll_freq, bool scrypt_only, bool detect_only, bool usbstick)
 {
-	const char *scrypt_only_ob[] =
-	{
-		"55AA1F2810000000",
-		"",
-	};
+	gc3355_reset_chips(fd);
 
-	const char *scrypt_ob[] =
-	{
-		"55AA1F2814000000",
-		"",
-	};
+	if (usbstick)
+		gc3355_reset_dtr(fd);
 
-	if (status == SCRYPT_UNIT_OPEN)
+	if (usbstick)
 	{
-		if (opt_dual_mode)
-			gc3355_opt_scrypt_init(fd);
+		// initialize units
+		if (opt_scrypt && scrypt_only)
+			gc3355_scrypt_only_init(fd);
 		else
-			gc3355_opt_scrypt_only_init(fd);
+		{
+			gc3355_sha2_init(fd);
+			gc3355_scrypt_init(fd);
+		}
+
+		//set freq
+		gc3355_set_pll_freq(fd, pll_freq);
 	}
 	else
 	{
-		if (opt_dual_mode)
-			gc3355_send_cmds(fd, scrypt_ob);
+		// zzz
+		cgsleep_ms(GC3355_COMMAND_DELAY_MS);
+		
+		// initialize units
+		gc3355_send_cmds(fd, multichip_init_cmd);
+		gc3355_scrypt_init(fd);
+
+		//set freq
+		gc3355_set_pll_freq(fd, pll_freq);
+		
+		//init sha2 nonce
+		gc3355_init_sha2_nonce(fd);
+	}
+
+	// zzz
+	cgsleep_ms(GC3355_COMMAND_DELAY_MS);
+
+	if (!detect_only)
+	{
+		if (!opt_scrypt)
+		{
+			if (usbstick)
+				// open sha2 units
+				gc3355_open_sha2_units(fd, opt_sha2_units);
+			else
+			{
+				// open sha2 cores
+				gc3355_open_sha2_cores(fd, DEFAULT_ORB_SHA2_CORES);
+			}
+		}
+
+		if (usbstick)
+			// set request to send (RTS) status
+			set_serial_rts(fd, BGV_HIGH);
 		else
-			gc3355_send_cmds(fd, scrypt_only_ob);
+			// no fifo for orb
+			gc3355_send_cmds(fd, no_fifo_cmd);
 	}
 }
 
-void gc3355_dualminer_init(int fd)
+void gc3355_init_usborb(int fd, int pll_freq, bool scrypt_only, bool detect_only)
 {
+	gc3355_init_device(fd, pll_freq, scrypt_only, detect_only, false);
+}
 
-	const char *init_ob[] =
-	{
-#if 1
-		"55AAEF0200000000",
-		"55AAEF0300000000",
-		"55AAEF0400000000",
-		"55AAEF0500000000",
-		"55AAEF0600000000",
-#endif
-		"55AAEF3020000000",
-		"55AA1F2817000000",
-		""
-	};
-	const char *initscrypt_ob[] =
-	{
-		"55AA1F2814000000",
-		"55AA1F2817000000",
-		""
-	};
+void gc3355_init_usbstick(int fd, int pll_freq, bool scrypt_only, bool detect_only)
+{
+	gc3355_init_device(fd, pll_freq, scrypt_only, detect_only, true);
+}
 
-	if (opt_scrypt)
-		gc3355_send_cmds(fd, initscrypt_ob);
-	else
-		gc3355_send_cmds(fd, init_ob);
+void gc3355_scrypt_reset(int fd)
+{
+	gc3355_send_cmds(fd, scrypt_reset_cmd);
+}
 
-	if (!opt_scrypt)
-		gc3355_pll_freq_init2(fd, opt_pll_freq);
+void gc3355_scrypt_prepare_work(unsigned char cmd[156], struct work *work)
+{
+	// command header
+	cmd[0] = 0x55;
+	cmd[1] = 0xaa;
+	cmd[2] = 0x1f;
+	cmd[3] = 0x00;
+	
+	// task data
+	memcpy(cmd + 4, work->target, 32);
+	memcpy(cmd + 36, work->midstate, 32);
+	memcpy(cmd + 68, work->data, 80);
+	
+	// nonce_max
+	cmd[148] = 0xff;
+	cmd[149] = 0xff;
+	cmd[150] = 0xff;
+	cmd[151] = 0xff;
+	
+	// taskid
+	int workid = work->id;
+	memcpy(cmd + 152, &(workid), 4);
 }
 
-void gc3355_init(int fd, char *sha2_unit, bool is_scrypt_only)
+void gc3355_sha2_prepare_work(unsigned char cmd[52], struct work *work, bool simple)
 {
-	if (gc3355_get_cts_status(fd) == 1)
+	if (simple)
 	{
-		//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));
-		}
+		// command header
+		cmd[0] = 0x55;
+		cmd[1] = 0xaa;
+		cmd[2] = 0x0f;
+		cmd[3] = 0x01; // SHA header sig
+		
+		memcpy(cmd + 4, work->midstate, 32);
+		memcpy(cmd + 36, work->data + 64, 12);
+		
+		// taskid
+		int workid = work->id;
+		memcpy(cmd + 48, &(workid), 4);
 	}
 	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));
-		}
+		// command header
+		cmd[0] = 0x55;
+		cmd[1] = 0xaa;
+		cmd[2] = 0x0f;
+		cmd[3] = 0x00; // Scrypt header sig - used by DualMiner in Dual Mode
+		
+		uint8_t temp_bin[64];
+		memset(temp_bin, 0, 64);
+		
+		memcpy(temp_bin, work->midstate, 32);
+		memcpy(temp_bin + 52, work->data + 64, 12);
+		
+		memcpy(cmd + 8, work->midstate, 32);
+		memcpy(cmd + 40, temp_bin + 52, 12);
 	}
 }
+
+uint32_t gc3355_get_firmware_version(int fd)
+{
+	gc3355_send_cmds(fd, firmware_request_cmd);
+	
+	char buf[GC3355_READ_SIZE];
+	int read = gc3355_read(fd, buf, GC3355_READ_SIZE);
+	if (read != GC3355_READ_SIZE)
+	{
+		applog(LOG_ERR, "%s: Failed reading work from %d", GC3355_CHIP_NAME, fd);
+		return -1;
+	}
+	
+	// firmware response begins with 55aac000 90909090
+	if (memcmp(buf, "\x55\xaa\xc0\x00\x90\x90\x90\x90", GC3355_READ_SIZE - 4) != 0)
+	{
+		return -1;
+	}
+	
+	uint32_t fw_version = le32toh(*(uint32_t *)(buf + 8));
+	
+	return fw_version;
+}

+ 30 - 29
gc3355.h

@@ -1,5 +1,6 @@
 /*
  * Copyright 2014 Nate Woolls
+ * Copyright 2014 GridSeed Team
  * Copyright 2014 Dualminer Team
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -12,52 +13,52 @@
 #define bfgminer_gc3355_h
 
 #include <stdbool.h>
+#include <stdint.h>
 
-#define SCRYPT_UNIT_OPEN  0
-#define SCRYPT_UNIT_CLOSE 1
+#include "miner.h"
 
-extern
-char *opt_dualminer_sha2_gating;
+// options configurable by the end-user
+
+extern int opt_sha2_units;
 
 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;
+// GridSeed common code begins here
 
-//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;
+#define GC3355_COMMAND_DELAY_MS 20
+#define GC3355_ORB_DEFAULT_CHIPS   5
+#define GC3355_READ_SIZE          12
 
-extern
-bool opt_hubfans;
+struct gc3355_orb_info
+{
+	uint16_t freq;
+	int needwork;
+};
 
-extern
-void gc3355_dual_reset(int fd);
+#define gc3355_open(path)  serial_open(path, 115200, 1, true)
+#define gc3355_close(fd)  serial_close(fd)
 
-extern
-void gc3355_opt_scrypt_only_init(int fd);
+extern int gc3355_read(int fd, char *buf, size_t size);
+extern ssize_t gc3355_write(int fd, const void * const buf, const size_t size);
 
-extern
-void gc3355_dualminer_init(int fd);
+extern void gc3355_init_usborb(int fd, int pll_freq, bool scrypt_only, bool detect_only);
 
 extern
-void gc3355_opt_scrypt_init(int fd);
+void gc3355_reset_dtr(int fd);
 
-extern
-void gc3355_init(int fd, char *sha2_unit, bool is_scrypt_only);
+extern void gc3355_init_usbstick(int fd, int pll_freq, bool scrypt_only, bool detect_only);
 
-extern
-void gc3355_open_sha2_unit(int fd, char *opt_sha2_gating);
+extern void gc3355_scrypt_reset(int fd);
 
 extern
-void gc3355_open_scrypt_unit(int fd, int status);
+void gc3355_scrypt_only_reset(int fd);
+
+extern void gc3355_scrypt_prepare_work(unsigned char cmd[156], struct work *);
+extern void gc3355_sha2_prepare_work(unsigned char cmd[52], struct work *, bool simple);
+extern uint32_t gc3355_get_firmware_version(int fd);
+extern void gc3355_set_pll_freq(int fd, int pll_freq);
 
-#define gc3355_get_cts_status(fd)  (get_serial_cts(fd) ? 0 : 1)
-#define gc3355_set_rts_status(fd, val)  set_serial_rts(fd, val)
+#define gc3355_get_cts_status(fd)  ((get_serial_cts(fd) == BGV_LOW) ? 1 : 0)
 
 #endif

+ 20 - 20
lowl-vcom.c

@@ -1097,24 +1097,24 @@ ssize_t _serial_read(int fd, char *buf, size_t bufsiz, char *eol)
 
 #ifndef WIN32
 
-int get_serial_cts(int fd)
+enum bfg_gpio_value get_serial_cts(int fd)
 {
 	int flags;
 
 	if (fd == -1)
-		return -1;
+		return BGV_ERROR;
 
 	ioctl(fd, TIOCMGET, &flags);
-	return (flags & TIOCM_CTS) ? 1 : 0;
+	return (flags & TIOCM_CTS) ? BGV_HIGH : BGV_LOW;
 }
 
 static
-int _set_serial_cmflag(int fd, int flag, bool val)
+enum bfg_gpio_value _set_serial_cmflag(int fd, int flag, bool val)
 {
 	int flags;
 
 	if (fd == -1)
-		return -1;
+		return BGV_ERROR;
 
 	ioctl(fd, TIOCMGET, &flags);
 	
@@ -1124,57 +1124,57 @@ int _set_serial_cmflag(int fd, int flag, bool val)
 		flags &= ~flag;
 
 	ioctl(fd, TIOCMSET, &flags);
-	return val ? 1 : 0;
+	return val ? BGV_HIGH : BGV_LOW;
 }
 
-int set_serial_dtr(int fd, int dtr)
+enum bfg_gpio_value set_serial_dtr(int fd, enum bfg_gpio_value dtr)
 {
 	return _set_serial_cmflag(fd, TIOCM_DTR, dtr);
 }
 
-int set_serial_rts(int fd, int rts)
+enum bfg_gpio_value set_serial_rts(int fd, enum bfg_gpio_value rts)
 {
 	return _set_serial_cmflag(fd, TIOCM_RTS, rts);
 }
 #else
-int get_serial_cts(const int fd)
+enum bfg_gpio_value get_serial_cts(const int fd)
 {
 	if (fd == -1)
-		return -1;
+		return BGV_ERROR;
 	const HANDLE fh = (HANDLE)_get_osfhandle(fd);
 	if (fh == INVALID_HANDLE_VALUE)
-		return -1;
+		return BGV_ERROR;
 
 	DWORD flags;
 	if (!GetCommModemStatus(fh, &flags))
-		return -1;
+		return BGV_ERROR;
 
-	return (flags & MS_CTS_ON) ? 1 : 0;
+	return (flags & MS_CTS_ON) ? BGV_HIGH : BGV_LOW;
 }
 
 static
-int _set_serial_cmflag(int fd, void (*setfunc)(DCB*, bool), bool val, const char * const fname)
+enum bfg_gpio_value _set_serial_cmflag(int fd, void (*setfunc)(DCB*, bool), bool val, const char * const fname)
 {
 	if (fd == -1)
-		return -1;
+		return BGV_ERROR;
 	const HANDLE fh = (HANDLE)_get_osfhandle(fd);
 	if (fh == INVALID_HANDLE_VALUE)
-		return -1;
+		return BGV_ERROR;
 	
 	DCB dcb;
 	if (!GetCommState(fh, &dcb))
-		applogr(-1, LOG_DEBUG, "Failed to %s"IN_FMT_FFL": %s",
+		applogr(BGV_ERROR, LOG_DEBUG, "Failed to %s"IN_FMT_FFL": %s",
 		        "GetCommState", __FILE__, fname, __LINE__,
 		        bfg_strerror(GetLastError(), BST_SYSTEM));
 	
 	setfunc(&dcb, val);
 	
 	if (!SetCommState(fh, &dcb))
-		applogr(-1, LOG_DEBUG, "Failed to %s"IN_FMT_FFL": %s",
+		applogr(BGV_ERROR, LOG_DEBUG, "Failed to %s"IN_FMT_FFL": %s",
 		        "GetCommState", __FILE__, fname, __LINE__,
 		        bfg_strerror(GetLastError(), BST_SYSTEM));
 	
-	return val ? 1 : 0;
+	return val ? BGV_HIGH : BGV_LOW;
 }
 #define _set_serial_cmflag2(name, field, trueval, falseval)  \
 static  \
@@ -1183,7 +1183,7 @@ void _set_serial_cmflag_ ## name(DCB *dcb, bool val)  \
 	dcb->field = val ? (trueval) : (falseval);  \
 }  \
   \
-int set_serial_ ## name(int fd, int val)  \
+enum bfg_gpio_value set_serial_ ## name(int fd, enum bfg_gpio_value val)  \
 {  \
 	return _set_serial_cmflag(fd, _set_serial_cmflag_ ## name, val, "set_serial_" #name);  \
 }  \

+ 4 - 3
lowl-vcom.h

@@ -7,6 +7,7 @@
 #include <unistd.h>
 
 #include "deviceapi.h"
+#include "util.h"
 
 struct device_drv;
 struct cgpu_info;
@@ -38,9 +39,9 @@ extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char *eol);
 	_serial_read(fd, buf, bufsiz, &eol)
 extern int serial_close(int fd);
 
-extern int get_serial_cts(int fd);
-extern int set_serial_dtr(int fd, int dtr);
-extern int set_serial_rts(int fd, int rts);
+extern enum bfg_gpio_value get_serial_cts(int fd);
+extern enum bfg_gpio_value set_serial_dtr(int fd, enum bfg_gpio_value dtr);
+extern enum bfg_gpio_value set_serial_rts(int fd, enum bfg_gpio_value rts);
 extern bool valid_baud(int baud);
 
 #endif

+ 7 - 7
mcp2210.c

@@ -281,7 +281,7 @@ bool mcp2210_set_cfg_gpio(struct mcp2210_device * const h)
 	return true;
 }
 
-bool mcp2210_set_gpio_output(struct mcp2210_device * const h, const int pin, const enum mcp2210_gpio_value d)
+bool mcp2210_set_gpio_output(struct mcp2210_device * const h, const int pin, const enum bfg_gpio_value d)
 {
 	const int bit = 1 << (pin % 8);
 	const int byte = (pin / 8);
@@ -293,7 +293,7 @@ bool mcp2210_set_gpio_output(struct mcp2210_device * const h, const int pin, con
 	h->cfg_gpio[byte + 0xb] &= ~bit;
 	
 	// Set value for GPIO output
-	if (d == MGV_HIGH)
+	if (d == BGV_HIGH)
 		h->cfg_gpio[byte + 9] |= bit;
 	else
 		h->cfg_gpio[byte + 9] &= ~bit;
@@ -301,7 +301,7 @@ bool mcp2210_set_gpio_output(struct mcp2210_device * const h, const int pin, con
 	return mcp2210_set_cfg_gpio(h);
 }
 
-enum mcp2210_gpio_value mcp2210_get_gpio_input(struct mcp2210_device * const h, const int pin)
+enum bfg_gpio_value mcp2210_get_gpio_input(struct mcp2210_device * const h, const int pin)
 {
 	hid_device * const hid = h->hid;
 	uint8_t cmd[0x41] = {0,0x31}, buf[0x40];
@@ -315,18 +315,18 @@ enum mcp2210_gpio_value mcp2210_get_gpio_input(struct mcp2210_device * const h,
 	h->cfg_gpio[byte + 0xb] |= bit;
 	
 	if (!mcp2210_set_cfg_gpio(h))
-		return MGV_ERROR;
+		return BGV_ERROR;
 	
 	if (!mcp2210_io(hid, cmd, buf))
 	{
 		applog(LOG_ERR, "%s: Failed to get current GPIO input values", __func__);
-		return MGV_ERROR;
+		return BGV_ERROR;
 	}
 	
 	if (buf[byte + 4] & bit)
-		return MGV_HIGH;
+		return BGV_HIGH;
 	else
-		return MGV_LOW;
+		return BGV_LOW;
 }
 
 struct lowlevel_driver lowl_mcp2210 = {

+ 2 - 8
mcp2210.h

@@ -9,12 +9,6 @@ enum mcp2210_gpio_direction {
 	MGD_INPUT,
 };
 
-enum mcp2210_gpio_value {
-	MGV_LOW,
-	MGV_HIGH,
-	MGV_ERROR,
-};
-
 struct mcp2210_device;
 
 extern struct mcp2210_device *mcp2210_open(const struct lowlevel_device_info *);
@@ -25,7 +19,7 @@ extern bool mcp2210_configure_spi(struct mcp2210_device *, uint32_t bitrate, uin
 extern bool mcp2210_set_spimode(struct mcp2210_device *, uint8_t spimode);
 extern bool mcp2210_spi_transfer(struct mcp2210_device *, const void *tx, void *rx, uint8_t sz);
 
-extern bool mcp2210_set_gpio_output(struct mcp2210_device *, int pin, enum mcp2210_gpio_value);
-extern enum mcp2210_gpio_value mcp2210_get_gpio_input(struct mcp2210_device *, int pin);
+extern bool mcp2210_set_gpio_output(struct mcp2210_device *, int pin, enum bfg_gpio_value);
+extern enum bfg_gpio_value mcp2210_get_gpio_input(struct mcp2210_device *, int pin);
 
 #endif

+ 8 - 0
util.h

@@ -111,6 +111,14 @@ bool isCspace(int c)
 	}
 }
 
+
+enum bfg_gpio_value {
+	BGV_LOW   =  0,
+	BGV_HIGH  =  1,
+	BGV_ERROR = -1,
+};
+
+
 typedef struct timeval cgtimer_t;
 
 struct thr_info;