Browse Source

BFL libusb driver

nfactor-troky
Kano 12 years ago
parent
commit
cbf6c71648
  1. 590
      driver-bitforce.c
  2. 133
      usbutils.c
  3. 55
      usbutils.h

590
driver-bitforce.c

@ -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,143 @@ 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 6000
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);
static ssize_t BFwrite(int fd, const void *buf, ssize_t bufLen) // Reset
{ err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
if ((bufLen) != write(fd, buf, bufLen)) FTDI_VALUE_RESET, bitforce->usbdev->found->interface, C_RESET);
return 0; if (opt_debug)
else applog(LOG_DEBUG, "%s%i: reset got err %d",
return bufLen; 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(struct libusb_device *dev, struct usb_find_devices *found)
static bool bitforce_detect_one(const char *devpath)
{ {
int fdDev = BFopen(devpath); char buf[BITFORCE_BUFSIZ+1];
struct cgpu_info *bitforce; char devpath[20];
char pdevbuf[0x100]; int err, amount;
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: failed to initialise (incorrect device?)", bitforce->api->dname);
return false; goto shin;
} }
BFwrite(fdDev, "ZGX", 3); int init_counter = 0;
pdevbuf[0] = '\0'; reinit:
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (unlikely(!pdevbuf[0])) { bitforce_initialise(bitforce, false);
applog(LOG_ERR, "BFL: Error reading/timeout (ZGX)");
return 0; if ((err = usb_write(bitforce, BITFORCE_IDENTIFY, BITFORCE_IDENTIFY_LEN, &amount, C_REQUESTIDENTIFY)) < 0 || amount != BITFORCE_IDENTIFY_LEN) {
applog(LOG_ERR, "%s detect: send identify request failed (%d:%d)",
bitforce->api->dname, 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_counter++ < 1) {
return false; applog(LOG_WARNING, "%s detect: 1st init failed - retrying in %dms (%d:%d)",
bitforce->api->dname, REINIT_TIME_MS, amount, err);
nmsleep(REINIT_TIME_MS);
goto reinit;
}
if (err < 0) {
applog(LOG_ERR, "%s detect: error identify reply (%d:%d)",
bitforce->api->dname, amount, err);
} else {
applog(LOG_ERR, "%s detect: empty identify reply (%d)",
bitforce->api->dname, amount);
}
goto unshin;
}
buf[amount] = '\0';
if (unlikely(!strstr(buf, "SHA256"))) {
applog(LOG_ERR, "%s detect: didn't recognise %s",
bitforce->api->dname, 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 identified as: '%s'", bitforce->api->dname, bitforce->name);
bitforce->api = &bitforce_api;
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 +202,38 @@ 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, ">>>")))) { sprintf(devpath, "%d:%d",
s[0] = '\0'; (int)(bitforce->usbdev->bus_number),
bitforce->name = strdup(pdevbuf + 7); (int)(bitforce->usbdev->device_address));
}
mutex_init(&bitforce->device_mutex);
return add_cgpu(bitforce);
}
#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)
#ifdef WIN32 bitforce->device_path = strdup(devpath);
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 (!add_cgpu(bitforce))
if (ftStatus != FT_OK) { goto unshin;
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); mutex_init(&bitforce->device_mutex);
bufptrs = alloca(sizeof(*bufptrs) * (numDevs + 1));
for (i = 0; i < numDevs; ++i) return true;
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; ) { unshin:
--i;
bufptrs[i][64] = '\0';
if (!(strstr(bufptrs[i], "BitFORCE") && strstr(bufptrs[i], "SHA256"))) usb_uninit(bitforce);
continue;
FT_HANDLE ftHandle; shin:
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); free(bitforce->device_path);
if (bitforce_detect_one(devpath)) if (bitforce->name != blank)
++found; free(bitforce->name);
}
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 +250,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,18 +268,21 @@ 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)",
/* Once we've tried - don't do it until told to again */ bitforce->api->name, bitforce->device_id, amount, err);
bitforce->flash_led = false; } else {
/* However, this stops anything else getting a reply /* However, this stops anything else getting a reply
* So best to delay any other access to the BFL */ * So best to delay any other access to the BFL */
sleep(4); sleep(4);
}
/* Once we've tried - don't do it until told to again */
bitforce->flash_led = false;
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
@ -373,13 +291,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 +311,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';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
mutex_unlock(&bitforce->device_mutex); 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 (unlikely(!pdevbuf[0])) { if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETTEMPERATURE)) < 0 || amount < 1) {
applog(LOG_ERR, "BFL%i: Error: Get temp returned empty string/timed out", bitforce->device_id); 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++; bitforce->hw_errors++;
return false; return false;
} }
if ((!strncasecmp(pdevbuf, "TEMP", 4)) && (s = strchr(pdevbuf + 4, ':'))) { 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 +345,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 +355,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 +370,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 +426,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 +438,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 +483,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 +545,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 +578,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 +595,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 +629,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 +656,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 +682,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,

133
usbutils.c

@ -36,11 +36,20 @@
#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 200
#define MODMINER_TIMEOUT_MS 200 #define MODMINER_TIMEOUT_MS 200
#else #else
#define BITFORCE_TIMEOUT_MS 100
#define MODMINER_TIMEOUT_MS 100 #define MODMINER_TIMEOUT_MS 100
#endif #endif
#ifdef USE_BITFORCE
static struct usb_endpoints bfl_eps[] = {
{ LIBUSB_TRANSFER_TYPE_BULK, 512, EPI(1), 0 },
{ LIBUSB_TRANSFER_TYPE_BULK, 512, EPO(2), 0 }
};
#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 +57,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 +65,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 #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 #endif
*/
#ifdef USE_MODMINER #ifdef USE_MODMINER
{ {
.drv = DRV_MODMINER, .drv = DRV_MODMINER,
@ -160,6 +178,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 +535,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 +568,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 +788,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 +816,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 +1161,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 +1204,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 +1281,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

@ -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…
Cancel
Save