Browse Source

Merge branch 'hashbuster' into bfgminer

Luke Dashjr 12 years ago
parent
commit
5b49c96464
10 changed files with 614 additions and 154 deletions
  1. 10 1
      Makefile.am
  2. 52 10
      configure.ac
  3. 315 0
      driver-hashbuster.c
  4. 3 2
      driver-nanofury.c
  5. 189 0
      lowl-hid.c
  6. 25 0
      lowl-hid.h
  7. 5 0
      lowlevel.c
  8. 3 0
      lowlevel.h
  9. 11 141
      mcp2210.c
  10. 1 0
      spidevc.h

+ 10 - 1
Makefile.am

@@ -257,8 +257,17 @@ endif
 
 if HAS_NANOFURY
 bfgminer_SOURCES += driver-nanofury.c mcp2210.c mcp2210.h
-bfgminer_CPPFLAGS += $(hidapi_CFLAGS)
 endif
+
+if USE_HASHBUSTER
+bfgminer_SOURCES += driver-hashbuster.c
+endif
+
+endif
+
+if NEED_BFG_LOWL_HID
+bfgminer_SOURCES += lowl-hid.c lowl-hid.h
+bfgminer_CPPFLAGS += $(hidapi_CFLAGS)
 endif
 
 bin_PROGRAMS += bfgminer-rpc

+ 52 - 10
configure.ac

@@ -112,6 +112,7 @@ optlist=
 need_dynclock=no
 need_fpgautils=no
 need_lowlevel=no
+need_lowl_hid=no
 have_cygwin=false
 have_win32=false
 have_macho=false
@@ -628,6 +629,17 @@ fi
 AM_CONDITIONAL([HAS_LITTLEFURY], [test x$littlefury = xyes])
 
 
+found_hidapi=false
+for _hidapi_lib in hidapi hidapi-hidraw hidapi-libusb; do
+	PKG_CHECK_MODULES([hidapi],[$_hidapi_lib],[
+		found_hidapi=true
+		break
+	],[
+		true
+	])
+done
+
+
 driverlist="$driverlist nanofury"
 nanofury=auto
 AC_ARG_ENABLE([nanofury],
@@ -637,15 +649,6 @@ AC_ARG_ENABLE([nanofury],
 if test "x$nanofury" = "xno"; then
 	true
 elif test "x$bitfury" = "xyes"; then
-	_found_hidapi=false
-	for _hidapi_lib in hidapi hidapi-hidraw hidapi-libusb; do
-		PKG_CHECK_MODULES([hidapi],[$_hidapi_lib],[
-			found_hidapi=true
-			break
-		],[
-			true
-		])
-	done
 	if test x$found_hidapi = xtrue; then
 		nanofury=yes
 	else
@@ -658,7 +661,6 @@ elif test "x$bitfury" = "xyes"; then
 	fi
 elif test "x$nanofury" = "xyes"; then
 	AC_MSG_ERROR([You explicitly disabled Bitfury and explicitly enabled NanoFury])
-	need_fpgautils=yes
 else
 	nanofury=no
 fi
@@ -666,10 +668,44 @@ if test "x$nanofury" = "xyes"; then
 	AC_DEFINE([USE_NANOFURY], [1], [Defined to 1 if NanoFury support is wanted])
 	need_fpgautils=yes
 	need_lowlevel=yes
+	need_lowl_hid=yes
 fi
 AM_CONDITIONAL([HAS_NANOFURY], [test x$nanofury = xyes])
 
 
+driverlist="$driverlist hashbuster"
+hashbuster=auto
+AC_ARG_ENABLE([hashbuster],
+	[AC_HELP_STRING([--disable-hashbuster],[Compile support for HashBuster (default enabled)])],
+	[hashbuster=$enableval]
+	)
+if test "x$hashbuster" = "xno"; then
+	true
+elif test "x$bitfury" = "xyes"; then
+	if test x$found_hidapi = xtrue; then
+		hashbuster=yes
+	else
+		if test x$hashbuster = xauto; then
+			hashbuster=no
+			hashbuster_enableaction="install hidapi"
+		else
+			AC_MSG_ERROR([Could not find hidapi, required for HashBuster support])
+		fi
+	fi
+elif test "x$hashbuster" = "xyes"; then
+	AC_MSG_ERROR([You explicitly disabled Bitfury and explicitly enabled HashBuster])
+else
+	hashbuster=no
+fi
+if test "x$hashbuster" = "xyes"; then
+	AC_DEFINE([USE_HASHBUSTER], [1], [Defined to 1 if HashBuster support is wanted])
+	need_fpgautils=yes
+	need_lowlevel=yes
+	need_lowl_hid=yes
+fi
+AM_CONDITIONAL([USE_HASHBUSTER], [test x$hashbuster = xyes])
+
+
 driverlist="$driverlist metabank"
 metabank=no
 AC_ARG_ENABLE([metabank],
@@ -753,6 +789,11 @@ if test x$need_fpgautils = xyes; then
 	fi
 fi
 
+if test x$need_lowl_hid = xyes; then
+	AC_DEFINE([NEED_BFG_LOWL_HID], [1], [Defined to 1 if lowlevel hid drivers are being used])
+	need_lowlevel=yes
+fi
+
 if test x$need_lowlevel = xyes; then
 	AC_DEFINE([HAVE_BFG_LOWLEVEL], [1], [Defined to 1 if lowlevel drivers are being used])
 fi
@@ -910,6 +951,7 @@ AC_SUBST(libblkmaker_LIBS)
 AM_CONDITIONAL([NEED_LIBBLKMAKER], [test x$with_system_libblkmaker != xyes])
 AM_CONDITIONAL([NEED_DYNCLOCK], [test x$need_dynclock = xyes])
 AM_CONDITIONAL([NEED_FPGAUTILS], [test x$need_fpgautils = xyes])
+AM_CONDITIONAL([NEED_BFG_LOWL_HID], [test x$need_lowl_hid = xyes])
 AM_CONDITIONAL([NEED_BFG_LOWLEVEL], [test x$need_lowlevel = xyes])
 AM_CONDITIONAL([HAS_SCRYPT], [test x$scrypt = xyes])
 AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes])

+ 315 - 0
driver-hashbuster.c

@@ -0,0 +1,315 @@
+/*
+ * Copyright 2013 Luke Dashjr
+ * Copyright 2013 Vladimir Strinski
+ *
+ * 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 "deviceapi.h"
+#include "driver-bitfury.h"
+#include "fpgautils.h"
+#include "libbitfury.h"
+#include "logging.h"
+#include "lowlevel.h"
+#include "lowl-hid.h"
+#include "miner.h"
+
+#define HASHBUSTER_USB_PRODUCT "HashBuster"
+
+#define HASHBUSTER_MAX_BYTES_PER_SPI_TRANSFER 62
+
+BFG_REGISTER_DRIVER(hashbuster_drv)
+
+static
+bool hashbuster_io(hid_device * const h, void * const buf, const void * const cmd)
+{
+	const uint8_t cmdbyte = *((uint8_t *)cmd);
+	char x[0x81];
+	if (unlikely(opt_dev_protocol))
+	{
+		bin2hex(x, cmd, 0x40);
+		applog(LOG_DEBUG, "%s(%p): SEND: %s", __func__, h, x);
+	}
+	const bool rv = likely(
+		0x40 == hid_write(h, cmd, 0x40) &&
+		0x40 == hid_read (h, buf, 0x40) &&
+		((uint8_t *)buf)[0] == cmdbyte
+	);
+	if (unlikely(opt_dev_protocol))
+	{
+		bin2hex(x, buf, 0x40);
+		applog(LOG_DEBUG, "%s(%p): RECV: %s", __func__, h, x);
+	}
+	return rv;
+}
+
+static
+bool hashbuster_spi_config(hid_device * const h, const uint8_t mode, const uint8_t miso, const uint32_t freq)
+{
+	uint8_t buf[0x40] = {'\x01', '\x01', mode, miso};
+	switch (freq)
+	{
+		case 100000:
+			buf[4] = '\0';
+			break;
+		case 750000:
+			buf[4] = '\x01';
+			break;
+		case 3000000:
+			buf[4] = '\x02';
+			break;
+		case 12000000:
+			buf[4] = '\x03';
+			break;
+		default:
+			return false;
+	}
+	if (!hashbuster_io(h, buf, buf))
+		return false;
+	return (buf[1] == '\x0f');
+}
+
+static
+bool hashbuster_spi_disable(hid_device * const h)
+{
+	uint8_t buf[0x40] = {'\x01'};
+	if (!hashbuster_io(h, buf, buf))
+		return false;
+	return (buf[1] == '\x0f');
+}
+
+static
+bool hashbuster_spi_reset(hid_device * const h, uint8_t chips)
+{
+	uint8_t buf[0x40] = {'\x02', chips};
+	if (!hashbuster_io(h, buf, buf))
+		return false;
+	return (buf[1] == '\xff');
+}
+
+static
+bool hashbuster_spi_transfer(hid_device * const h, void * const buf, const void * const data, size_t datasz)
+{
+	if (datasz > HASHBUSTER_MAX_BYTES_PER_SPI_TRANSFER)
+		return false;
+	uint8_t cbuf[0x40] = {'\x03', datasz};
+	memcpy(&cbuf[2], data, datasz);
+	if (!hashbuster_io(h, cbuf, cbuf))
+		return false;
+	if (cbuf[1] != datasz)
+		return false;
+	memcpy(buf, &cbuf[2], datasz);
+	return true;
+}
+
+static
+bool hashbuster_spi_txrx(struct spi_port * const port)
+{
+	hid_device * const h = port->userp;
+	const uint8_t *wrbuf = spi_gettxbuf(port);
+	uint8_t *rdbuf = spi_getrxbuf(port);
+	size_t bufsz = spi_getbufsz(port);
+	
+	hashbuster_spi_disable(h);
+	hashbuster_spi_reset(h, 0x10);
+	
+	hashbuster_spi_config(h, port->mode, 0, port->speed);
+	
+	while (bufsz >= HASHBUSTER_MAX_BYTES_PER_SPI_TRANSFER)
+	{
+		if (!hashbuster_spi_transfer(h, rdbuf, wrbuf, HASHBUSTER_MAX_BYTES_PER_SPI_TRANSFER))
+			return false;
+		rdbuf += HASHBUSTER_MAX_BYTES_PER_SPI_TRANSFER;
+		wrbuf += HASHBUSTER_MAX_BYTES_PER_SPI_TRANSFER;
+		bufsz -= HASHBUSTER_MAX_BYTES_PER_SPI_TRANSFER;
+	}
+	
+	if (bufsz > 0)
+	{
+		if (!hashbuster_spi_transfer(h, rdbuf, wrbuf, bufsz))
+			return false;
+	}
+	
+	return true;
+}
+
+static
+bool hashbuster_foundlowl(struct lowlevel_device_info * const info, __maybe_unused void *userp)
+{
+	const char * const product = info->product;
+	const char * const serial = info->serial;
+	char * const path = info->path;
+	hid_device *h;
+	uint8_t buf[0x40] = {'\xfe'};
+	
+	if (info->lowl != &lowl_hid)
+		applogr(false, LOG_WARNING, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not hid!",
+		       __func__, product, serial);
+	
+	if (info->vid != 0xFA04 || info->pid != 0x0011)
+		applogr(false, LOG_WARNING, "%s: Wrong VID/PID", __func__);
+	
+	h = hid_open_path(path);
+	if (!h)
+		applogr(false, LOG_WARNING, "%s: Failed to open HID path %s",
+		       __func__, path);
+	
+	if ((!hashbuster_io(h, buf, buf)) || buf[1] != 0x07)
+		applogr(false, LOG_DEBUG, "%s: Identify sequence didn't match on %s",
+		        __func__, path);
+	
+	struct spi_port spi = {
+		.txrx = hashbuster_spi_txrx,
+		.userp = h,
+		.repr = hashbuster_drv.dname,
+		.logprio = LOG_DEBUG,
+		.speed = 100000,
+		.mode = 0,
+	};
+	const int chip_n = libbitfury_detectChips1(&spi);
+	
+	hid_close(h);
+	
+	if (bfg_claim_hid(&hashbuster_drv, true, info->path))
+		return false;
+	
+	struct cgpu_info *cgpu;
+	cgpu = malloc(sizeof(*cgpu));
+	*cgpu = (struct cgpu_info){
+		.drv = &hashbuster_drv,
+		.device_data = info,
+		.threads = 1,
+		.procs = chip_n,
+		.device_path = strdup(info->path),
+		.dev_manufacturer = maybe_strdup(info->manufacturer),
+		.dev_product = maybe_strdup(product),
+		.dev_serial = maybe_strdup(serial),
+		.deven = DEV_ENABLED,
+	};
+
+	return add_cgpu(cgpu);
+}
+
+static bool hashbuster_detect_one(const char *serial)
+{
+	return lowlevel_detect_serial(hashbuster_foundlowl, serial);
+}
+
+static int hashbuster_detect_auto()
+{
+	return lowlevel_detect(hashbuster_foundlowl, HASHBUSTER_USB_PRODUCT);
+}
+
+static void hashbuster_detect()
+{
+	serial_detect_auto(&hashbuster_drv, hashbuster_detect_one, hashbuster_detect_auto);
+}
+
+static
+bool hashbuster_init(struct thr_info * const thr)
+{
+	struct cgpu_info * const cgpu = thr->cgpu, *proc;
+	struct bitfury_device *bitfury;
+	struct spi_port *port;
+	hid_device *h;
+	
+	h = hid_open_path(cgpu->device_path);
+	lowlevel_devinfo_free(cgpu->device_data);
+	
+	if (!h)
+		applogr(false, LOG_ERR, "%s: Failed to open hid device", cgpu->dev_repr);
+	
+	port = malloc(sizeof(*port));
+	if (!port)
+		applogr(false, LOG_ERR, "%s: Failed to allocate spi_port", cgpu->dev_repr);
+	*port = (struct spi_port){
+		.txrx = hashbuster_spi_txrx,
+		.userp = h,
+		.cgpu = cgpu,
+		.repr = cgpu->dev_repr,
+		.logprio = LOG_ERR,
+		.speed = 100000,
+		.mode = 0,
+	};
+	
+	for (proc = cgpu; proc; proc = proc->next_proc)
+	{
+		bitfury = malloc(sizeof(*bitfury));
+		
+		if (!bitfury)
+		{
+			applog(LOG_ERR, "%"PRIpreprv": Failed to allocate bitfury_device",
+			       cgpu->proc_repr);
+			proc->status = LIFE_DEAD2;
+			continue;
+		}
+		
+		*bitfury = (struct bitfury_device){
+			.spi = port,
+		};
+		proc->device_data = bitfury;
+		bitfury_init_chip(proc);
+		bitfury->osc6_bits = 53;
+		bitfury_send_reinit(bitfury->spi, bitfury->slot, bitfury->fasync, bitfury->osc6_bits);
+		bitfury_init_freq_stat(&bitfury->chip_stat, 52, 56);
+	}
+	
+	timer_set_now(&thr->tv_poll);
+	cgpu->status = LIFE_INIT2;
+	return true;
+}
+
+static
+bool hashbuster_get_stats(struct cgpu_info * const cgpu)
+{
+	struct cgpu_info *proc;
+	if (cgpu != cgpu->device)
+		return true;
+	
+	struct bitfury_device * const bitfury = cgpu->device_data;
+	struct spi_port * const spi = bitfury->spi;
+	hid_device * const h = spi->userp;
+	uint8_t buf[0x40] = {'\x04'};
+	if (!hashbuster_io(h, buf, buf))
+		return false;
+	if (buf[1])
+	{
+		for (proc = cgpu; proc; proc = proc->next_proc)
+			proc->temp = buf[1];
+	}
+	return true;
+}
+
+struct device_drv hashbuster_drv = {
+	.dname = "hashbuster",
+	.name = "HBR",
+	.drv_detect = hashbuster_detect,
+	
+	.thread_init = hashbuster_init,
+	
+	.minerloop = minerloop_async,
+	.job_prepare = bitfury_job_prepare,
+	.job_start = bitfury_noop_job_start,
+	.poll = bitfury_do_io,
+	.job_process_results = bitfury_job_process_results,
+	
+	.get_stats = hashbuster_get_stats,
+	
+	.get_api_extra_device_detail = bitfury_api_device_detail,
+	.get_api_extra_device_status = bitfury_api_device_status,
+	.set_device = bitfury_set_device,
+	
+#ifdef HAVE_CURSES
+	.proc_wlogprint_status = bitfury_wlogprint_status,
+	.proc_tui_wlogprint_choices = bitfury_tui_wlogprint_choices,
+	.proc_tui_handle_choice = bitfury_tui_handle_choice,
+#endif
+};

+ 3 - 2
driver-nanofury.c

@@ -169,8 +169,9 @@ bool nanofury_foundlowl(struct lowlevel_device_info * const info, __maybe_unused
 	
 	if (info->lowl != &lowl_mcp2210)
 	{
-		applog(LOG_WARNING, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not mcp2210!",
-		       __func__, product, serial);
+		if (info->lowl != &lowl_hid && info->lowl != &lowl_usb)
+			applog(LOG_WARNING, "%s: Matched \"%s\" serial \"%s\", but lowlevel driver is not mcp2210!",
+			       __func__, product, serial);
 		return false;
 	}
 	

+ 189 - 0
lowl-hid.c

@@ -0,0 +1,189 @@
+/*
+ * Copyright 2012-2013 Luke Dashjr
+ *
+ * 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"
+
+#ifndef WIN32
+#include <dlfcn.h>
+typedef void *dlh_t;
+#else
+#include <winsock2.h>
+#include <windows.h>
+#define dlopen(lib, flags) LoadLibrary(lib)
+#define dlsym(h, sym)  ((void*)GetProcAddress(h, sym))
+#define dlerror()  "unknown"
+#define dlclose(h)  FreeLibrary(h)
+typedef HMODULE dlh_t;
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <hidapi.h>
+#include <utlist.h>
+
+#include "logging.h"
+#include "lowlevel.h"
+#include "miner.h"
+
+struct hid_device_info HID_API_EXPORT *(*dlsym_hid_enumerate)(unsigned short, unsigned short);
+void HID_API_EXPORT (*dlsym_hid_free_enumeration)(struct hid_device_info *);
+hid_device * HID_API_EXPORT (*dlsym_hid_open_path)(const char *);
+void HID_API_EXPORT (*dlsym_hid_close)(hid_device *);
+int HID_API_EXPORT (*dlsym_hid_read)(hid_device *, unsigned char *, size_t);
+int HID_API_EXPORT (*dlsym_hid_write)(hid_device *, const unsigned char *, size_t);
+
+#define LOAD_SYM(sym)  do { \
+	if (!(dlsym_ ## sym = dlsym(dlh, #sym))) {  \
+		applog(LOG_DEBUG, "%s: Failed to load %s in %s", __func__, #sym, dlname);  \
+		goto fail;  \
+	}  \
+} while(0)
+
+static
+bool hidapi_try_lib(const char * const dlname)
+{
+	struct hid_device_info *hid_enum;
+	dlh_t dlh;
+	
+	dlh = dlopen(dlname, RTLD_NOW);
+	if (!dlh)
+	{
+		applog(LOG_DEBUG, "%s: Couldn't load %s: %s", __func__, dlname, dlerror());
+		return false;
+	}
+	
+	LOAD_SYM(hid_enumerate);
+	LOAD_SYM(hid_free_enumeration);
+	
+	hid_enum = dlsym_hid_enumerate(0, 0);
+	if (!hid_enum)
+	{
+		applog(LOG_DEBUG, "%s: Loaded %s, but no devices enumerated; trying other libraries", __func__, dlname);
+		goto fail;
+	}
+	dlsym_hid_free_enumeration(hid_enum);
+	
+	LOAD_SYM(hid_open_path);
+	LOAD_SYM(hid_close);
+	LOAD_SYM(hid_read);
+	LOAD_SYM(hid_write);
+	
+	applog(LOG_DEBUG, "%s: Successfully loaded %s", __func__, dlname);
+	
+	return true;
+
+fail:
+	dlclose(dlh);
+	return false;
+}
+
+// #defines hid_* calls, so must be after library loader
+#include "lowl-hid.h"
+
+static
+bool hidapi_load_library()
+{
+	if (dlsym_hid_write)
+		return true;
+	
+	const char **p;
+	char dlname[23] = "libhidapi";
+	const char *dltry[] = {
+		"",
+		"-0",
+		"-hidraw",
+		"-libusb",
+		NULL
+	};
+	for (p = &dltry[0]; *p; ++p)
+	{
+		sprintf(&dlname[9], "%s.%s", *p,
+#ifdef WIN32
+		        "dll"
+#else
+		        "so"
+#endif
+		);
+		if (hidapi_try_lib(dlname))
+			return true;
+	}
+	
+	return false;
+}
+
+static
+char *wcs2str_dup(wchar_t *ws)
+{
+	if (!(ws && ws[0]))
+		return NULL;
+	
+	char *rv;
+	int clen, i;
+	
+	clen = wcslen(ws);
+	++clen;
+	rv = malloc(clen);
+	for (i = 0; i < clen; ++i)
+		rv[i] = ws[i];
+	
+	return rv;
+}
+
+static
+struct lowlevel_device_info *hid_devinfo_scan()
+{
+	if (!hidapi_load_library())
+	{
+		applog(LOG_DEBUG, "%s: Failed to load any hidapi library", __func__);
+		return NULL;
+	}
+	
+	struct hid_device_info *hid_enum, *hid_item;
+	struct lowlevel_device_info *info, *devinfo_list = NULL;
+	
+	hid_enum = hid_enumerate(0, 0);
+	if (!hid_enum)
+	{
+		applog(LOG_DEBUG, "%s: No HID devices found", __func__);
+		return NULL;
+	}
+	
+	LL_FOREACH(hid_enum, hid_item)
+	{
+		info = malloc(sizeof(struct lowlevel_device_info));
+		char * const devid = malloc(4 + strlen(hid_item->path) + 1);
+		sprintf(devid, "hid:%s", hid_item->path);
+		*info = (struct lowlevel_device_info){
+			.lowl = &lowl_hid,
+			.path = strdup(hid_item->path),
+			.devid = devid,
+			.vid = hid_item->vendor_id,
+			.pid = hid_item->product_id,
+			.manufacturer = wcs2str_dup(hid_item->manufacturer_string),
+			.product = wcs2str_dup(hid_item->product_string),
+			.serial  = wcs2str_dup(hid_item->serial_number),
+		};
+		LL_PREPEND(devinfo_list, info);
+
+		applog(LOG_DEBUG, "%s: Found \"%s\" serial \"%s\"",
+		       __func__, info->product, info->serial);
+	}
+	
+	hid_free_enumeration(hid_enum);
+	
+	return devinfo_list;
+}
+
+struct lowlevel_driver lowl_hid = {
+	.dname = "hid",
+	.devinfo_scan = hid_devinfo_scan,
+};

+ 25 - 0
lowl-hid.h

@@ -0,0 +1,25 @@
+#ifndef BFG_LOWL_HID_H
+#define BFG_LOWL_HID_H
+
+#include <hidapi.h>
+
+#ifdef WIN32
+#define HID_API_EXPORT __declspec(dllexport)
+#else
+#define HID_API_EXPORT /* */
+#endif
+extern struct hid_device_info HID_API_EXPORT *(*dlsym_hid_enumerate)(unsigned short, unsigned short);
+extern void HID_API_EXPORT (*dlsym_hid_free_enumeration)(struct hid_device_info *);
+extern hid_device * HID_API_EXPORT (*dlsym_hid_open_path)(const char *);
+extern void HID_API_EXPORT (*dlsym_hid_close)(hid_device *);
+extern int HID_API_EXPORT (*dlsym_hid_read)(hid_device *, unsigned char *, size_t);
+extern int HID_API_EXPORT (*dlsym_hid_write)(hid_device *, const unsigned char *, size_t);
+
+#define hid_enumerate dlsym_hid_enumerate
+#define hid_free_enumeration dlsym_hid_free_enumeration
+#define hid_open_path dlsym_hid_open_path
+#define hid_close dlsym_hid_close
+#define hid_read dlsym_hid_read
+#define hid_write dlsym_hid_write
+
+#endif

+ 5 - 0
lowlevel.c

@@ -74,6 +74,11 @@ void lowlevel_scan()
 	LL_CONCAT(devinfo_list, devinfo_mid_list);
 #endif
 	
+#ifdef NEED_BFG_LOWL_HID
+	devinfo_mid_list = lowl_hid.devinfo_scan();
+	LL_CONCAT(devinfo_list, devinfo_mid_list);
+#endif
+	
 #ifdef USE_NANOFURY
 	devinfo_mid_list = lowl_mcp2210.devinfo_scan();
 	LL_CONCAT(devinfo_list, devinfo_mid_list);

+ 3 - 0
lowlevel.h

@@ -44,6 +44,9 @@ extern void lowlevel_devinfo_free(struct lowlevel_device_info *);
 #ifdef USE_X6500
 extern struct lowlevel_driver lowl_ft232r;
 #endif
+#ifdef NEED_BFG_LOWL_HID
+extern struct lowlevel_driver lowl_hid;
+#endif
 #ifdef USE_NANOFURY
 extern struct lowlevel_driver lowl_mcp2210;
 #endif

+ 11 - 141
mcp2210.c

@@ -27,11 +27,11 @@ typedef HMODULE dlh_t;
 #include <stdio.h>
 #include <stdlib.h>
 
-#include <hidapi.h>
 #include <utlist.h>
 
 #include "logging.h"
 #include "lowlevel.h"
+#include "lowl-hid.h"
 #include "miner.h"
 
 #include "mcp2210.h"
@@ -39,158 +39,28 @@ typedef HMODULE dlh_t;
 #define MCP2210_IDVENDOR   0x04d8
 #define MCP2210_IDPRODUCT  0x00de
 
-#ifdef WIN32
-#define HID_API_EXPORT __declspec(dllexport)
-#else
-#define HID_API_EXPORT /* */
-#endif
-struct hid_device_info HID_API_EXPORT *(*dlsym_hid_enumerate)(unsigned short, unsigned short);
-void HID_API_EXPORT (*dlsym_hid_free_enumeration)(struct hid_device_info *);
-hid_device * HID_API_EXPORT (*dlsym_hid_open_path)(const char *);
-void HID_API_EXPORT (*dlsym_hid_close)(hid_device *);
-int HID_API_EXPORT (*dlsym_hid_read)(hid_device *, unsigned char *, size_t);
-int HID_API_EXPORT (*dlsym_hid_write)(hid_device *, const unsigned char *, size_t);
-
-#define LOAD_SYM(sym)  do { \
-	if (!(dlsym_ ## sym = dlsym(dlh, #sym))) {  \
-		applog(LOG_DEBUG, "%s: Failed to load %s in %s", __func__, #sym, dlname);  \
-		goto fail;  \
-	}  \
-} while(0)
-
 static
-bool hidapi_try_lib(const char * const dlname)
+bool _mcp2210_devinfo_scan_cb(struct lowlevel_device_info * const usbinfo, void * const userp)
 {
-	struct hid_device_info *hid_enum;
-	dlh_t dlh;
-	
-	dlh = dlopen(dlname, RTLD_NOW);
-	if (!dlh)
-	{
-		applog(LOG_DEBUG, "%s: Couldn't load %s: %s", __func__, dlname, dlerror());
-		return false;
-	}
-	
-	LOAD_SYM(hid_enumerate);
-	LOAD_SYM(hid_free_enumeration);
-	
-	hid_enum = dlsym_hid_enumerate(0, 0);
-	if (!hid_enum)
-	{
-		applog(LOG_DEBUG, "%s: Loaded %s, but no devices enumerated; trying other libraries", __func__, dlname);
-		goto fail;
-	}
-	dlsym_hid_free_enumeration(hid_enum);
+	struct lowlevel_device_info **devinfo_list_p = userp, *info;
 	
-	LOAD_SYM(hid_open_path);
-	LOAD_SYM(hid_close);
-	LOAD_SYM(hid_read);
-	LOAD_SYM(hid_write);
-	
-	applog(LOG_DEBUG, "%s: Successfully loaded %s", __func__, dlname);
-	
-	return true;
-
-fail:
-	dlclose(dlh);
-	return false;
-}
-
-#define hid_enumerate dlsym_hid_enumerate
-#define hid_free_enumeration dlsym_hid_free_enumeration
-#define hid_open_path dlsym_hid_open_path
-#define hid_close dlsym_hid_close
-#define hid_read dlsym_hid_read
-#define hid_write dlsym_hid_write
-
-static
-bool hidapi_load_library()
-{
-	if (dlsym_hid_write)
-		return true;
-	
-	const char **p;
-	char dlname[23] = "libhidapi";
-	const char *dltry[] = {
-		"",
-		"-0",
-		"-hidraw",
-		"-libusb",
-		NULL
+	info = malloc(sizeof(*info));
+	*info = (struct lowlevel_device_info){
+		.lowl = &lowl_mcp2210,
 	};
-	for (p = &dltry[0]; *p; ++p)
-	{
-		sprintf(&dlname[9], "%s.%s", *p,
-#ifdef WIN32
-		        "dll"
-#else
-		        "so"
-#endif
-		);
-		if (hidapi_try_lib(dlname))
-			return true;
-	}
+	lowlevel_devinfo_semicpy(info, usbinfo);
+	LL_PREPEND(*devinfo_list_p, info);
 	
+	// Never *consume* the lowl_usb entry - especially since this is during the scan!
 	return false;
 }
 
-static
-char *wcs2str_dup(wchar_t *ws)
-{
-	if (!ws)
-		return NULL;
-	
-	char *rv;
-	int clen, i;
-	
-	clen = wcslen(ws);
-	++clen;
-	rv = malloc(clen);
-	for (i = 0; i < clen; ++i)
-		rv[i] = ws[i];
-	
-	return rv;
-}
-
 static
 struct lowlevel_device_info *mcp2210_devinfo_scan()
 {
-	if (!hidapi_load_library())
-	{
-		applog(LOG_DEBUG, "%s: Failed to load any hidapi library", __func__);
-		return NULL;
-	}
-	
-	struct hid_device_info *hid_enum, *hid_item;
-	struct lowlevel_device_info *info, *devinfo_list = NULL;
-	
-	hid_enum = hid_enumerate(MCP2210_IDVENDOR, MCP2210_IDPRODUCT);
-	if (!hid_enum)
-	{
-		applog(LOG_DEBUG, "%s: No MCP2210 devices found", __func__);
-		return NULL;
-	}
-	
-	LL_FOREACH(hid_enum, hid_item)
-	{
-		info = malloc(sizeof(struct lowlevel_device_info));
-		char * const devid = malloc(4 + strlen(hid_item->path) + 1);
-		sprintf(devid, "hid:%s", hid_item->path);
-		*info = (struct lowlevel_device_info){
-			.lowl = &lowl_mcp2210,
-			.path = strdup(hid_item->path),
-			.devid = devid,
-			.manufacturer = wcs2str_dup(hid_item->manufacturer_string),
-			.product = wcs2str_dup(hid_item->product_string),
-			.serial  = wcs2str_dup(hid_item->serial_number),
-		};
-		LL_PREPEND(devinfo_list, info);
-
-		applog(LOG_DEBUG, "%s: Found \"%s\" serial \"%s\"",
-		       __func__, info->product, info->serial);
-	}
+	struct lowlevel_device_info *devinfo_list = NULL;
 	
-	hid_free_enumeration(hid_enum);
+	lowlevel_detect_id(_mcp2210_devinfo_scan_cb, &devinfo_list, &lowl_hid, MCP2210_IDVENDOR, MCP2210_IDPRODUCT);
 	
 	return devinfo_list;
 }

+ 1 - 0
spidevc.h

@@ -17,6 +17,7 @@ struct spi_port {
 	char spibuf[SPIMAXSZ], spibuf_rx[SPIMAXSZ];
 	size_t spibufsz;
 	
+	void *userp;
 	struct cgpu_info *cgpu;
 	const char *repr;
 	int logprio;