1
0
mirror of https://github.com/GOSTSec/sgminer synced 2025-01-11 07:17:58 +00:00

Merge branch 'bfl'

This commit is contained in:
Kano 2013-01-03 21:47:41 +11:00
commit e3db37a64e
9 changed files with 510 additions and 367 deletions

View File

@ -2,15 +2,8 @@
This README contains extended details about FPGA mining with cgminer This README contains extended details about FPGA mining with cgminer
ModMinerQuad (MMQ) For ModMinerQuad (MMQ) and BitForce (BFL)
------------------ -----------------------------------------
The mining bitstream does not survive a power cycle, so cgminer will upload
it, if it needs to, before it starts mining (approx 7min 40sec)
The red LED also flashes while it is uploading the bitstream
-
When mining on windows, the driver being used will determine if mining will work. When mining on windows, the driver being used will determine if mining will work.
@ -39,7 +32,17 @@ problems:
--usb-dump 0 --usb-dump 0
It will only help if you have a working MMQ device attached to the computer It will only help if you have a working MMQ or BFL device attached to the
computer
ModMinerQuad (MMQ)
------------------
The mining bitstream does not survive a power cycle, so cgminer will upload
it, if it needs to, before it starts mining (approx 7min 40sec)
The red LED also flashes while it is uploading the bitstream
- -
@ -130,7 +133,7 @@ modem-manager software
TODO: check that all MMQ's have the same product ID TODO: check that all MMQ's have the same product ID
Bitforce (BFL) BitForce (BFL)
-------------- --------------
--bfl-range Use nonce range on bitforce devices if supported --bfl-range Use nonce range on bitforce devices if supported

View File

@ -82,6 +82,10 @@ if NEED_FPGAUTILS
cgminer_SOURCES += fpgautils.c fpgautils.h cgminer_SOURCES += fpgautils.c fpgautils.h
endif endif
if NEED_USBUTILS_C
cgminer_SOURCES += usbutils.c
endif
if HAS_BITFORCE if HAS_BITFORCE
cgminer_SOURCES += driver-bitforce.c cgminer_SOURCES += driver-bitforce.c
endif endif
@ -91,7 +95,7 @@ cgminer_SOURCES += driver-icarus.c
endif endif
if HAS_MODMINER if HAS_MODMINER
cgminer_SOURCES += driver-modminer.c usbutils.c cgminer_SOURCES += driver-modminer.c
bitstreamsdir = $(bindir)/bitstreams bitstreamsdir = $(bindir)/bitstreams
dist_bitstreams_DATA = bitstreams/* dist_bitstreams_DATA = bitstreams/*
endif endif

18
README
View File

@ -220,15 +220,16 @@ SCRYPT only options:
See SCRYPT-README for more information regarding litecoin mining. See SCRYPT-README for more information regarding litecoin mining.
FPGA mining boards(BitForce, Icarus, ModMiner, Ztex) only options: FPGA mining boards (BitForce, Icarus, ModMiner, Ztex) only options:
cgminer will automatically find your ModMiner or Ztex FPGAs cgminer will automatically find your ModMiner, BitForce or Ztex FPGAs
independent of the --scan-serial options specified below
--scan-serial|-S <arg> Serial port to probe for FPGA mining device --scan-serial|-S <arg> Serial port to probe for Icarus mining device
This option is only for BitForce and/or Icarus FPGAs This option is only for Icarus bitstream FPGAs
By default, cgminer will scan for autodetected FPGAs unless at least one By default, cgminer will scan for autodetected Icarus unless at least one
-S is specified for that driver. If you specify -S and still want cgminer -S is specified for that driver. If you specify -S and still want cgminer
to scan, you must also use "-S auto". If you want to prevent cgminer from to scan, you must also use "-S auto". If you want to prevent cgminer from
scanning without specifying a device, you can use "-S noauto". Note that scanning without specifying a device, you can use "-S noauto". Note that
@ -237,13 +238,14 @@ device depending on the version of udev being used.
On linux <arg> is usually of the format /dev/ttyUSBn On linux <arg> is usually of the format /dev/ttyUSBn
On windows <arg> is usually of the format \\.\COMn On windows <arg> is usually of the format \\.\COMn
(where n = the correct device number for the FPGA device) (where n = the correct device number for the Icarus device)
The official supplied binaries are compiled with support for all FPGAs. The official supplied binaries are compiled with support for all FPGAs.
To force the code to only attempt detection with a specific driver, To force the code to only attempt detection with a specific driver,
prepend the argument with the driver name followed by a colon. prepend the argument with the driver name followed by a colon.
For example, "icarus:/dev/ttyUSB0" or "bitforce:\\.\COM5" For example, "icarus:/dev/ttyUSB0" or using the short name: "ica:/dev/ttyUSB0"
or using the short name: "ica:/dev/ttyUSB0" or "bfl:\\.\COM5" This option not longer matters since Icarus is the only serial-USB
device that uses it
For other FPGA details see the FPGA-README For other FPGA details see the FPGA-README

4
api.c
View File

@ -3120,7 +3120,7 @@ static void usbstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __may
{ {
struct api_data *root = NULL; struct api_data *root = NULL;
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
char buf[TMPBUFSIZ]; char buf[TMPBUFSIZ];
bool io_open = false; bool io_open = false;
int count = 0; int count = 0;
@ -3133,7 +3133,7 @@ static void usbstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __may
return; return;
} }
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
message(io_data, MSG_USBSTA, 0, NULL, isjson); message(io_data, MSG_USBSTA, 0, NULL, isjson);

View File

@ -273,6 +273,7 @@ fi
AM_CONDITIONAL([NEED_FPGAUTILS], [test x$icarus$bitforce$modminer$ztex != xnononono]) AM_CONDITIONAL([NEED_FPGAUTILS], [test x$icarus$bitforce$modminer$ztex != xnononono])
AM_CONDITIONAL([NEED_USBUTILS_C], [test x$bitforce$modminer != xnono])
AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes]) AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes])
AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue]) AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue])
AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue]) AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue])
@ -321,7 +322,7 @@ fi
AM_CONDITIONAL([HAS_YASM], [test x$has_yasm = xtrue]) AM_CONDITIONAL([HAS_YASM], [test x$has_yasm = xtrue])
if test "x$bitforce" != xno; then if test "x$icarus" != xno; then
AC_ARG_WITH([libudev], [AC_HELP_STRING([--without-libudev], [Autodetect FPGAs using libudev (default enabled)])], AC_ARG_WITH([libudev], [AC_HELP_STRING([--without-libudev], [Autodetect FPGAs using libudev (default enabled)])],
[libudev=$withval], [libudev=$withval],
[libudev=auto] [libudev=auto]
@ -343,7 +344,7 @@ AM_CONDITIONAL([HAVE_LIBUDEV], [test x$libudev != xno])
PKG_PROG_PKG_CONFIG() PKG_PROG_PKG_CONFIG()
if test "x$ztex$modminer" != xnono; then if test "x$ztex$modminer$bitforce" != xnonono; then
case $target in case $target in
*-*-freebsd*) *-*-freebsd*)
LIBUSB_LIBS="-lusb" LIBUSB_LIBS="-lusb"
@ -508,7 +509,7 @@ else
echo " Ztex.FPGAs...........: Disabled" echo " Ztex.FPGAs...........: Disabled"
fi fi
if test "x$bitforce" != xno; then if test "x$icarus" != xno; then
echo " libudev.detection....: $libudev" echo " libudev.detection....: $libudev"
fi fi

View File

@ -1,4 +1,5 @@
/* /*
* Copyright 2012 Andrew Smith
* Copyright 2012 Luke Dashjr * Copyright 2012 Luke Dashjr
* Copyright 2012 Con Kolivas * Copyright 2012 Con Kolivas
* *
@ -19,34 +20,25 @@
#include "config.h" #include "config.h"
#ifdef WIN32 #ifdef WIN32
#include <windows.h> #include <windows.h>
#define dlsym (void*)GetProcAddress
#define dlclose FreeLibrary
typedef unsigned long FT_STATUS;
typedef PVOID FT_HANDLE;
__stdcall FT_STATUS (*FT_ListDevices)(PVOID pArg1, PVOID pArg2, DWORD Flags);
__stdcall FT_STATUS (*FT_Open)(int idx, FT_HANDLE*);
__stdcall FT_STATUS (*FT_GetComPortNumber)(FT_HANDLE, LPLONG lplComPortNumber);
__stdcall FT_STATUS (*FT_Close)(FT_HANDLE);
const uint32_t FT_OPEN_BY_DESCRIPTION = 2;
const uint32_t FT_LIST_ALL = 0x20000000;
const uint32_t FT_LIST_NUMBER_ONLY = 0x80000000;
enum {
FT_OK,
};
// Code must deal with a timeout. Make it 1 second on windows, 0.1 on linux.
#define BFopen(devpath) serial_open(devpath, 0, 10, true)
#else /* WIN32 */
#define BFopen(devpath) serial_open(devpath, 0, 1, true)
#endif /* WIN32 */ #endif /* WIN32 */
#include "compat.h" #include "compat.h"
#include "miner.h" #include "miner.h"
#include "fpgautils.h" #include "usbutils.h"
#define BITFORCE_IDENTIFY "ZGX"
#define BITFORCE_IDENTIFY_LEN (sizeof(BITFORCE_IDENTIFY)-1)
#define BITFORCE_FLASH "ZMX"
#define BITFORCE_FLASH_LEN (sizeof(BITFORCE_FLASH)-1)
#define BITFORCE_TEMPERATURE "ZLX"
#define BITFORCE_TEMPERATURE_LEN (sizeof(BITFORCE_TEMPERATURE)-1)
#define BITFORCE_SENDRANGE "ZPX"
#define BITFORCE_SENDRANGE_LEN (sizeof(BITFORCE_SENDRANGE)-1)
#define BITFORCE_SENDWORK "ZDX"
#define BITFORCE_SENDWORK_LEN (sizeof(BITFORCE_SENDWORK)-1)
#define BITFORCE_WORKSTATUS "ZFX"
#define BITFORCE_WORKSTATUS_LEN (sizeof(BITFORCE_WORKSTATUS)-1)
#define BITFORCE_SLEEP_MS 500 #define BITFORCE_SLEEP_MS 500
#define BITFORCE_TIMEOUT_S 7 #define BITFORCE_TIMEOUT_S 7
@ -62,62 +54,159 @@ enum {
#define KNAME_WORK "full work" #define KNAME_WORK "full work"
#define KNAME_RANGE "nonce range" #define KNAME_RANGE "nonce range"
#define BITFORCE_BUFSIZ (0x200)
// If initialisation fails the first time,
// sleep this amount (ms) and try again
#define REINIT_TIME_MS 1000
// But try this many times
#define REINIT_COUNT 6
static const char *blank = "";
struct device_api bitforce_api; struct device_api bitforce_api;
static void BFgets(char *buf, size_t bufLen, int fd) static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
{ {
do { int err;
buf[0] = '\0';
--bufLen;
} while (likely(bufLen && read(fd, buf, 1) == 1 && (buf++)[0] != '\n'));
buf[0] = '\0'; if (lock)
mutex_lock(&bitforce->device_mutex);
// Reset
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
FTDI_VALUE_RESET, bitforce->usbdev->found->interface, C_RESET);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: reset got err %d",
bitforce->api->name, bitforce->device_id, err);
// Set data control
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_DATA,
FTDI_VALUE_DATA, bitforce->usbdev->found->interface, C_SETDATA);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: setdata got err %d",
bitforce->api->name, bitforce->device_id, err);
// Set the baud
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_BAUD, FTDI_VALUE_BAUD,
(FTDI_INDEX_BAUD & 0xff00) | bitforce->usbdev->found->interface,
C_SETBAUD);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: setbaud got err %d",
bitforce->api->name, bitforce->device_id, err);
// Set Flow Control
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_FLOW,
FTDI_VALUE_FLOW, bitforce->usbdev->found->interface, C_SETFLOW);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: setflowctrl got err %d",
bitforce->api->name, bitforce->device_id, err);
// Set Modem Control
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_MODEM,
FTDI_VALUE_MODEM, bitforce->usbdev->found->interface, C_SETMODEM);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: setmodemctrl got err %d",
bitforce->api->name, bitforce->device_id, err);
// Clear any sent data
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
FTDI_VALUE_PURGE_TX, bitforce->usbdev->found->interface, C_PURGETX);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: purgetx got err %d",
bitforce->api->name, bitforce->device_id, err);
// Clear any received data
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
FTDI_VALUE_PURGE_RX, bitforce->usbdev->found->interface, C_PURGERX);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: purgerx got err %d",
bitforce->api->name, bitforce->device_id, err);
if (lock)
mutex_unlock(&bitforce->device_mutex);
} }
static ssize_t BFwrite(int fd, const void *buf, ssize_t bufLen) static bool bitforce_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
{ {
if ((bufLen) != write(fd, buf, bufLen)) char buf[BITFORCE_BUFSIZ+1];
return 0; char devpath[20];
else int err, amount;
return bufLen;
}
#define BFclose(fd) close(fd)
static bool bitforce_detect_one(const char *devpath)
{
int fdDev = BFopen(devpath);
struct cgpu_info *bitforce;
char pdevbuf[0x100];
char *s; char *s;
applog(LOG_DEBUG, "BFL: Attempting to open %s", devpath); struct cgpu_info *bitforce = NULL;
bitforce = calloc(1, sizeof(*bitforce));
bitforce->api = &bitforce_api;
bitforce->deven = DEV_ENABLED;
bitforce->threads = 1;
if (unlikely(fdDev == -1)) { if (!usb_init(bitforce, dev, found)) {
applog(LOG_ERR, "BFL: Failed to open %s", devpath); applog(LOG_ERR, "%s detect (%d:%d) failed to initialise (incorrect device?)",
return false; bitforce->api->dname,
(int)libusb_get_bus_number(dev),
(int)libusb_get_device_address(dev));
goto shin;
} }
BFwrite(fdDev, "ZGX", 3); sprintf(devpath, "%d:%d",
pdevbuf[0] = '\0'; (int)(bitforce->usbdev->bus_number),
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); (int)(bitforce->usbdev->device_address));
if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "BFL: Error reading/timeout (ZGX)"); int init_count = 0;
return 0; reinit:
bitforce_initialise(bitforce, false);
if ((err = usb_write(bitforce, BITFORCE_IDENTIFY, BITFORCE_IDENTIFY_LEN, &amount, C_REQUESTIDENTIFY)) < 0 || amount != BITFORCE_IDENTIFY_LEN) {
applog(LOG_ERR, "%s detect (%s) send identify request failed (%d:%d)",
bitforce->api->dname, devpath, amount, err);
goto unshin;
} }
BFclose(fdDev); if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETIDENTIFY)) < 0 || amount < 1) {
if (unlikely(!strstr(pdevbuf, "SHA256"))) { // Maybe it was still processing previous work?
applog(LOG_ERR, "BFL: Didn't recognise BitForce on %s", devpath); if (++init_count <= REINIT_COUNT) {
return false; if (init_count < 2) {
applog(LOG_WARNING, "%s detect (%s) 1st init failed - retrying (%d:%d)",
bitforce->api->dname, devpath, amount, err);
}
nmsleep(REINIT_TIME_MS);
goto reinit;
}
if (init_count > 0)
applog(LOG_WARNING, "%s detect (%s) init failed %d times",
bitforce->api->dname, devpath, init_count);
if (err < 0) {
applog(LOG_ERR, "%s detect (%s) error identify reply (%d:%d)",
bitforce->api->dname, devpath, amount, err);
} else {
applog(LOG_ERR, "%s detect (%s) empty identify reply (%d)",
bitforce->api->dname, devpath, amount);
}
goto unshin;
}
buf[amount] = '\0';
if (unlikely(!strstr(buf, "SHA256"))) {
applog(LOG_ERR, "%s detect (%s) didn't recognise '%s'",
bitforce->api->dname, devpath, buf);
goto unshin;
}
if (likely((!memcmp(buf, ">>>ID: ", 7)) && (s = strstr(buf + 3, ">>>")))) {
s[0] = '\0';
bitforce->name = strdup(buf + 7);
} else {
bitforce->name = (char *)blank;
} }
// We have a real BitForce! // We have a real BitForce!
bitforce = calloc(1, sizeof(*bitforce)); applog(LOG_DEBUG, "%s (%s) identified as: '%s'",
bitforce->api = &bitforce_api; bitforce->api->dname, devpath, bitforce->name);
bitforce->device_path = strdup(devpath);
bitforce->deven = DEV_ENABLED;
bitforce->threads = 1;
/* Initially enable support for nonce range and disable it later if it /* Initially enable support for nonce range and disable it later if it
* fails */ * fails */
if (opt_bfl_noncerange) { if (opt_bfl_noncerange) {
@ -129,108 +218,36 @@ static bool bitforce_detect_one(const char *devpath)
bitforce->kname = KNAME_WORK; bitforce->kname = KNAME_WORK;
} }
if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) { bitforce->device_path = strdup(devpath);
s[0] = '\0';
bitforce->name = strdup(pdevbuf + 7); if (!add_cgpu(bitforce))
} goto unshin;
update_usb_stats(bitforce);
mutex_init(&bitforce->device_mutex); mutex_init(&bitforce->device_mutex);
return add_cgpu(bitforce); return true;
}
#define LOAD_SYM(sym) do { \ unshin:
if (!(sym = dlsym(dll, #sym))) { \
applog(LOG_DEBUG, "Failed to load " #sym ", not using FTDI bitforce autodetect"); \
goto out; \
} \
} while(0)
#ifdef WIN32 usb_uninit(bitforce);
static int bitforce_autodetect_ftdi(void)
{
char devpath[] = "\\\\.\\COMnnnnn";
char *devpathnum = &devpath[7];
char **bufptrs;
char *buf;
int found = 0;
DWORD i;
FT_STATUS ftStatus; shin:
DWORD numDevs;
HMODULE dll = LoadLibrary("FTD2XX.DLL");
if (!dll) {
applog(LOG_DEBUG, "FTD2XX.DLL failed to load, not using FTDI bitforce autodetect");
return 0;
}
LOAD_SYM(FT_ListDevices);
LOAD_SYM(FT_Open);
LOAD_SYM(FT_GetComPortNumber);
LOAD_SYM(FT_Close);
ftStatus = FT_ListDevices(&numDevs, NULL, FT_LIST_NUMBER_ONLY);
if (ftStatus != FT_OK) {
applog(LOG_DEBUG, "FTDI device count failed, not using FTDI bitforce autodetect");
goto out;
}
applog(LOG_DEBUG, "FTDI reports %u devices", (unsigned)numDevs);
buf = alloca(65 * numDevs); free(bitforce->device_path);
bufptrs = alloca(sizeof(*bufptrs) * (numDevs + 1));
for (i = 0; i < numDevs; ++i) if (bitforce->name != blank)
bufptrs[i] = &buf[i * 65]; free(bitforce->name);
bufptrs[numDevs] = NULL;
ftStatus = FT_ListDevices(bufptrs, &numDevs, FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION);
if (ftStatus != FT_OK) {
applog(LOG_DEBUG, "FTDI device list failed, not using FTDI bitforce autodetect");
goto out;
}
for (i = numDevs; i > 0; ) {
--i;
bufptrs[i][64] = '\0';
if (!(strstr(bufptrs[i], "BitFORCE") && strstr(bufptrs[i], "SHA256")))
continue;
FT_HANDLE ftHandle;
if (FT_OK != FT_Open(i, &ftHandle))
continue;
LONG lComPortNumber;
ftStatus = FT_GetComPortNumber(ftHandle, &lComPortNumber);
FT_Close(ftHandle);
if (FT_OK != ftStatus || lComPortNumber < 0)
continue;
sprintf(devpathnum, "%d", (int)lComPortNumber);
if (bitforce_detect_one(devpath))
++found;
}
out: free(bitforce);
dlclose(dll);
return found;
}
#else
static int bitforce_autodetect_ftdi(void)
{
return 0;
}
#endif
static int bitforce_detect_auto(void) return false;
{
return (serial_autodetect_udev (bitforce_detect_one, "BitFORCE*SHA256") ?:
serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?:
bitforce_autodetect_ftdi() ?:
0);
} }
static void bitforce_detect(void) static void bitforce_detect(void)
{ {
serial_detect_auto(&bitforce_api, bitforce_detect_one, bitforce_detect_auto); usb_detect(&bitforce_api, bitforce_detect_one);
} }
static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce) static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
@ -247,105 +264,17 @@ static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
static bool bitforce_thread_prepare(struct thr_info *thr) static bool bitforce_thread_prepare(struct thr_info *thr)
{ {
struct cgpu_info *bitforce = thr->cgpu; struct cgpu_info *bitforce = thr->cgpu;
int fdDev = BFopen(bitforce->device_path);
struct timeval now; struct timeval now;
if (unlikely(fdDev == -1)) {
applog(LOG_ERR, "BFL%i: Failed to open %s", bitforce->device_id, bitforce->device_path);
return false;
}
bitforce->device_fd = fdDev;
applog(LOG_INFO, "BFL%i: Opened %s", bitforce->device_id, bitforce->device_path);
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
get_datestamp(bitforce->init, &now); get_datestamp(bitforce->init, &now);
return true; return true;
} }
static void bitforce_clear_buffer(struct cgpu_info *bitforce)
{
int fdDev = bitforce->device_fd;
char pdevbuf[0x100];
int count = 0;
if (!fdDev)
return;
applog(LOG_DEBUG, "BFL%i: Clearing read buffer", bitforce->device_id);
mutex_lock(&bitforce->device_mutex);
do {
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
} while (pdevbuf[0] && (++count < 10));
mutex_unlock(&bitforce->device_mutex);
}
void bitforce_init(struct cgpu_info *bitforce)
{
char *devpath = bitforce->device_path;
int fdDev = bitforce->device_fd, retries = 0;
char pdevbuf[0x100];
char *s;
applog(LOG_WARNING, "BFL%i: Re-initialising", bitforce->device_id);
bitforce_clear_buffer(bitforce);
mutex_lock(&bitforce->device_mutex);
if (fdDev) {
BFclose(fdDev);
sleep(5);
}
bitforce->device_fd = 0;
fdDev = BFopen(devpath);
if (unlikely(fdDev == -1)) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "BFL%i: Failed to open %s", bitforce->device_id, devpath);
return;
}
do {
BFwrite(fdDev, "ZGX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (unlikely(!pdevbuf[0])) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "BFL%i: Error reading/timeout (ZGX)", bitforce->device_id);
return;
}
if (retries++)
nmsleep(10);
} while (!strstr(pdevbuf, "BUSY") && (retries * 10 < BITFORCE_TIMEOUT_MS));
if (unlikely(!strstr(pdevbuf, "SHA256"))) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "BFL%i: Didn't recognise BitForce on %s returned: %s", bitforce->device_id, devpath, pdevbuf);
return;
}
if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
s[0] = '\0';
bitforce->name = strdup(pdevbuf + 7);
}
bitforce->device_fd = fdDev;
bitforce->sleep_ms = BITFORCE_SLEEP_MS;
mutex_unlock(&bitforce->device_mutex);
}
static void bitforce_flash_led(struct cgpu_info *bitforce) static void bitforce_flash_led(struct cgpu_info *bitforce)
{ {
int fdDev = bitforce->device_fd; int err, amount;
if (!fdDev)
return;
/* Do not try to flash the led if we're polling for a result to /* Do not try to flash the led if we're polling for a result to
* minimise the chance of interleaved results */ * minimise the chance of interleaved results */
@ -353,19 +282,22 @@ static void bitforce_flash_led(struct cgpu_info *bitforce)
return; return;
/* It is not critical flashing the led so don't get stuck if we /* It is not critical flashing the led so don't get stuck if we
* can't grab the mutex here */ * can't grab the mutex now */
if (mutex_trylock(&bitforce->device_mutex)) if (mutex_trylock(&bitforce->device_mutex))
return; return;
BFwrite(fdDev, "ZMX", 3); if ((err = usb_write(bitforce, BITFORCE_FLASH, BITFORCE_FLASH_LEN, &amount, C_REQUESTFLASH)) < 0 || amount != BITFORCE_FLASH_LEN) {
applog(LOG_ERR, "%s%i: flash request failed (%d:%d)",
bitforce->api->name, bitforce->device_id, amount, err);
} else {
/* However, this stops anything else getting a reply
* So best to delay any other access to the BFL */
sleep(4);
}
/* Once we've tried - don't do it until told to again */ /* Once we've tried - don't do it until told to again */
bitforce->flash_led = false; bitforce->flash_led = false;
/* However, this stops anything else getting a reply
* So best to delay any other access to the BFL */
sleep(4);
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
return; // nothing is returned by the BFL return; // nothing is returned by the BFL
@ -373,13 +305,10 @@ static void bitforce_flash_led(struct cgpu_info *bitforce)
static bool bitforce_get_temp(struct cgpu_info *bitforce) static bool bitforce_get_temp(struct cgpu_info *bitforce)
{ {
int fdDev = bitforce->device_fd; char buf[BITFORCE_BUFSIZ+1];
char pdevbuf[0x100]; int err, amount;
char *s; char *s;
if (!fdDev)
return false;
/* Do not try to get the temperature if we're polling for a result to /* Do not try to get the temperature if we're polling for a result to
* minimise the chance of interleaved results */ * minimise the chance of interleaved results */
if (bitforce->polling) if (bitforce->polling)
@ -396,18 +325,30 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
if (mutex_trylock(&bitforce->device_mutex)) if (mutex_trylock(&bitforce->device_mutex))
return false; return false;
BFwrite(fdDev, "ZLX", 3); if ((err = usb_write(bitforce, BITFORCE_TEMPERATURE, BITFORCE_TEMPERATURE_LEN, &amount, C_REQUESTTEMPERATURE)) < 0 || amount != BITFORCE_TEMPERATURE_LEN) {
pdevbuf[0] = '\0'; mutex_unlock(&bitforce->device_mutex);
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); applog(LOG_ERR, "%s%i: Error: Request temp invalid/timed out (%d:%d)",
mutex_unlock(&bitforce->device_mutex); bitforce->api->name, bitforce->device_id, amount, err);
if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "BFL%i: Error: Get temp returned empty string/timed out", bitforce->device_id);
bitforce->hw_errors++; bitforce->hw_errors++;
return false; return false;
} }
if ((!strncasecmp(pdevbuf, "TEMP", 4)) && (s = strchr(pdevbuf + 4, ':'))) { if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETTEMPERATURE)) < 0 || amount < 1) {
mutex_unlock(&bitforce->device_mutex);
if (err < 0) {
applog(LOG_ERR, "%s%i: Error: Get temp return invalid/timed out (%d:%d)",
bitforce->api->name, bitforce->device_id, amount, err);
} else {
applog(LOG_ERR, "%s%i: Error: Get temp returned nothing (%d:%d)",
bitforce->api->name, bitforce->device_id, amount, err);
}
bitforce->hw_errors++;
return false;
}
mutex_unlock(&bitforce->device_mutex);
if ((!strncasecmp(buf, "TEMP", 4)) && (s = strchr(buf + 4, ':'))) {
float temp = strtof(s + 1, NULL); float temp = strtof(s + 1, NULL);
/* Cope with older software that breaks and reads nonsense /* Cope with older software that breaks and reads nonsense
@ -418,7 +359,8 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
if (temp > 0) { if (temp > 0) {
bitforce->temp = temp; bitforce->temp = temp;
if (unlikely(bitforce->cutofftemp > 0 && temp > bitforce->cutofftemp)) { if (unlikely(bitforce->cutofftemp > 0 && temp > bitforce->cutofftemp)) {
applog(LOG_WARNING, "BFL%i: Hit thermal cutoff limit, disabling!", bitforce->device_id); applog(LOG_WARNING, "%s%i: Hit thermal cutoff limit, disabling!",
bitforce->api->name, bitforce->device_id);
bitforce->deven = DEV_RECOVER; bitforce->deven = DEV_RECOVER;
dev_error(bitforce, REASON_DEV_THERMAL_CUTOFF); dev_error(bitforce, REASON_DEV_THERMAL_CUTOFF);
} }
@ -427,11 +369,12 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
/* Use the temperature monitor as a kind of watchdog for when /* Use the temperature monitor as a kind of watchdog for when
* our responses are out of sync and flush the buffer to * our responses are out of sync and flush the buffer to
* hopefully recover */ * hopefully recover */
applog(LOG_WARNING, "BFL%i: Garbled response probably throttling, clearing buffer", bitforce->device_id); applog(LOG_WARNING, "%s%i: Garbled response probably throttling, clearing buffer",
bitforce->api->name, bitforce->device_id);
dev_error(bitforce, REASON_DEV_THROTTLE); dev_error(bitforce, REASON_DEV_THROTTLE);
/* Count throttling episodes as hardware errors */ /* Count throttling episodes as hardware errors */
bitforce->hw_errors++; bitforce->hw_errors++;
bitforce_clear_buffer(bitforce); bitforce_initialise(bitforce, true);
return false; return false;
} }
@ -441,35 +384,53 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
static bool bitforce_send_work(struct thr_info *thr, struct work *work) static bool bitforce_send_work(struct thr_info *thr, struct work *work)
{ {
struct cgpu_info *bitforce = thr->cgpu; struct cgpu_info *bitforce = thr->cgpu;
int fdDev = bitforce->device_fd;
unsigned char ob[70]; unsigned char ob[70];
char pdevbuf[0x100]; char buf[BITFORCE_BUFSIZ+1];
int err, amount;
char *s; char *s;
char *cmd;
int len;
if (!fdDev)
return false;
re_send: re_send:
if (bitforce->nonce_range) {
cmd = BITFORCE_SENDRANGE;
len = BITFORCE_SENDRANGE_LEN;
} else {
cmd = BITFORCE_SENDWORK;
len = BITFORCE_SENDWORK_LEN;
}
mutex_lock(&bitforce->device_mutex); mutex_lock(&bitforce->device_mutex);
if (bitforce->nonce_range) if ((err = usb_write(bitforce, cmd, len, &amount, C_REQUESTSENDWORK)) < 0 || amount != len) {
BFwrite(fdDev, "ZPX", 3); mutex_unlock(&bitforce->device_mutex);
else applog(LOG_ERR, "%s%i: request send work failed (%d:%d)",
BFwrite(fdDev, "ZDX", 3); bitforce->api->name, bitforce->device_id, amount, err);
pdevbuf[0] = '\0'; return false;
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); }
if (!pdevbuf[0] || !strncasecmp(pdevbuf, "B", 1)) {
if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_REQUESTSENDWORKSTATUS)) < 0) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "%s%d: read request send work status failed (%d:%d)",
bitforce->api->name, bitforce->device_id, amount, err);
return false;
}
if (amount == 0 || !buf[0] || !strncasecmp(buf, "B", 1)) {
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
nmsleep(WORK_CHECK_INTERVAL_MS); nmsleep(WORK_CHECK_INTERVAL_MS);
goto re_send; goto re_send;
} else if (unlikely(strncasecmp(pdevbuf, "OK", 2))) { } else if (unlikely(strncasecmp(buf, "OK", 2))) {
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
if (bitforce->nonce_range) { if (bitforce->nonce_range) {
applog(LOG_WARNING, "BFL%i: Does not support nonce range, disabling", bitforce->device_id); applog(LOG_WARNING, "%s%i: Does not support nonce range, disabling",
bitforce->api->name, bitforce->device_id);
bitforce->nonce_range = false; bitforce->nonce_range = false;
bitforce->sleep_ms *= 5; bitforce->sleep_ms *= 5;
bitforce->kname = KNAME_WORK; bitforce->kname = KNAME_WORK;
goto re_send; goto re_send;
} }
applog(LOG_ERR, "BFL%i: Error: Send work reports: %s", bitforce->device_id, pdevbuf); applog(LOG_ERR, "%s%i: Error: Send work reports: %s",
bitforce->api->name, bitforce->device_id, buf);
return false; return false;
} }
@ -479,7 +440,7 @@ re_send:
if (!bitforce->nonce_range) { if (!bitforce->nonce_range) {
sprintf((char *)ob + 8 + 32 + 12, ">>>>>>>>"); sprintf((char *)ob + 8 + 32 + 12, ">>>>>>>>");
work->blk.nonce = bitforce->nonces = 0xffffffff; work->blk.nonce = bitforce->nonces = 0xffffffff;
BFwrite(fdDev, ob, 60); len = 60;
} else { } else {
uint32_t *nonce; uint32_t *nonce;
@ -491,26 +452,41 @@ re_send:
*nonce = htobe32(work->blk.nonce + bitforce->nonces); *nonce = htobe32(work->blk.nonce + bitforce->nonces);
work->blk.nonce += bitforce->nonces + 1; work->blk.nonce += bitforce->nonces + 1;
sprintf((char *)ob + 8 + 32 + 12 + 8, ">>>>>>>>"); sprintf((char *)ob + 8 + 32 + 12 + 8, ">>>>>>>>");
BFwrite(fdDev, ob, 68); len = 68;
}
if ((err = usb_write(bitforce, (char *)ob, len, &amount, C_SENDWORK)) < 0 || amount != len) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "%s%i: send work failed (%d:%d)",
bitforce->api->name, bitforce->device_id, amount, err);
return false;
}
if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_SENDWORKSTATUS)) < 0) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "%s%d: read send work status failed (%d:%d)",
bitforce->api->name, bitforce->device_id, amount, err);
return false;
} }
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
if (opt_debug) { if (opt_debug) {
s = bin2hex(ob + 8, 44); s = bin2hex(ob + 8, 44);
applog(LOG_DEBUG, "BFL%i: block data: %s", bitforce->device_id, s); applog(LOG_DEBUG, "%s%i: block data: %s",
bitforce->api->name, bitforce->device_id, s);
free(s); free(s);
} }
if (unlikely(!pdevbuf[0])) { if (amount == 0 || !buf[0]) {
applog(LOG_ERR, "BFL%i: Error: Send block data returned empty string/timed out", bitforce->device_id); applog(LOG_ERR, "%s%i: Error: Send block data returned empty string/timed out",
bitforce->api->name, bitforce->device_id);
return false; return false;
} }
if (unlikely(strncasecmp(pdevbuf, "OK", 2))) { if (unlikely(strncasecmp(buf, "OK", 2))) {
applog(LOG_ERR, "BFL%i: Error: Send block data reports: %s", bitforce->device_id, pdevbuf); applog(LOG_ERR, "%s%i: Error: Send block data reports: %s",
bitforce->api->name, bitforce->device_id, buf);
return false; return false;
} }
@ -521,53 +497,52 @@ re_send:
static int64_t bitforce_get_result(struct thr_info *thr, struct work *work) static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
{ {
struct cgpu_info *bitforce = thr->cgpu; struct cgpu_info *bitforce = thr->cgpu;
int fdDev = bitforce->device_fd;
unsigned int delay_time_ms; unsigned int delay_time_ms;
struct timeval elapsed; struct timeval elapsed;
struct timeval now; struct timeval now;
char pdevbuf[0x100]; char buf[BITFORCE_BUFSIZ+1];
int amount;
char *pnoncebuf; char *pnoncebuf;
uint32_t nonce; uint32_t nonce;
if (!fdDev)
return -1;
while (1) { while (1) {
if (unlikely(thr->work_restart)) if (unlikely(thr->work_restart))
return 0; return 0;
mutex_lock(&bitforce->device_mutex); mutex_lock(&bitforce->device_mutex);
BFwrite(fdDev, "ZFX", 3); usb_write(bitforce, BITFORCE_WORKSTATUS, BITFORCE_WORKSTATUS_LEN, &amount, C_REQUESTWORKSTATUS);
pdevbuf[0] = '\0'; usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETWORKSTATUS);
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
timersub(&now, &bitforce->work_start_tv, &elapsed); timersub(&now, &bitforce->work_start_tv, &elapsed);
if (elapsed.tv_sec >= BITFORCE_LONG_TIMEOUT_S) { if (elapsed.tv_sec >= BITFORCE_LONG_TIMEOUT_S) {
applog(LOG_ERR, "BFL%i: took %dms - longer than %dms", bitforce->device_id, applog(LOG_ERR, "%s%i: took %dms - longer than %dms",
bitforce->api->name, bitforce->device_id,
tv_to_ms(elapsed), BITFORCE_LONG_TIMEOUT_MS); tv_to_ms(elapsed), BITFORCE_LONG_TIMEOUT_MS);
return 0; return 0;
} }
if (pdevbuf[0] && strncasecmp(pdevbuf, "B", 1)) /* BFL does not respond during throttling */ if (amount > 0 && buf[0] && strncasecmp(buf, "B", 1)) /* BFL does not respond during throttling */
break; break;
/* if BFL is throttling, no point checking so quickly */ /* if BFL is throttling, no point checking so quickly */
delay_time_ms = (pdevbuf[0] ? BITFORCE_CHECK_INTERVAL_MS : 2 * WORK_CHECK_INTERVAL_MS); delay_time_ms = (buf[0] ? BITFORCE_CHECK_INTERVAL_MS : 2 * WORK_CHECK_INTERVAL_MS);
nmsleep(delay_time_ms); nmsleep(delay_time_ms);
bitforce->wait_ms += delay_time_ms; bitforce->wait_ms += delay_time_ms;
} }
if (elapsed.tv_sec > BITFORCE_TIMEOUT_S) { if (elapsed.tv_sec > BITFORCE_TIMEOUT_S) {
applog(LOG_ERR, "BFL%i: took %dms - longer than %dms", bitforce->device_id, applog(LOG_ERR, "%s%i: took %dms - longer than %dms",
bitforce->api->name, bitforce->device_id,
tv_to_ms(elapsed), BITFORCE_TIMEOUT_MS); tv_to_ms(elapsed), BITFORCE_TIMEOUT_MS);
dev_error(bitforce, REASON_DEV_OVER_HEAT); dev_error(bitforce, REASON_DEV_OVER_HEAT);
if (!pdevbuf[0]) /* Only return if we got nothing after timeout - there still may be results */ /* Only return if we got nothing after timeout - there still may be results */
if (amount == 0)
return 0; return 0;
} else if (!strncasecmp(pdevbuf, "N", 1)) {/* Hashing complete (NONCE-FOUND or NO-NONCE) */ } else if (!strncasecmp(buf, "N", 1)) {/* Hashing complete (NONCE-FOUND or NO-NONCE) */
/* Simple timing adjustment. Allow a few polls to cope with /* Simple timing adjustment. Allow a few polls to cope with
* OS timer delays being variably reliable. wait_ms will * OS timer delays being variably reliable. wait_ms will
* always equal sleep_ms when we've waited greater than or * always equal sleep_ms when we've waited greater than or
@ -584,26 +559,31 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
} }
if (delay_time_ms != bitforce->sleep_ms) if (delay_time_ms != bitforce->sleep_ms)
applog(LOG_DEBUG, "BFL%i: Wait time changed to: %d, waited %u", bitforce->device_id, bitforce->sleep_ms, bitforce->wait_ms); applog(LOG_DEBUG, "%s%i: Wait time changed to: %d, waited %u",
bitforce->api->name, bitforce->device_id,
bitforce->sleep_ms, bitforce->wait_ms);
/* Work out the average time taken. Float for calculation, uint for display */ /* Work out the average time taken. Float for calculation, uint for display */
bitforce->avg_wait_f += (tv_to_ms(elapsed) - bitforce->avg_wait_f) / TIME_AVG_CONSTANT; bitforce->avg_wait_f += (tv_to_ms(elapsed) - bitforce->avg_wait_f) / TIME_AVG_CONSTANT;
bitforce->avg_wait_d = (unsigned int) (bitforce->avg_wait_f + 0.5); bitforce->avg_wait_d = (unsigned int) (bitforce->avg_wait_f + 0.5);
} }
applog(LOG_DEBUG, "BFL%i: waited %dms until %s", bitforce->device_id, bitforce->wait_ms, pdevbuf); applog(LOG_DEBUG, "%s%i: waited %dms until %s",
if (!strncasecmp(&pdevbuf[2], "-", 1)) bitforce->api->name, bitforce->device_id,
bitforce->wait_ms, buf);
if (!strncasecmp(&buf[2], "-", 1))
return bitforce->nonces; /* No valid nonce found */ return bitforce->nonces; /* No valid nonce found */
else if (!strncasecmp(pdevbuf, "I", 1)) else if (!strncasecmp(buf, "I", 1))
return 0; /* Device idle */ return 0; /* Device idle */
else if (strncasecmp(pdevbuf, "NONCE-FOUND", 11)) { else if (strncasecmp(buf, "NONCE-FOUND", 11)) {
bitforce->hw_errors++; bitforce->hw_errors++;
applog(LOG_WARNING, "BFL%i: Error: Get result reports: %s", bitforce->device_id, pdevbuf); applog(LOG_WARNING, "%s%i: Error: Get result reports: %s",
bitforce_clear_buffer(bitforce); bitforce->api->name, bitforce->device_id, buf);
bitforce_initialise(bitforce, true);
return 0; return 0;
} }
pnoncebuf = &pdevbuf[12]; pnoncebuf = &buf[12];
while (1) { while (1) {
hex2bin((void*)&nonce, pnoncebuf, 4); hex2bin((void*)&nonce, pnoncebuf, 4);
@ -612,7 +592,8 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
#endif #endif
if (unlikely(bitforce->nonce_range && (nonce >= work->blk.nonce || if (unlikely(bitforce->nonce_range && (nonce >= work->blk.nonce ||
(work->blk.nonce > 0 && nonce < work->blk.nonce - bitforce->nonces - 1)))) { (work->blk.nonce > 0 && nonce < work->blk.nonce - bitforce->nonces - 1)))) {
applog(LOG_WARNING, "BFL%i: Disabling broken nonce range support", bitforce->device_id); applog(LOG_WARNING, "%s%i: Disabling broken nonce range support",
bitforce->api->name, bitforce->device_id);
bitforce->nonce_range = false; bitforce->nonce_range = false;
work->blk.nonce = 0xffffffff; work->blk.nonce = 0xffffffff;
bitforce->sleep_ms *= 5; bitforce->sleep_ms *= 5;
@ -628,19 +609,16 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
return bitforce->nonces; return bitforce->nonces;
} }
static void bitforce_shutdown(struct thr_info *thr) static void bitforce_shutdown(__maybe_unused struct thr_info *thr)
{ {
struct cgpu_info *bitforce = thr->cgpu; // struct cgpu_info *bitforce = thr->cgpu;
BFclose(bitforce->device_fd);
bitforce->device_fd = 0;
} }
static void biforce_thread_enable(struct thr_info *thr) static void biforce_thread_enable(struct thr_info *thr)
{ {
struct cgpu_info *bitforce = thr->cgpu; struct cgpu_info *bitforce = thr->cgpu;
bitforce_init(bitforce); bitforce_initialise(bitforce, true);
} }
static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce) static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
@ -665,11 +643,11 @@ static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_
if (ret == -1) { if (ret == -1) {
ret = 0; ret = 0;
applog(LOG_ERR, "BFL%i: Comms error", bitforce->device_id); applog(LOG_ERR, "%s%i: Comms error", bitforce->api->name, bitforce->device_id);
dev_error(bitforce, REASON_DEV_COMMS_ERROR); dev_error(bitforce, REASON_DEV_COMMS_ERROR);
bitforce->hw_errors++; bitforce->hw_errors++;
/* empty read buffer */ /* empty read buffer */
bitforce_clear_buffer(bitforce); bitforce_initialise(bitforce, true);
} }
return ret; return ret;
} }
@ -692,7 +670,8 @@ static bool bitforce_thread_init(struct thr_info *thr)
/* Pause each new thread at least 100ms between initialising /* Pause each new thread at least 100ms between initialising
* so the devices aren't making calls all at the same time. */ * so the devices aren't making calls all at the same time. */
wait = thr->id * MAX_START_DELAY_MS; wait = thr->id * MAX_START_DELAY_MS;
applog(LOG_DEBUG, "BFL%i: Delaying start by %dms", bitforce->device_id, wait / 1000); applog(LOG_DEBUG, "%s%d: Delaying start by %dms",
bitforce->api->name, bitforce->device_id, wait / 1000);
nmsleep(wait); nmsleep(wait);
return true; return true;
@ -717,7 +696,6 @@ struct device_api bitforce_api = {
.name = "BFL", .name = "BFL",
.api_detect = bitforce_detect, .api_detect = bitforce_detect,
.get_api_stats = bitforce_api_stats, .get_api_stats = bitforce_api_stats,
.reinit_device = bitforce_init,
.get_statline_before = get_bitforce_statline_before, .get_statline_before = get_bitforce_statline_before,
.get_stats = bitforce_get_stats, .get_stats = bitforce_get_stats,
.identify_device = bitforce_identify, .identify_device = bitforce_identify,

10
miner.h
View File

@ -114,7 +114,7 @@ static inline int fsync (int fd)
#include "libztex.h" #include "libztex.h"
#endif #endif
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
#include "usbutils.h" #include "usbutils.h"
#endif #endif
@ -374,13 +374,17 @@ struct cgpu_info {
#ifdef USE_ZTEX #ifdef USE_ZTEX
struct libztex_device *device_ztex; struct libztex_device *device_ztex;
#endif #endif
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
struct cg_usb_device *usbdev; struct cg_usb_device *usbdev;
#endif #endif
#ifdef USE_ICARUS
int device_fd; int device_fd;
#endif
}; };
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
int usbstat; int usbstat;
#endif
#ifdef USE_MODMINER
char fpgaid; char fpgaid;
unsigned char clock; unsigned char clock;
pthread_mutex_t *modminer_mutex; pthread_mutex_t *modminer_mutex;

View File

@ -36,11 +36,25 @@
#define EPO(x) (LIBUSB_ENDPOINT_OUT | (unsigned char)(x)) #define EPO(x) (LIBUSB_ENDPOINT_OUT | (unsigned char)(x))
#ifdef WIN32 #ifdef WIN32
#define BITFORCE_TIMEOUT_MS 500
#define MODMINER_TIMEOUT_MS 200 #define MODMINER_TIMEOUT_MS 200
#else #else
#define BITFORCE_TIMEOUT_MS 200
#define MODMINER_TIMEOUT_MS 100 #define MODMINER_TIMEOUT_MS 100
#endif #endif
#ifdef USE_BITFORCE
static struct usb_endpoints bfl_eps[] = {
#ifdef WIN32
{ LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(1), 0 },
{ LIBUSB_TRANSFER_TYPE_BULK, 64, EPO(2), 0 }
#else
{ LIBUSB_TRANSFER_TYPE_BULK, 512, EPI(1), 0 },
{ LIBUSB_TRANSFER_TYPE_BULK, 512, EPO(2), 0 }
#endif
};
#endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
static struct usb_endpoints mmq_eps[] = { static struct usb_endpoints mmq_eps[] = {
{ LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(3), 0 }, { LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(3), 0 },
@ -48,7 +62,7 @@ static struct usb_endpoints mmq_eps[] = {
}; };
#endif #endif
// TODO: Add support for (at least) Interrupt endpoints // TODO: Add support for (at least) Isochronous endpoints
static struct usb_find_devices find_dev[] = { static struct usb_find_devices find_dev[] = {
/* /*
#ifdef USE_ICARUS #ifdef USE_ICARUS
@ -56,10 +70,19 @@ static struct usb_find_devices find_dev[] = {
{ DRV_ICARUS, "LOT", 0x0403, 0x6001, false, EPI(0), EPO(0), 1 }, { DRV_ICARUS, "LOT", 0x0403, 0x6001, false, EPI(0), EPO(0), 1 },
{ DRV_ICARUS, "CM1", 0x067b, 0x0230, false, EPI(0), EPO(0), 1 }, { DRV_ICARUS, "CM1", 0x067b, 0x0230, false, EPI(0), EPO(0), 1 },
#endif #endif
#ifdef USE_BITFORCE
{ DRV_BITFORCE, "BFL", 0x0403, 0x6014, true, EPI(1), EPO(2), 1 },
#endif
*/ */
#ifdef USE_BITFORCE
{
.drv = DRV_BITFORCE,
.name = "BFL",
.idVendor = 0x0403,
.idProduct = 0x6014,
.config = 1,
.interface = 0,
.timeout = BITFORCE_TIMEOUT_MS,
.epcount = ARRAY_SIZE(bfl_eps),
.eps = bfl_eps },
#endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
{ {
.drv = DRV_MODMINER, .drv = DRV_MODMINER,
@ -160,6 +183,18 @@ static const char *C_SENDWORK_S = "SendWork";
static const char *C_SENDWORKSTATUS_S = "SendWorkStatus"; static const char *C_SENDWORKSTATUS_S = "SendWorkStatus";
static const char *C_REQUESTWORKSTATUS_S = "RequestWorkStatus"; static const char *C_REQUESTWORKSTATUS_S = "RequestWorkStatus";
static const char *C_GETWORKSTATUS_S = "GetWorkStatus"; static const char *C_GETWORKSTATUS_S = "GetWorkStatus";
static const char *C_REQUESTIDENTIFY_S = "RequestIdentify";
static const char *C_GETIDENTIFY_S = "GetIdentify";
static const char *C_REQUESTFLASH_S = "RequestFlash";
static const char *C_REQUESTSENDWORK_S = "RequestSendWork";
static const char *C_REQUESTSENDWORKSTATUS_S = "RequestSendWorkStatus";
static const char *C_RESET_S = "Reset";
static const char *C_SETBAUD_S = "SetBaud";
static const char *C_SETDATA_S = "SetDataCtrl";
static const char *C_SETFLOW_S = "SetFlowCtrl";
static const char *C_SETMODEM_S = "SetModemCtrl";
static const char *C_PURGERX_S = "PurgeRx";
static const char *C_PURGETX_S = "PurgeTx";
#ifdef EOL #ifdef EOL
#undef EOL #undef EOL
@ -505,6 +540,7 @@ static void cgusb_check_init()
list_lock = calloc(1, sizeof(*list_lock)); list_lock = calloc(1, sizeof(*list_lock));
mutex_init(list_lock); mutex_init(list_lock);
// N.B. environment LIBUSB_DEBUG also sets libusb_set_debug()
if (opt_usbdump >= 0) { if (opt_usbdump >= 0) {
libusb_set_debug(NULL, opt_usbdump); libusb_set_debug(NULL, opt_usbdump);
usb_all(); usb_all();
@ -537,6 +573,18 @@ static void cgusb_check_init()
usb_commands[C_SENDWORKSTATUS] = C_SENDWORKSTATUS_S; usb_commands[C_SENDWORKSTATUS] = C_SENDWORKSTATUS_S;
usb_commands[C_REQUESTWORKSTATUS] = C_REQUESTWORKSTATUS_S; usb_commands[C_REQUESTWORKSTATUS] = C_REQUESTWORKSTATUS_S;
usb_commands[C_GETWORKSTATUS] = C_GETWORKSTATUS_S; usb_commands[C_GETWORKSTATUS] = C_GETWORKSTATUS_S;
usb_commands[C_REQUESTIDENTIFY] = C_REQUESTIDENTIFY_S;
usb_commands[C_GETIDENTIFY] = C_GETIDENTIFY_S;
usb_commands[C_REQUESTFLASH] = C_REQUESTFLASH_S;
usb_commands[C_REQUESTSENDWORK] = C_REQUESTSENDWORK_S;
usb_commands[C_REQUESTSENDWORKSTATUS] = C_REQUESTSENDWORKSTATUS_S;
usb_commands[C_RESET] = C_RESET_S;
usb_commands[C_SETBAUD] = C_SETBAUD_S;
usb_commands[C_SETDATA] = C_SETDATA_S;
usb_commands[C_SETFLOW] = C_SETFLOW_S;
usb_commands[C_SETMODEM] = C_SETMODEM_S;
usb_commands[C_PURGERX] = C_PURGERX_S;
usb_commands[C_PURGETX] = C_PURGETX_S;
} }
mutex_unlock(&cgusb_lock); mutex_unlock(&cgusb_lock);
@ -745,9 +793,9 @@ bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find
} }
if (libusb_kernel_driver_active(cgusb->handle, 0) == 1) { if (libusb_kernel_driver_active(cgusb->handle, 0) == 1) {
applog(LOG_WARNING, "USB init, kernel attached ..."); applog(LOG_DEBUG, "USB init, kernel attached ...");
if (libusb_detach_kernel_driver(cgusb->handle, 0) == 0) if (libusb_detach_kernel_driver(cgusb->handle, 0) == 0)
applog(LOG_WARNING, "USB init, kernel detached successfully"); applog(LOG_DEBUG, "USB init, kernel detached successfully");
else else
applog(LOG_WARNING, "USB init, kernel detach failed :("); applog(LOG_WARNING, "USB init, kernel detach failed :(");
} }
@ -773,7 +821,7 @@ bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find
goto cldame; goto cldame;
} }
if ((int)(config->bNumInterfaces) < found->interface) if ((int)(config->bNumInterfaces) <= found->interface)
goto cldame; goto cldame;
for (i = 0; i < found->epcount; i++) for (i = 0; i < found->epcount; i++)
@ -1118,26 +1166,42 @@ static void stats(struct cgpu_info *cgpu, struct timeval *tv_start, struct timev
} }
#endif #endif
int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, int eol, enum usb_cmds cmd) int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, int eol, enum usb_cmds cmd, bool ftdi)
{ {
struct cg_usb_device *usbdev = cgpu->usbdev; struct cg_usb_device *usbdev = cgpu->usbdev;
#if DO_USB_STATS #if DO_USB_STATS
struct timeval tv_start, tv_finish; struct timeval tv_start;
#endif #endif
int err, got, tot; struct timeval read_start, tv_finish;
unsigned int initial_timeout;
double max, done;
int err, got, tot, i;
bool first = true; bool first = true;
if (timeout == DEVTIMEOUT)
timeout = usbdev->found->timeout;
if (eol == -1) { if (eol == -1) {
got = 0; got = 0;
STATS_TIMEVAL(&tv_start); STATS_TIMEVAL(&tv_start);
err = libusb_bulk_transfer(usbdev->handle, err = libusb_bulk_transfer(usbdev->handle,
usbdev->found->eps[ep].ep, usbdev->found->eps[ep].ep,
(unsigned char *)buf, (unsigned char *)buf,
bufsiz, &got, bufsiz, &got, timeout);
timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout);
STATS_TIMEVAL(&tv_finish); STATS_TIMEVAL(&tv_finish);
USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, SEQ0); USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, SEQ0);
if (ftdi) {
// first 2 bytes returned are an FTDI status
if (got > 2) {
got -= 2;
memmove(buf, buf+2, got+1);
} else {
got = 0;
*buf = '\0';
}
}
*processed = got; *processed = got;
return err; return err;
@ -1145,31 +1209,55 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro
tot = 0; tot = 0;
err = LIBUSB_SUCCESS; err = LIBUSB_SUCCESS;
initial_timeout = timeout;
max = ((double)timeout) / 1000.0;
gettimeofday(&read_start, NULL);
while (bufsiz) { while (bufsiz) {
got = 0; got = 0;
STATS_TIMEVAL(&tv_start); STATS_TIMEVAL(&tv_start);
err = libusb_bulk_transfer(usbdev->handle, err = libusb_bulk_transfer(usbdev->handle,
usbdev->found->eps[ep].ep, usbdev->found->eps[ep].ep,
(unsigned char *)buf, (unsigned char *)buf,
1, &got, bufsiz, &got, timeout);
timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout); gettimeofday(&tv_finish, NULL);
STATS_TIMEVAL(&tv_finish);
USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, first ? SEQ0 : SEQ1); USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, first ? SEQ0 : SEQ1);
if (ftdi) {
// first 2 bytes returned are an FTDI status
if (got > 2) {
got -= 2;
memmove(buf, buf+2, got+1);
} else {
got = 0;
*buf = '\0';
}
}
tot += got; tot += got;
if (err) if (err)
break; break;
if (eol == buf[0]) // WARNING - this will return data past EOL ('if' there is extra data)
break; for (i = 0; i < got; i++)
if (buf[i] == eol)
goto goteol;
buf += got; buf += got;
bufsiz -= got; bufsiz -= got;
first = false; first = false;
done = tdiff(&tv_finish, &read_start);
// N.B. this is return LIBUSB_SUCCESS with whatever size has already been read
if (unlikely(done >= max))
break;
timeout = initial_timeout - (done * 1000);
} }
goteol:
*processed = tot; *processed = tot;
return err; return err;
@ -1198,6 +1286,24 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr
return err; return err;
} }
int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned int timeout, enum usb_cmds cmd)
{
struct cg_usb_device *usbdev = cgpu->usbdev;
#if DO_USB_STATS
struct timeval tv_start, tv_finish;
#endif
int err;
STATS_TIMEVAL(&tv_start);
err = libusb_control_transfer(usbdev->handle, request_type,
bRequest, wValue, wIndex, NULL, 0,
timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout);
STATS_TIMEVAL(&tv_finish);
USB_STATS(cgpu, &tv_start, &tv_finish, err, cmd, SEQ0);
return err;
}
void usb_cleanup() void usb_cleanup()
{ {
// TODO: // TODO:

View File

@ -12,6 +12,29 @@
#include <libusb.h> #include <libusb.h>
// for 0x0403/0x6014 FT232H (and possibly others?)
#define FTDI_TYPE_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT)
#define FTDI_REQUEST_RESET ((uint8_t)0)
#define FTDI_REQUEST_MODEM ((uint8_t)1)
#define FTDI_REQUEST_FLOW ((uint8_t)2)
#define FTDI_REQUEST_BAUD ((uint8_t)3)
#define FTDI_REQUEST_DATA ((uint8_t)4)
#define FTDI_VALUE_RESET 0
#define FTDI_VALUE_PURGE_RX 1
#define FTDI_VALUE_PURGE_TX 2
// baud with a 0 divisor is 120,000,000/10
//#define FTDI_VALUE_BAUD (0)
//#define FTDI_INDEX_BAUD (0)
#define FTDI_VALUE_BAUD 0xc068
#define FTDI_INDEX_BAUD 0x0200
#define FTDI_VALUE_DATA 0
#define FTDI_VALUE_FLOW 0
#define FTDI_VALUE_MODEM 0x0303
// Use the device defined timeout // Use the device defined timeout
#define DEVTIMEOUT 0 #define DEVTIMEOUT 0
@ -78,6 +101,18 @@ enum usb_cmds {
C_SENDWORKSTATUS, C_SENDWORKSTATUS,
C_REQUESTWORKSTATUS, C_REQUESTWORKSTATUS,
C_GETWORKSTATUS, C_GETWORKSTATUS,
C_REQUESTIDENTIFY,
C_GETIDENTIFY,
C_REQUESTFLASH,
C_REQUESTSENDWORK,
C_REQUESTSENDWORKSTATUS,
C_RESET,
C_SETBAUD,
C_SETDATA,
C_SETFLOW,
C_SETMODEM,
C_PURGERX,
C_PURGETX,
C_MAX C_MAX
}; };
@ -89,21 +124,25 @@ bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find
void usb_detect(struct device_api *api, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *)); void usb_detect(struct device_api *api, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *));
struct api_data *api_usb_stats(int *count); struct api_data *api_usb_stats(int *count);
void update_usb_stats(struct cgpu_info *cgpu); void update_usb_stats(struct cgpu_info *cgpu);
int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, int eol, enum usb_cmds); int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, int eol, enum usb_cmds, bool ftdi);
int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds); int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *processed, unsigned int timeout, enum usb_cmds);
int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, unsigned int timeout, enum usb_cmds cmd);
void usb_cleanup(); void usb_cleanup();
#define usb_read(cgpu, buf, bufsiz, read, cmd) \ #define usb_read(cgpu, buf, bufsiz, read, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, -1, cmd) _usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, -1, cmd, false)
#define usb_read_nl(cgpu, buf, bufsiz, read, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, '\n', cmd, false)
#define usb_read_ep(cgpu, ep, buf, bufsiz, read, cmd) \ #define usb_read_ep(cgpu, ep, buf, bufsiz, read, cmd) \
_usb_read(cgpu, ep, buf, bufsiz, read, DEVTIMEOUT, -1, cmd) _usb_read(cgpu, ep, buf, bufsiz, read, DEVTIMEOUT, -1, cmd, false)
#define usb_read_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \ #define usb_read_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, -1, cmd) _usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, -1, cmd, false)
#define usb_read_ep_timeout(cgpu, ep, buf, bufsiz, read, timeout, cmd) \ #define usb_read_ep_timeout(cgpu, ep, buf, bufsiz, read, timeout, cmd) \
_usb_read(cgpu, ep, buf, bufsiz, read, timeout, -1, cmd) _usb_read(cgpu, ep, buf, bufsiz, read, timeout, -1, cmd, false)
#define usb_write(cgpu, buf, bufsiz, wrote, cmd) \ #define usb_write(cgpu, buf, bufsiz, wrote, cmd) \
_usb_write(cgpu, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd) _usb_write(cgpu, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
@ -117,4 +156,10 @@ void usb_cleanup();
#define usb_write_ep_timeout(cgpu, ep, buf, bufsiz, wrote, timeout, cmd) \ #define usb_write_ep_timeout(cgpu, ep, buf, bufsiz, wrote, timeout, cmd) \
_usb_write(cgpu, ep, buf, bufsiz, wrote, timeout, cmd) _usb_write(cgpu, ep, buf, bufsiz, wrote, timeout, cmd)
#define usb_ftdi_read_nl(cgpu, buf, bufsiz, read, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, '\n', cmd, true)
#define usb_transfer(cgpu, typ, req, val, idx, cmd) \
_usb_transfer(cgpu, typ, req, val, idx, DEVTIMEOUT, cmd)
#endif #endif