Browse Source

Merge branch 'bfl'

nfactor-troky
Kano 12 years ago
parent
commit
e3db37a64e
  1. 25
      FPGA-README
  2. 6
      Makefile.am
  3. 18
      README
  4. 4
      api.c
  5. 7
      configure.ac
  6. 616
      driver-bitforce.c
  7. 10
      miner.h
  8. 138
      usbutils.c
  9. 55
      usbutils.h

25
FPGA-README

@ -2,15 +2,8 @@ @@ -2,15 +2,8 @@
This README contains extended details about FPGA mining with cgminer
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
-
For ModMinerQuad (MMQ) and BitForce (BFL)
-----------------------------------------
When mining on windows, the driver being used will determine if mining will work.
@ -39,7 +32,17 @@ problems: @@ -39,7 +32,17 @@ problems:
--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 @@ -130,7 +133,7 @@ modem-manager software
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

6
Makefile.am

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

18
README

@ -220,15 +220,16 @@ SCRYPT only options: @@ -220,15 +220,16 @@ SCRYPT only options:
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
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
@ -237,13 +238,14 @@ device depending on the version of udev being used. @@ -237,13 +238,14 @@ device depending on the version of udev being used.
On linux <arg> is usually of the format /dev/ttyUSBn
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.
To force the code to only attempt detection with a specific driver,
prepend the argument with the driver name followed by a colon.
For example, "icarus:/dev/ttyUSB0" or "bitforce:\\.\COM5"
or using the short name: "ica:/dev/ttyUSB0" or "bfl:\\.\COM5"
For example, "icarus:/dev/ttyUSB0" or using the short name: "ica:/dev/ttyUSB0"
This option not longer matters since Icarus is the only serial-USB
device that uses it
For other FPGA details see the FPGA-README

4
api.c

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

7
configure.ac

@ -273,6 +273,7 @@ fi @@ -273,6 +273,7 @@ fi
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([WANT_JANSSON], [test x$request_jansson = xtrue])
AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue])
@ -321,7 +322,7 @@ fi @@ -321,7 +322,7 @@ fi
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)])],
[libudev=$withval],
[libudev=auto]
@ -343,7 +344,7 @@ AM_CONDITIONAL([HAVE_LIBUDEV], [test x$libudev != xno]) @@ -343,7 +344,7 @@ AM_CONDITIONAL([HAVE_LIBUDEV], [test x$libudev != xno])
PKG_PROG_PKG_CONFIG()
if test "x$ztex$modminer" != xnono; then
if test "x$ztex$modminer$bitforce" != xnonono; then
case $target in
*-*-freebsd*)
LIBUSB_LIBS="-lusb"
@ -508,7 +509,7 @@ else @@ -508,7 +509,7 @@ else
echo " Ztex.FPGAs...........: Disabled"
fi
if test "x$bitforce" != xno; then
if test "x$icarus" != xno; then
echo " libudev.detection....: $libudev"
fi

616
driver-bitforce.c

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
/*
* Copyright 2012 Andrew Smith
* Copyright 2012 Luke Dashjr
* Copyright 2012 Con Kolivas
*
@ -19,34 +20,25 @@ @@ -19,34 +20,25 @@
#include "config.h"
#ifdef WIN32
#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 */
#include "compat.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_TIMEOUT_S 7
@ -62,62 +54,159 @@ enum { @@ -62,62 +54,159 @@ enum {
#define KNAME_WORK "full work"
#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;
static void BFgets(char *buf, size_t bufLen, int fd)
static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
{
do {
buf[0] = '\0';
--bufLen;
} while (likely(bufLen && read(fd, buf, 1) == 1 && (buf++)[0] != '\n'));
int err;
buf[0] = '\0';
}
if (lock)
mutex_lock(&bitforce->device_mutex);
static ssize_t BFwrite(int fd, const void *buf, ssize_t bufLen)
{
if ((bufLen) != write(fd, buf, bufLen))
return 0;
else
return bufLen;
// 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);
}
#define BFclose(fd) close(fd)
static bool bitforce_detect_one(const char *devpath)
static bool bitforce_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
{
int fdDev = BFopen(devpath);
struct cgpu_info *bitforce;
char pdevbuf[0x100];
char buf[BITFORCE_BUFSIZ+1];
char devpath[20];
int err, amount;
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)) {
applog(LOG_ERR, "BFL: Failed to open %s", devpath);
return false;
if (!usb_init(bitforce, dev, found)) {
applog(LOG_ERR, "%s detect (%d:%d) failed to initialise (incorrect device?)",
bitforce->api->dname,
(int)libusb_get_bus_number(dev),
(int)libusb_get_device_address(dev));
goto shin;
}
BFwrite(fdDev, "ZGX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "BFL: Error reading/timeout (ZGX)");
return 0;
sprintf(devpath, "%d:%d",
(int)(bitforce->usbdev->bus_number),
(int)(bitforce->usbdev->device_address));
int init_count = 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 (unlikely(!strstr(pdevbuf, "SHA256"))) {
applog(LOG_ERR, "BFL: Didn't recognise BitForce on %s", devpath);
return false;
if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETIDENTIFY)) < 0 || amount < 1) {
// Maybe it was still processing previous work?
if (++init_count <= REINIT_COUNT) {
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!
bitforce = calloc(1, sizeof(*bitforce));
bitforce->api = &bitforce_api;
bitforce->device_path = strdup(devpath);
bitforce->deven = DEV_ENABLED;
bitforce->threads = 1;
applog(LOG_DEBUG, "%s (%s) identified as: '%s'",
bitforce->api->dname, devpath, bitforce->name);
/* Initially enable support for nonce range and disable it later if it
* fails */
if (opt_bfl_noncerange) {
@ -129,108 +218,36 @@ static bool bitforce_detect_one(const char *devpath) @@ -129,108 +218,36 @@ static bool bitforce_detect_one(const char *devpath)
bitforce->kname = KNAME_WORK;
}
if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
s[0] = '\0';
bitforce->name = strdup(pdevbuf + 7);
}
bitforce->device_path = strdup(devpath);
if (!add_cgpu(bitforce))
goto unshin;
update_usb_stats(bitforce);
mutex_init(&bitforce->device_mutex);
return add_cgpu(bitforce);
}
return true;
#define LOAD_SYM(sym) do { \
if (!(sym = dlsym(dll, #sym))) { \
applog(LOG_DEBUG, "Failed to load " #sym ", not using FTDI bitforce autodetect"); \
goto out; \
} \
} while(0)
unshin:
#ifdef WIN32
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;
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);
bufptrs = alloca(sizeof(*bufptrs) * (numDevs + 1));
for (i = 0; i < numDevs; ++i)
bufptrs[i] = &buf[i * 65];
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;
}
usb_uninit(bitforce);
out:
dlclose(dll);
return found;
}
#else
static int bitforce_autodetect_ftdi(void)
{
return 0;
}
#endif
shin:
static int bitforce_detect_auto(void)
{
return (serial_autodetect_udev (bitforce_detect_one, "BitFORCE*SHA256") ?:
serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?:
bitforce_autodetect_ftdi() ?:
0);
free(bitforce->device_path);
if (bitforce->name != blank)
free(bitforce->name);
free(bitforce);
return false;
}
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)
@ -247,105 +264,17 @@ 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)
{
struct cgpu_info *bitforce = thr->cgpu;
int fdDev = BFopen(bitforce->device_path);
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);
get_datestamp(bitforce->init, &now);
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)
{
int fdDev = bitforce->device_fd;
if (!fdDev)
return;
int err, amount;
/* Do not try to flash the led if we're polling for a result to
* minimise the chance of interleaved results */
@ -353,19 +282,22 @@ static void bitforce_flash_led(struct cgpu_info *bitforce) @@ -353,19 +282,22 @@ static void bitforce_flash_led(struct cgpu_info *bitforce)
return;
/* 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))
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 */
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);
return; // nothing is returned by the BFL
@ -373,13 +305,10 @@ static void bitforce_flash_led(struct cgpu_info *bitforce) @@ -373,13 +305,10 @@ static void bitforce_flash_led(struct cgpu_info *bitforce)
static bool bitforce_get_temp(struct cgpu_info *bitforce)
{
int fdDev = bitforce->device_fd;
char pdevbuf[0x100];
char buf[BITFORCE_BUFSIZ+1];
int err, amount;
char *s;
if (!fdDev)
return false;
/* Do not try to get the temperature if we're polling for a result to
* minimise the chance of interleaved results */
if (bitforce->polling)
@ -396,18 +325,30 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce) @@ -396,18 +325,30 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
if (mutex_trylock(&bitforce->device_mutex))
return false;
BFwrite(fdDev, "ZLX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex);
if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "BFL%i: Error: Get temp returned empty string/timed out", bitforce->device_id);
if ((err = usb_write(bitforce, BITFORCE_TEMPERATURE, BITFORCE_TEMPERATURE_LEN, &amount, C_REQUESTTEMPERATURE)) < 0 || amount != BITFORCE_TEMPERATURE_LEN) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "%s%i: Error: Request temp invalid/timed out (%d:%d)",
bitforce->api->name, bitforce->device_id, amount, err);
bitforce->hw_errors++;
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);
/* Cope with older software that breaks and reads nonsense
@ -418,7 +359,8 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce) @@ -418,7 +359,8 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
if (temp > 0) {
bitforce->temp = temp;
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;
dev_error(bitforce, REASON_DEV_THERMAL_CUTOFF);
}
@ -427,11 +369,12 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce) @@ -427,11 +369,12 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
/* Use the temperature monitor as a kind of watchdog for when
* our responses are out of sync and flush the buffer to
* 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);
/* Count throttling episodes as hardware errors */
bitforce->hw_errors++;
bitforce_clear_buffer(bitforce);
bitforce_initialise(bitforce, true);
return false;
}
@ -441,35 +384,53 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce) @@ -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)
{
struct cgpu_info *bitforce = thr->cgpu;
int fdDev = bitforce->device_fd;
unsigned char ob[70];
char pdevbuf[0x100];
char buf[BITFORCE_BUFSIZ+1];
int err, amount;
char *s;
char *cmd;
int len;
if (!fdDev)
return false;
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);
if (bitforce->nonce_range)
BFwrite(fdDev, "ZPX", 3);
else
BFwrite(fdDev, "ZDX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (!pdevbuf[0] || !strncasecmp(pdevbuf, "B", 1)) {
if ((err = usb_write(bitforce, cmd, len, &amount, C_REQUESTSENDWORK)) < 0 || amount != len) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "%s%i: request 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_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);
nmsleep(WORK_CHECK_INTERVAL_MS);
goto re_send;
} else if (unlikely(strncasecmp(pdevbuf, "OK", 2))) {
} else if (unlikely(strncasecmp(buf, "OK", 2))) {
mutex_unlock(&bitforce->device_mutex);
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->sleep_ms *= 5;
bitforce->kname = KNAME_WORK;
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;
}
@ -479,7 +440,7 @@ re_send: @@ -479,7 +440,7 @@ re_send:
if (!bitforce->nonce_range) {
sprintf((char *)ob + 8 + 32 + 12, ">>>>>>>>");
work->blk.nonce = bitforce->nonces = 0xffffffff;
BFwrite(fdDev, ob, 60);
len = 60;
} else {
uint32_t *nonce;
@ -491,26 +452,41 @@ re_send: @@ -491,26 +452,41 @@ re_send:
*nonce = htobe32(work->blk.nonce + bitforce->nonces);
work->blk.nonce += bitforce->nonces + 1;
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);
if (opt_debug) {
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);
}
if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "BFL%i: Error: Send block data returned empty string/timed out", bitforce->device_id);
if (amount == 0 || !buf[0]) {
applog(LOG_ERR, "%s%i: Error: Send block data returned empty string/timed out",
bitforce->api->name, bitforce->device_id);
return false;
}
if (unlikely(strncasecmp(pdevbuf, "OK", 2))) {
applog(LOG_ERR, "BFL%i: Error: Send block data reports: %s", bitforce->device_id, pdevbuf);
if (unlikely(strncasecmp(buf, "OK", 2))) {
applog(LOG_ERR, "%s%i: Error: Send block data reports: %s",
bitforce->api->name, bitforce->device_id, buf);
return false;
}
@ -521,53 +497,52 @@ re_send: @@ -521,53 +497,52 @@ re_send:
static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
{
struct cgpu_info *bitforce = thr->cgpu;
int fdDev = bitforce->device_fd;
unsigned int delay_time_ms;
struct timeval elapsed;
struct timeval now;
char pdevbuf[0x100];
char buf[BITFORCE_BUFSIZ+1];
int amount;
char *pnoncebuf;
uint32_t nonce;
if (!fdDev)
return -1;
while (1) {
if (unlikely(thr->work_restart))
return 0;
mutex_lock(&bitforce->device_mutex);
BFwrite(fdDev, "ZFX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
usb_write(bitforce, BITFORCE_WORKSTATUS, BITFORCE_WORKSTATUS_LEN, &amount, C_REQUESTWORKSTATUS);
usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETWORKSTATUS);
mutex_unlock(&bitforce->device_mutex);
gettimeofday(&now, NULL);
timersub(&now, &bitforce->work_start_tv, &elapsed);
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);
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;
/* 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);
bitforce->wait_ms += delay_time_ms;
}
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);
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;
} 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
* OS timer delays being variably reliable. wait_ms will
* 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) @@ -584,26 +559,31 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
}
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 */
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);
}
applog(LOG_DEBUG, "BFL%i: waited %dms until %s", bitforce->device_id, bitforce->wait_ms, pdevbuf);
if (!strncasecmp(&pdevbuf[2], "-", 1))
applog(LOG_DEBUG, "%s%i: waited %dms until %s",
bitforce->api->name, bitforce->device_id,
bitforce->wait_ms, buf);
if (!strncasecmp(&buf[2], "-", 1))
return bitforce->nonces; /* No valid nonce found */
else if (!strncasecmp(pdevbuf, "I", 1))
else if (!strncasecmp(buf, "I", 1))
return 0; /* Device idle */
else if (strncasecmp(pdevbuf, "NONCE-FOUND", 11)) {
else if (strncasecmp(buf, "NONCE-FOUND", 11)) {
bitforce->hw_errors++;
applog(LOG_WARNING, "BFL%i: Error: Get result reports: %s", bitforce->device_id, pdevbuf);
bitforce_clear_buffer(bitforce);
applog(LOG_WARNING, "%s%i: Error: Get result reports: %s",
bitforce->api->name, bitforce->device_id, buf);
bitforce_initialise(bitforce, true);
return 0;
}
pnoncebuf = &pdevbuf[12];
pnoncebuf = &buf[12];
while (1) {
hex2bin((void*)&nonce, pnoncebuf, 4);
@ -612,7 +592,8 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work) @@ -612,7 +592,8 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
#endif
if (unlikely(bitforce->nonce_range && (nonce >= work->blk.nonce ||
(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;
work->blk.nonce = 0xffffffff;
bitforce->sleep_ms *= 5;
@ -628,19 +609,16 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work) @@ -628,19 +609,16 @@ static int64_t bitforce_get_result(struct thr_info *thr, struct work *work)
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;
BFclose(bitforce->device_fd);
bitforce->device_fd = 0;
// struct cgpu_info *bitforce = thr->cgpu;
}
static void biforce_thread_enable(struct thr_info *thr)
{
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)
@ -665,11 +643,11 @@ static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_ @@ -665,11 +643,11 @@ static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_
if (ret == -1) {
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);
bitforce->hw_errors++;
/* empty read buffer */
bitforce_clear_buffer(bitforce);
bitforce_initialise(bitforce, true);
}
return ret;
}
@ -692,7 +670,8 @@ static bool bitforce_thread_init(struct thr_info *thr) @@ -692,7 +670,8 @@ static bool bitforce_thread_init(struct thr_info *thr)
/* Pause each new thread at least 100ms between initialising
* so the devices aren't making calls all at the same time. */
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);
return true;
@ -717,7 +696,6 @@ struct device_api bitforce_api = { @@ -717,7 +696,6 @@ struct device_api bitforce_api = {
.name = "BFL",
.api_detect = bitforce_detect,
.get_api_stats = bitforce_api_stats,
.reinit_device = bitforce_init,
.get_statline_before = get_bitforce_statline_before,
.get_stats = bitforce_get_stats,
.identify_device = bitforce_identify,

10
miner.h

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

138
usbutils.c

@ -36,11 +36,25 @@ @@ -36,11 +36,25 @@
#define EPO(x) (LIBUSB_ENDPOINT_OUT | (unsigned char)(x))
#ifdef WIN32
#define BITFORCE_TIMEOUT_MS 500
#define MODMINER_TIMEOUT_MS 200
#else
#define BITFORCE_TIMEOUT_MS 200
#define MODMINER_TIMEOUT_MS 100
#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
static struct usb_endpoints mmq_eps[] = {
{ LIBUSB_TRANSFER_TYPE_BULK, 64, EPI(3), 0 },
@ -48,7 +62,7 @@ static struct usb_endpoints mmq_eps[] = { @@ -48,7 +62,7 @@ static struct usb_endpoints mmq_eps[] = {
};
#endif
// TODO: Add support for (at least) Interrupt endpoints
// TODO: Add support for (at least) Isochronous endpoints
static struct usb_find_devices find_dev[] = {
/*
#ifdef USE_ICARUS
@ -56,10 +70,19 @@ static struct usb_find_devices find_dev[] = { @@ -56,10 +70,19 @@ static struct usb_find_devices find_dev[] = {
{ DRV_ICARUS, "LOT", 0x0403, 0x6001, false, EPI(0), EPO(0), 1 },
{ DRV_ICARUS, "CM1", 0x067b, 0x0230, false, EPI(0), EPO(0), 1 },
#endif
*/
#ifdef USE_BITFORCE
{ DRV_BITFORCE, "BFL", 0x0403, 0x6014, true, EPI(1), EPO(2), 1 },
{
.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
{
.drv = DRV_MODMINER,
@ -160,6 +183,18 @@ static const char *C_SENDWORK_S = "SendWork"; @@ -160,6 +183,18 @@ static const char *C_SENDWORK_S = "SendWork";
static const char *C_SENDWORKSTATUS_S = "SendWorkStatus";
static const char *C_REQUESTWORKSTATUS_S = "RequestWorkStatus";
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
#undef EOL
@ -505,6 +540,7 @@ static void cgusb_check_init() @@ -505,6 +540,7 @@ static void cgusb_check_init()
list_lock = calloc(1, sizeof(*list_lock));
mutex_init(list_lock);
// N.B. environment LIBUSB_DEBUG also sets libusb_set_debug()
if (opt_usbdump >= 0) {
libusb_set_debug(NULL, opt_usbdump);
usb_all();
@ -537,6 +573,18 @@ static void cgusb_check_init() @@ -537,6 +573,18 @@ static void cgusb_check_init()
usb_commands[C_SENDWORKSTATUS] = C_SENDWORKSTATUS_S;
usb_commands[C_REQUESTWORKSTATUS] = C_REQUESTWORKSTATUS_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);
@ -745,9 +793,9 @@ bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find @@ -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) {
applog(LOG_WARNING, "USB init, kernel attached ...");
applog(LOG_DEBUG, "USB init, kernel attached ...");
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
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 @@ -773,7 +821,7 @@ bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find
goto cldame;
}
if ((int)(config->bNumInterfaces) < found->interface)
if ((int)(config->bNumInterfaces) <= found->interface)
goto cldame;
for (i = 0; i < found->epcount; i++)
@ -1118,26 +1166,42 @@ static void stats(struct cgpu_info *cgpu, struct timeval *tv_start, struct timev @@ -1118,26 +1166,42 @@ static void stats(struct cgpu_info *cgpu, struct timeval *tv_start, struct timev
}
#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;
#if DO_USB_STATS
struct timeval tv_start, tv_finish;
struct timeval tv_start;
#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;
if (timeout == DEVTIMEOUT)
timeout = usbdev->found->timeout;
if (eol == -1) {
got = 0;
STATS_TIMEVAL(&tv_start);
err = libusb_bulk_transfer(usbdev->handle,
usbdev->found->eps[ep].ep,
(unsigned char *)buf,
bufsiz, &got,
timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout);
bufsiz, &got, timeout);
STATS_TIMEVAL(&tv_finish);
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;
return err;
@ -1145,31 +1209,55 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro @@ -1145,31 +1209,55 @@ int _usb_read(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pro
tot = 0;
err = LIBUSB_SUCCESS;
initial_timeout = timeout;
max = ((double)timeout) / 1000.0;
gettimeofday(&read_start, NULL);
while (bufsiz) {
got = 0;
STATS_TIMEVAL(&tv_start);
err = libusb_bulk_transfer(usbdev->handle,
usbdev->found->eps[ep].ep,
(unsigned char *)buf,
1, &got,
timeout == DEVTIMEOUT ? usbdev->found->timeout : timeout);
STATS_TIMEVAL(&tv_finish);
bufsiz, &got, timeout);
gettimeofday(&tv_finish, NULL);
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;
if (err)
break;
if (eol == buf[0])
break;
// WARNING - this will return data past EOL ('if' there is extra data)
for (i = 0; i < got; i++)
if (buf[i] == eol)
goto goteol;
buf += got;
bufsiz -= got;
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;
return err;
@ -1198,6 +1286,24 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr @@ -1198,6 +1286,24 @@ int _usb_write(struct cgpu_info *cgpu, int ep, char *buf, size_t bufsiz, int *pr
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()
{
// TODO:

55
usbutils.h

@ -12,6 +12,29 @@ @@ -12,6 +12,29 @@
#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
#define DEVTIMEOUT 0
@ -78,6 +101,18 @@ enum usb_cmds { @@ -78,6 +101,18 @@ enum usb_cmds {
C_SENDWORKSTATUS,
C_REQUESTWORKSTATUS,
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
};
@ -89,21 +124,25 @@ bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find @@ -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 *));
struct api_data *api_usb_stats(int *count);
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_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();
#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) \
_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) \
_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) \
_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) \
_usb_write(cgpu, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
@ -117,4 +156,10 @@ void usb_cleanup(); @@ -117,4 +156,10 @@ void usb_cleanup();
#define usb_write_ep_timeout(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

Loading…
Cancel
Save