Browse Source

gridseed: Added support for Scrypt hashing with 5-chip GridSeed devices

Clock can be set with --set-device gridseed:clock=mhz
Individual chip stats by pressing D, M, Return
Nate Woolls 12 years ago
parent
commit
33cf402872
6 changed files with 724 additions and 41 deletions
  1. 1 0
      AUTHORS
  2. 9 1
      Makefile.am
  3. 15 0
      configure.ac
  4. 456 0
      driver-gridseed.c
  5. 223 36
      gc3355.c
  6. 20 4
      gc3355.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

@@ -234,8 +234,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

+ 15 - 0
configure.ac

@@ -461,8 +461,23 @@ else
 fi
 if test "x$dualminer" = "xyes"; then
 	AC_DEFINE([USE_DUALMINER], [1], [Defined to 1 if DualMiner support is wanted])
+	AC_DEFINE([USE_GC3355], [1], [Defined to 1 if GC3355 support is wanted])
 fi
 AM_CONDITIONAL([USE_DUALMINER], [test x$dualminer = xyes])
+AM_CONDITIONAL([USE_GC3355], [test x$dualminer = xyes])
+
+driverlist="$driverlist gridseed"
+gridseed=yes
+AC_ARG_ENABLE([gridseed],
+	[AC_HELP_STRING([--disable-gridseed],[Compile support for GridSeed (default enabled)])],
+	[gridseed=$enableval]
+	)
+if test "x$gridseed" = "xyes"; then
+	AC_DEFINE([USE_GRIDSEED], [1], [Defined to 1 if GridSeed support is wanted])
+	AC_DEFINE([USE_GC3355], [1], [Defined to 1 if GC3355 support is wanted])
+fi
+AM_CONDITIONAL([USE_GRIDSEED], [test x$gridseed = xyes])
+AM_CONDITIONAL([USE_GC3355], [test x$gridseed = xyes])
 
 driverlist="$driverlist avalon"
 avalon="no"

+ 456 - 0
driver-gridseed.c

@@ -0,0 +1,456 @@
+/*
+ * 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, *proc;
+	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)
+{
+	struct gc3355_orb_info * const info = device->device_data;
+	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;
+	int fd = device->device_fd;
+	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
+	bool timeout = false;
+	
+	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);
+			timeout = true;
+			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,
+};

+ 223 - 36
gc3355.c

@@ -31,6 +31,24 @@
 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 *firmware_request_cmd[] =
+{
+	"55AAC000909090900000000001000000",  // get firmware version of GC3355
+	NULL
+};
+
+static
+const char *no_fifo_cmd[] = {
+	"55AAC000D0D0D0D00000000001000000",
+	NULL
+};
 
 // SHA-2 commands
 
@@ -212,6 +230,15 @@ const char *sha2_open_cmd[] =
 	NULL
 };
 
+static
+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[] =
 {
@@ -359,56 +386,87 @@ 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)
 {
-	const int rv = icarus_write(fd, buf, bufsz);
-	cgsleep_ms(GC3355_COMMAND_DELAY_MS);
-	return rv;
+	char hex[(size * 2) + 1];
+	bin2hex(hex, buf, size);
+	applog(LOG_DEBUG, "%s fd=%d: DEVPROTO: %s(%3lu) %s", GC3355_CHIP_NAME, fd, prefix, size, hex);
+}
+
+int gc3355_read(int fd, char *buf, size_t size)
+{
+	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] == NULL)
+		const char *cmd = cmds[i];
+		if (cmd == NULL)
 			break;
 
-		hex2bin(ob_bin, cmds[i], strlen(cmds[i]) / 2);
-		icarus_write(fd, ob_bin, 8);
+		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);
 	}
 }
 
+#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)
+
 void gc3355_scrypt_only_reset(int fd)
 {
 	gc3355_send_cmds(fd, scrypt_only_reset_cmd);
 }
 
-static
 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));
 }
@@ -450,6 +508,71 @@ void gc3355_scrypt_only_init(int fd)
 }
 
 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);
+	}
+	return;
+}
+
+static
+void gc3355_init_sha2_nonce(int fd)
+{
+	char **cmds, *p;
+	uint32_t nonce, step;
+	int i;
+	
+	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++)
+	{
+		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;
+	}
+	
+	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_sha2_init(int fd)
 {
 	gc3355_send_cmds(fd, sha2_gating_cmd);
@@ -464,24 +587,42 @@ void gc3355_reset_chips(int fd)
 	gc3355_send_cmds(fd, sha2_chip_reset_cmd);
 }
 
-void gc3355_init_usbstick(int fd, int pll_freq, bool scrypt_only, bool detect_only)
+void gc3355_init_device(int fd, int pll_freq, bool scrypt_only, bool detect_only, bool usbstick)
 {
 	gc3355_reset_chips(fd);
 
-	gc3355_reset_dtr(fd);
+	if (usbstick)
+		gc3355_reset_dtr(fd);
 
+	if (usbstick)
+	{
+		// initialize units
+		if (opt_scrypt && scrypt_only)
+			gc3355_scrypt_only_init(fd);
+		else
+		{
+			gc3355_sha2_init(fd);
+			gc3355_scrypt_init(fd);
+		}
 
-	// initialize units
-	if (opt_scrypt && scrypt_only)
-		gc3355_scrypt_only_init(fd);
+		//set freq
+		gc3355_set_pll_freq(fd, pll_freq);
+	}
 	else
 	{
-		gc3355_sha2_init(fd);
+		// 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);
+		//set freq
+		gc3355_set_pll_freq(fd, pll_freq);
+		
+		//init sha2 nonce
+		gc3355_init_sha2_nonce(fd);
+	}
 
 	// zzz
 	cgsleep_ms(GC3355_COMMAND_DELAY_MS);
@@ -490,15 +631,35 @@ void gc3355_init_usbstick(int fd, int pll_freq, bool scrypt_only, bool detect_on
 	{
 		if (!opt_scrypt)
 		{
-			// open sha2 units
-			gc3355_open_sha2_units(fd, opt_sha2_units);
+			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);
+			}
 		}
 
-		// set request to send (RTS) status
-		set_serial_rts(fd, BGV_HIGH);
+		if (usbstick)
+			// set request to send (RTS) status
+			set_serial_rts(fd, BGV_HIGH);
+		else
+			// no fifo for orb
+			gc3355_send_cmds(fd, no_fifo_cmd);
 	}
 }
 
+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);
+}
+
+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);
+}
+
 void gc3355_scrypt_reset(int fd)
 {
 	gc3355_send_cmds(fd, scrypt_reset_cmd);
@@ -563,3 +724,29 @@ void gc3355_sha2_prepare_work(unsigned char cmd[52], struct work *work, bool sim
 		memcpy(cmd + 40, temp_bin + 52, 12);
 	}
 }
+
+uint32_t gc3355_get_firmware_version(int fd)
+{
+	unsigned char detect_data[16];
+	int size = sizeof(detect_data);
+	
+	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;
+}

+ 20 - 4
gc3355.h

@@ -13,6 +13,7 @@
 #define bfgminer_gc3355_h
 
 #include <stdbool.h>
+#include <stdint.h>
 
 #include "miner.h"
 
@@ -20,15 +21,28 @@
 
 extern int opt_sha2_units;
 
+extern
+int opt_pll_freq;
+
 // GridSeed common code begins here
 
 #define GC3355_COMMAND_DELAY_MS 20
+#define GC3355_ORB_DEFAULT_CHIPS   5
+#define GC3355_READ_SIZE          12
 
-#define SCRYPT_UNIT_OPEN  0
-#define SCRYPT_UNIT_CLOSE 1
+struct gc3355_orb_info
+{
+	uint16_t freq;
+	int needwork;
+};
 
-extern
-int opt_pll_freq;
+#define gc3355_open(path)  serial_open(path, 115200, 1, true)
+#define gc3355_close(fd)  serial_close(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_init_usborb(int fd, int pll_freq, bool scrypt_only, bool detect_only);
 
 extern
 void gc3355_reset_dtr(int fd);
@@ -42,6 +56,8 @@ 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) == BGV_LOW) ? 1 : 0)