mirror of
https://github.com/GOSTSec/sgminer
synced 2025-01-11 07:17:58 +00:00
Merge branch 'bfl'
This commit is contained in:
commit
e3db37a64e
25
FPGA-README
25
FPGA-README
@ -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
|
||||||
|
@ -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
18
README
@ -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
4
api.c
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
10
miner.h
@ -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;
|
||||||
|
140
usbutils.c
140
usbutils.c
@ -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:
|
||||||
|
55
usbutils.h
55
usbutils.h
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user