Browse Source

Merge branch 'master' into hashfast

Conflicts:
	Makefile.am
	api.c
	cgminer.c
	configure.ac
	miner.h
	usbutils.c
	usbutils.h
nfactor-troky
Con Kolivas 11 years ago
parent
commit
f49a3c7657
  1. 3
      01-cgminer.rules
  2. 21
      ASIC-README
  3. 8
      Makefile.am
  4. 137
      NEWS
  5. 90
      api.c
  6. 182
      cgminer.c
  7. 27
      configure.ac
  8. 23
      driver-avalon.c
  9. 1
      driver-avalon.h
  10. 6
      driver-bflsc.c
  11. 6
      driver-bitforce.c
  12. 330
      driver-bitfury.c
  13. 30
      driver-bitfury.h
  14. 11
      driver-hashfast.c
  15. 103
      driver-icarus.c
  16. 6
      driver-modminer.c
  17. 20
      driver-opencl.c
  18. 6
      driver-ztex.c
  19. 56
      miner.h
  20. 681
      usbutils.c
  21. 92
      usbutils.h
  22. 6
      util.c
  23. 1
      util.h

3
01-cgminer.rules

@ -18,3 +18,6 @@ ATTRS{idVendor}=="067b", ATTRS{idProduct}=="0230", SUBSYSTEMS=="usb", ACTION=="a
# Ztex # Ztex
ATTRS{idVendor}=="221a", ATTRS{idProduct}=="0100", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev" ATTRS{idVendor}=="221a", ATTRS{idProduct}=="0100", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev"
# BF1
ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204b", SUBSYSTEMS=="usb", ACTION=="add", MODE="0666", GROUP="plugdev"

21
ASIC-README

@ -1,10 +1,10 @@
SUPPORTED DEVICES SUPPORTED DEVICES
Currently supported devices include the Avalon (including BitBurner), the Currently supported devices include the Avalon (including BitBurner), the
Butterfly Labs SC range of devices and the ASICMINER block erupters. No COM Butterfly Labs SC range of devices, the ASICMINER block erupters and the BPMC
ports on windows or TTY devices will be used by cgminer as it communicates BF1 (bitfury) USB devices. No COM ports on windows or TTY devices will be used
directly with them via USB so it is normal for them to not exist or be by cgminer as it communicates directly with them via USB so it is normal for
disconnected when cgminer is running. them to not exist or be disconnected when cgminer is running.
The BFL devices should come up as one of the following: The BFL devices should come up as one of the following:
@ -24,7 +24,18 @@ ASICMINER block erupters will come up as AMU.
ASICMINER devices need the --enable-icarus option when compiling cgminer. ASICMINER devices need the --enable-icarus option when compiling cgminer.
Also note that the AMU is managed by the Icarus driver which is detailed Also note that the AMU is managed by the Icarus driver which is detailed
in the FPGA-README in the FPGA-README. Configuring them uses the same mechanism as outlined
below for getting started with butterfly labs ASICs.
BITFURY devices
Bitfury devices need the --enable-bitfury option when compiling cgminer.
Currently only the BPMC BF1 devices AKA redfury/bluefury are supported and
come up as BF1. There are no options available for them. Bitfury device are
also set up as per the butterfly labs ASICs below.
GETTING STARTED WITH BUTTERFLY LABS ASICS GETTING STARTED WITH BUTTERFLY LABS ASICS

8
Makefile.am

@ -86,6 +86,14 @@ if HAS_HASHFAST
cgminer_SOURCES += driver-hashfast.c driver-hashfast.h cgminer_SOURCES += driver-hashfast.c driver-hashfast.h
endif endif
if HAS_BITFURY
cgminer_SOURCES += driver-bitfury.c driver-bitfury.h
endif
if HAS_ICARUS
cgminer_SOURCES += driver-icarus.c
endif
if HAS_ICARUS if HAS_ICARUS
cgminer_SOURCES += driver-icarus.c cgminer_SOURCES += driver-icarus.c
endif endif

137
NEWS

@ -1,3 +1,140 @@
Version 3.5.0 - 29th September 2013
- Add magic init sequence required on BF1 devices to get them mining on windows.
- usbinfo.devlock is only ever write locked so convert it to a mutex
- Icarus remove unneeded opt_debug tests due to applog being a macro
- Icarus - CMR shouldn't wait the full timeout due to handle sharing
- We should only yield once in cg_wunlock
- Provide a function to downgrade a cglock from a write lock to an intermediate
variant.
- Deuglify use of _PARSE_COMMANDS macro expansions.
- Deuglify use of usb parse commands macro in usbutils.
- Use the driver add commands macros in api.c to avoid individually listing
them.
- Separate out asic fpga and opencl drivers in the driver parse commands macro
for use individually as needed.
- Use macro expansion in usb_find_devices to avoid explicitly listing them all.
- Use macro expansion to iterate over all the drivers without explicitly writing
them out in usbutils.c
- Iterate over the bitfury offsets in order of decreasing likelihood.
- Reattach the kernel driver on linux on usb_uninit.
- Attach the kernel driver on failure to usb init on linux.
- libusb kernel driver operations are only available on linux.
- There is no need to get the external prototypes for drivers in cgminer.c any
more.
- Remove unnecessary gpu_threads initialisation.
- Put avalon last in the sequence of adding drivers to prevent it trying to
claim similar chip devices on startup.
- Use macro expansion to iterate over all device drivers without needing to
explicitly code in support in all places. Pass a hotplug bool to the detect()
function to prevent opencl trying to hogplug GPUs.
- Forward declare all device drivers in miner.h avoiding the need to export them
everywhere else.
- Add a noop function for driver detect when it's missing.
- Reuse the DRIVER_ macros to avoid having yet another definition for DRV_
- Use macro expansion to generate extern device_drv prototypes.
- Create a macro list of drivers to enable easier addition of further drivers.
- There is no point setting the BF1 preferred packet size to the maximum since
it will do so automatically.
- icarus ensure all cmr interfaces are initialised properly
- usbutils - fix USBDEBUG warnings
- Remove unnecessary steps in communicating with BF1 and just use USB interface
1.
- usbutils - usb_bulk_transfer fix the buf/data fix
- usb_bulk_transfer - use the allocated buffer
- Set preferred packet sizes per interface on BF1.
- usbutils allow PrefPacketSize per endpoint
- Remove magic control sequences on open/close on BF1 and just flush the read
buffers.
- Check return codes in getinfo and reset and fail as needed in BF1.
- Check return code for bitfury_open and release resources properly on failed
initialisation.
- Abstract out flushing of interrupt reads in BF1 devices.
- Perform interrupt read after close message on BF1 as per serial close.
- Perform interrupt read flush as per serial open on BF1 devices.
- Add information for 2nd USB interface on BF1 devices and choose interface 1
for bulk transfers.
- usbutils - bulk transfer copy test fix
- usbutils - add USBDEBUG for usb_bulk_transfer
- Add more read_ii variants to usbutils.
- Name remainder of BFU usb commands used.
- Use submit_tested_work in bitfury driver to avoid unnecessarily re-testing the
work for validity.
- Abstract out work submission once it's been tested, to be used by drivers that
do their own internal validity testing.
- Store the hash2 array in struct work for further reuse.
- usbutils - which_intinfo not requried
- Use the test_nonce function within submit_nonce and store the uint32
corresponding to hash2 37 for further use.
- usbutils - interfaces must all be on one handle - ep implies the interface
- avalon stats use exact type
- Only set share diff if we've confirmed it's a share first.
- Update ASIC-README for bitfury devices.
- Use an array of offsets when checking nonces in bitfury_checkresults
- Limit the duration we wait for reads in BF1 based on time already elapsed to
account for other delays such as work restart messages or out of work.
- Minimise size of serial string we copy in BF1 stats to avoid overflow.
- Implement basic API stats for BF1 and increase array of results to check for
the rare straggling result.
- Space debug output for bf1 to separate from numerals.
- Abstract out the bitfury open close and reset functions and use them on
reinit.
- Rename BF1 devices BF1
- Check for work restart, breaking out early after usb reads in BF1.
- Do not lose the first sets of results from BF1.
- There is no point checking for results from the next round of work on BF1.
- Last result returned by BF1 is an end of results marker so ignore it.
- restart_wait should return 0 if thr_restart is true.
- Remove unused code by bitfury driver since current driver uses serialised
scanhash.
- Meter out return of estimated hashes in BF1 to smooth out visible hashrate.
- Optimise inner scanhash loop for bf1.
- Add yet another backup work for triple buffering of work in bf1 to account for
extra late results returned and don't check nonce offsets which appear to never
return.
- Name the work request and result usb commands for BF1
- Define a mandatory upper limit to waiting for reset and data on BF1 based on
full nonce duration.
- Decrease usb buffering to verbose logging.
- Add in first draft for a serialised work model sending/receiving data for BF1
devices.
- Add complete close sequence to bf1 as it happens on serial.
- Provide a bitfury identify function for bf1.
- Reliably extract BF1 information at startup and reset the device.
- Add commands for getting BF1 bitfury info
- Add magic BF1 bitfury open and close control sequences.
- Add BF1 detection code to bitfury driver.
- Create basic placeholders for bitfury driver code.
- Add bf1 device information to usbutils to enable device detection.
- Add basic defines for building for bitfury devices.
- Add redfury device to udev rules.
- avalon: display the FPGA controller version on API
- pool_active uninitialised_var rolltime
- Use macro expansion to only need to define usb enums and commands in one
place.
- usbutils saving incorrect overflow buffer
- ignore libusb.la and *.lo on linux
- icarus support CMR with no extensions
- usbtils - interfaces dont work yet in libusb windows so disable for that only
- Provide a --disable-libcurl config option to build support for stratum mining
only.
- Fix the api-example.c compile under Linux
- usbutils - only release the device once - for the first intinfo
- usbutils set_interface is no longer valid
- ubsutils interfaces much each have their own handle
- usbutils kernel_detach should use the interface number
- usbutils - allow the driver to change which_intinfo
- Reset quotas on load balance for all pools at the same time to avoid running
out during selection and unintentionally dropping to fallback.
- Break out of select pool from a common point for appropriate debug messages
and to avoid further tests.
- usbutils correct/reverse CMR product numbers
- usbutils specifically track handles and interfaces
- change drivers to use usb_interface() - required for multi interface change
- usbutils - allow a device to use multiple interfaces (and better var names)
- Cast -1 to (char) to cope with different default char types on ARM.
Version 3.4.3 - 13th September 2013 Version 3.4.3 - 13th September 2013
- Put corefoundation and iokit separate in ldflags for darwin. - Put corefoundation and iokit separate in ldflags for darwin.

90
api.c

@ -29,7 +29,7 @@
#include "miner.h" #include "miner.h"
#include "util.h" #include "util.h"
#if defined(USE_BFLSC) || defined(USE_AVALON) || defined(USE_HASHFAST) #if defined(USE_BFLSC) || defined(USE_AVALON) || defined(USE_HASHFAST) || defined(USE_BITFURY)
#define HAVE_AN_ASIC 1 #define HAVE_AN_ASIC 1
#endif #endif
@ -167,8 +167,8 @@ static const char *SCRYPTSTR = "scrypt";
static const char *SHA256STR = "sha256"; static const char *SHA256STR = "sha256";
static const char *DEVICECODE = "" static const char *DEVICECODE = ""
#ifdef HAVE_OPENCL #ifdef USE_AVALON
"GPU " "AVA "
#endif #endif
#ifdef USE_BFLSC #ifdef USE_BFLSC
"BAS " "BAS "
@ -176,20 +176,23 @@ static const char *DEVICECODE = ""
#ifdef USE_BITFORCE #ifdef USE_BITFORCE
"BFL " "BFL "
#endif #endif
#ifdef USE_BITFURY
"BFU "
#endif
#ifdef HAVE_OPENCL
"GPU "
#endif
#ifdef USE_HASHFAST #ifdef USE_HASHFAST
"HFA " "HFA "
#endif #endif
#ifdef USE_ICARUS #ifdef USE_ICARUS
"ICA " "ICA "
#endif #endif
#ifdef USE_AVALON #ifdef USE_MODMINER
"AVA " "MMQ "
#endif #endif
#ifdef USE_ZTEX #ifdef USE_ZTEX
"ZTX " "ZTX "
#endif
#ifdef USE_MODMINER
"MMQ "
#endif #endif
""; "";
@ -1211,26 +1214,18 @@ static struct api_data *print_data(struct api_data *root, char *buf, bool isjson
return root; return root;
} }
#define DRIVER_COUNT_DRV(X) if (devices[i]->drv->drv_id == DRIVER_##X) \
count++;
#ifdef HAVE_AN_ASIC #ifdef HAVE_AN_ASIC
static int numascs() static int numascs(void)
{ {
int count = 0; int count = 0;
int i; int i;
rd_lock(&devices_lock); rd_lock(&devices_lock);
for (i = 0; i < total_devices; i++) { for (i = 0; i < total_devices; i++) {
#ifdef USE_AVALON ASIC_PARSE_COMMANDS(DRIVER_COUNT_DRV)
if (devices[i]->drv->drv_id == DRIVER_AVALON)
count++;
#endif
#ifdef USE_BFLSC
if (devices[i]->drv->drv_id == DRIVER_BFLSC)
count++;
#endif
#ifdef USE_HASHFAST
if (devices[i]->drv->drv_id == DRIVER_HASHFAST)
count++;
#endif
} }
rd_unlock(&devices_lock); rd_unlock(&devices_lock);
return count; return count;
@ -1243,18 +1238,7 @@ static int ascdevice(int ascid)
rd_lock(&devices_lock); rd_lock(&devices_lock);
for (i = 0; i < total_devices; i++) { for (i = 0; i < total_devices; i++) {
#ifdef USE_AVALON ASIC_PARSE_COMMANDS(DRIVER_COUNT_DRV)
if (devices[i]->drv->drv_id == DRIVER_AVALON)
count++;
#endif
#ifdef USE_BFLSC
if (devices[i]->drv->drv_id == DRIVER_BFLSC)
count++;
#endif
#ifdef USE_HASHFAST
if (devices[i]->drv->drv_id == DRIVER_HASHFAST)
count++;
#endif
if (count == (ascid + 1)) if (count == (ascid + 1))
goto foundit; goto foundit;
} }
@ -1270,29 +1254,14 @@ foundit:
#endif #endif
#ifdef HAVE_AN_FPGA #ifdef HAVE_AN_FPGA
static int numpgas() static int numpgas(void)
{ {
int count = 0; int count = 0;
int i; int i;
rd_lock(&devices_lock); rd_lock(&devices_lock);
for (i = 0; i < total_devices; i++) { for (i = 0; i < total_devices; i++) {
#ifdef USE_BITFORCE FPGA_PARSE_COMMANDS(DRIVER_COUNT_DRV)
if (devices[i]->drv->drv_id == DRIVER_BITFORCE)
count++;
#endif
#ifdef USE_ICARUS
if (devices[i]->drv->drv_id == DRIVER_ICARUS)
count++;
#endif
#ifdef USE_ZTEX
if (devices[i]->drv->drv_id == DRIVER_ZTEX)
count++;
#endif
#ifdef USE_MODMINER
if (devices[i]->drv->drv_id == DRIVER_MODMINER)
count++;
#endif
} }
rd_unlock(&devices_lock); rd_unlock(&devices_lock);
return count; return count;
@ -1305,22 +1274,7 @@ static int pgadevice(int pgaid)
rd_lock(&devices_lock); rd_lock(&devices_lock);
for (i = 0; i < total_devices; i++) { for (i = 0; i < total_devices; i++) {
#ifdef USE_BITFORCE FPGA_PARSE_COMMANDS(DRIVER_COUNT_DRV)
if (devices[i]->drv->drv_id == DRIVER_BITFORCE)
count++;
#endif
#ifdef USE_ICARUS
if (devices[i]->drv->drv_id == DRIVER_ICARUS)
count++;
#endif
#ifdef USE_ZTEX
if (devices[i]->drv->drv_id == DRIVER_ZTEX)
count++;
#endif
#ifdef USE_MODMINER
if (devices[i]->drv->drv_id == DRIVER_MODMINER)
count++;
#endif
if (count == (pgaid + 1)) if (count == (pgaid + 1))
goto foundit; goto foundit;
} }
@ -1770,11 +1724,11 @@ static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom
dev_runtime = 1.0; dev_runtime = 1.0;
#ifdef USE_ZTEX #ifdef USE_ZTEX
if (cgpu->drv->drv_id == DRIVER_ZTEX && cgpu->device_ztex) if (cgpu->drv->drv_id == DRIVER_ztex && cgpu->device_ztex)
frequency = cgpu->device_ztex->freqM1 * (cgpu->device_ztex->freqM + 1); frequency = cgpu->device_ztex->freqM1 * (cgpu->device_ztex->freqM + 1);
#endif #endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
if (cgpu->drv->drv_id == DRIVER_MODMINER) if (cgpu->drv->drv_id == DRIVER_modminer)
frequency = cgpu->clock; frequency = cgpu->clock;
#endif #endif

182
cgminer.c

@ -123,7 +123,7 @@ bool opt_scrypt;
#endif #endif
#endif #endif
bool opt_restart = true; bool opt_restart = true;
static bool opt_nogpu; bool opt_nogpu;
struct list_head scan_devices; struct list_head scan_devices;
static bool devices_enabled[MAX_DEVICES]; static bool devices_enabled[MAX_DEVICES];
@ -1567,6 +1567,9 @@ static char *opt_verusage_and_exit(const char *extra)
#ifdef USE_BITFORCE #ifdef USE_BITFORCE
"bitforce " "bitforce "
#endif #endif
#ifdef USE_BITFURY
"bitfury "
#endif
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
"GPU " "GPU "
#endif #endif
@ -3662,15 +3665,6 @@ static void rebuild_hash(struct work *work)
scrypt_regenhash(work); scrypt_regenhash(work);
else else
regen_hash(work); regen_hash(work);
work->share_diff = share_diff(work);
if (unlikely(work->share_diff >= current_diff)) {
work->block = true;
work->pool->solved++;
found_blocks++;
work->mandatory = true;
applog(LOG_NOTICE, "Found block for pool %d!", work->pool->pool_no);
}
} }
static bool cnx_needed(struct pool *pool); static bool cnx_needed(struct pool *pool);
@ -3848,7 +3842,7 @@ int restart_wait(struct thr_info *thr, unsigned int mstime)
mutex_lock(&restart_lock); mutex_lock(&restart_lock);
if (thr->work_restart) if (thr->work_restart)
rc = ETIMEDOUT; rc = 0;
else else
rc = pthread_cond_timedwait(&restart_cond, &restart_lock, &abstime); rc = pthread_cond_timedwait(&restart_cond, &restart_lock, &abstime);
mutex_unlock(&restart_lock); mutex_unlock(&restart_lock);
@ -5578,7 +5572,7 @@ static bool pool_active(struct pool *pool, bool pinging)
bool ret = false; bool ret = false;
json_t *val; json_t *val;
CURL *curl; CURL *curl;
int rolltime; int uninitialised_var(rolltime);
if (pool->has_gbt) if (pool->has_gbt)
applog(LOG_DEBUG, "Retrieving block template from pool %s", pool->rpc_url); applog(LOG_DEBUG, "Retrieving block template from pool %s", pool->rpc_url);
@ -6020,17 +6014,12 @@ void inc_hw_errors(struct thr_info *thr)
thr->cgpu->drv->hw_error(thr); thr->cgpu->drv->hw_error(thr);
} }
/* Returns true if nonce for work was a valid share */ bool test_nonce(struct work *work, uint32_t nonce)
bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
{ {
uint32_t *work_nonce = (uint32_t *)(work->data + 64 + 12); uint32_t *work_nonce = (uint32_t *)(work->data + 64 + 12);
struct timeval tv_work_found; uint32_t *hash2_32 = (uint32_t *)work->hash2;
unsigned char hash2[32];
uint32_t *hash2_32 = (uint32_t *)hash2;
uint32_t diff1targ; uint32_t diff1targ;
bool ret = true;
cgtime(&tv_work_found);
*work_nonce = htole32(nonce); *work_nonce = htole32(nonce);
/* Do one last check before attempting to submit the work */ /* Do one last check before attempting to submit the work */
@ -6038,14 +6027,16 @@ bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
flip32(hash2_32, work->hash); flip32(hash2_32, work->hash);
diff1targ = opt_scrypt ? 0x0000ffffUL : 0; diff1targ = opt_scrypt ? 0x0000ffffUL : 0;
if (be32toh(hash2_32[7]) > diff1targ) { return (be32toh(hash2_32[7]) <= diff1targ);
applog(LOG_INFO, "%s%d: invalid nonce - HW error", }
thr->cgpu->drv->name, thr->cgpu->device_id);
inc_hw_errors(thr); /* To be used once the work has been tested to be meet diff1 and has had its
ret = false; * nonce adjusted. */
goto out; void submit_tested_work(struct thr_info *thr, struct work *work)
} {
struct timeval tv_work_found;
work->share_diff = share_diff(work);
mutex_lock(&stats_lock); mutex_lock(&stats_lock);
total_diff1 += work->device_diff; total_diff1 += work->device_diff;
@ -6054,13 +6045,30 @@ bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
thr->cgpu->last_device_valid_work = time(NULL); thr->cgpu->last_device_valid_work = time(NULL);
mutex_unlock(&stats_lock); mutex_unlock(&stats_lock);
if (!fulltest(hash2, work->target)) { if (!fulltest(work->hash2, work->target)) {
applog(LOG_INFO, "Share below target"); applog(LOG_INFO, "Share below target");
goto out; return;
} }
cgtime(&tv_work_found);
submit_work_async(work, &tv_work_found); submit_work_async(work, &tv_work_found);
out: }
/* Returns true if nonce for work was a valid share */
bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
{
bool ret = true;
if (test_nonce(work, nonce))
submit_tested_work(thr, work);
else {
applog(LOG_INFO, "%s%d: invalid nonce - HW error",
thr->cgpu->drv->name, thr->cgpu->device_id);
inc_hw_errors(thr);
ret = false;
}
return ret; return ret;
} }
@ -7351,34 +7359,6 @@ void enable_curses(void) {
} }
#endif #endif
#ifdef USE_BFLSC
extern struct device_drv bflsc_drv;
#endif
#ifdef USE_BITFORCE
extern struct device_drv bitforce_drv;
#endif
#ifdef USE_HASHFAST
extern struct device_drv hashfast_drv;
#endif
#ifdef USE_ICARUS
extern struct device_drv icarus_drv;
#endif
#ifdef USE_AVALON
extern struct device_drv avalon_drv;
#endif
#ifdef USE_MODMINER
extern struct device_drv modminer_drv;
#endif
#ifdef USE_ZTEX
extern struct device_drv ztex_drv;
#endif
static int cgminer_id_count = 0; static int cgminer_id_count = 0;
/* Various noop functions for drivers that don't support or need their /* Various noop functions for drivers that don't support or need their
@ -7433,14 +7413,17 @@ static void noop_thread_enable(struct thr_info __maybe_unused *thr)
{ {
} }
static void noop_detect(bool __maybe_unused hotplug)
{
}
#define noop_flush_work noop_reinit_device #define noop_flush_work noop_reinit_device
#define noop_queue_full noop_get_stats #define noop_queue_full noop_get_stats
/* Fill missing driver drv functions with noops */ /* Fill missing driver drv functions with noops */
void fill_device_drv(struct cgpu_info *cgpu) void fill_device_drv(struct device_drv *drv)
{ {
struct device_drv *drv = cgpu->drv; if (!drv->drv_detect)
drv->drv_detect = &noop_detect;
if (!drv->reinit_device) if (!drv->reinit_device)
drv->reinit_device = &noop_reinit_device; drv->reinit_device = &noop_reinit_device;
if (!drv->get_statline_before) if (!drv->get_statline_before)
@ -7495,7 +7478,7 @@ void enable_device(struct cgpu_info *cgpu)
#endif #endif
} }
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
if (cgpu->drv->drv_id == DRIVER_OPENCL) { if (cgpu->drv->drv_id == DRIVER_opencl) {
gpu_threads += cgpu->threads; gpu_threads += cgpu->threads;
} }
#endif #endif
@ -7538,8 +7521,6 @@ bool add_cgpu(struct cgpu_info *cgpu)
cgpu->last_device_valid_work = time(NULL); cgpu->last_device_valid_work = time(NULL);
mutex_unlock(&stats_lock); mutex_unlock(&stats_lock);
fill_device_drv(cgpu);
if (hotplug_mode) if (hotplug_mode)
devices[total_devices + new_devices++] = cgpu; devices[total_devices + new_devices++] = cgpu;
else else
@ -7630,6 +7611,8 @@ static void hotplug_process()
switch_logsize(true); switch_logsize(true);
} }
#define DRIVER_DRV_DETECT_HOTPLUG(X) X##_drv.drv_detect(true);
static void *hotplug_thread(void __maybe_unused *userdata) static void *hotplug_thread(void __maybe_unused *userdata)
{ {
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
@ -7649,29 +7632,9 @@ static void *hotplug_thread(void __maybe_unused *userdata)
new_devices = 0; new_devices = 0;
new_threads = 0; new_threads = 0;
#ifdef USE_ICARUS /* Use the DRIVER_PARSE_COMMANDS macro to detect all
icarus_drv.drv_detect(); * devices */
#endif DRIVER_PARSE_COMMANDS(DRIVER_DRV_DETECT_HOTPLUG)
#ifdef USE_BFLSC
bflsc_drv.drv_detect();
#endif
#ifdef USE_BITFORCE
bitforce_drv.drv_detect();
#endif
#ifdef USE_HASHFAST
hashfast_drv.drv_detect();
#endif
#ifdef USE_MODMINER
modminer_drv.drv_detect();
#endif
#ifdef USE_AVALON
avalon_drv.drv_detect();
#endif
if (new_devices) if (new_devices)
hotplug_process(); hotplug_process();
@ -7697,6 +7660,9 @@ static void probe_pools(void)
} }
} }
#define DRIVER_FILL_DEVICE_DRV(X) fill_device_drv(&X##_drv);
#define DRIVER_DRV_DETECT_ALL(X) X##_drv.drv_detect(false);
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
struct sigaction handler; struct sigaction handler;
@ -7877,44 +7843,14 @@ int main(int argc, char *argv[])
} }
#endif #endif
#ifdef HAVE_OPENCL /* Use the DRIVER_PARSE_COMMANDS macro to fill all the device_drvs */
if (!opt_nogpu) DRIVER_PARSE_COMMANDS(DRIVER_FILL_DEVICE_DRV)
opencl_drv.drv_detect();
gpu_threads = 0;
#endif
if (!opt_scrypt) {
#ifdef USE_ICARUS
icarus_drv.drv_detect();
#endif
#ifdef USE_BFLSC
bflsc_drv.drv_detect();
#endif
#ifdef USE_BITFORCE
bitforce_drv.drv_detect();
#endif
#ifdef USE_HASHFAST if (opt_scrypt)
hf_init_crc8(); opencl_drv.drv_detect(false);
hf_init_crc32(); else {
hashfast_drv.drv_detect(); /* Use the DRIVER_PARSE_COMMANDS macro to detect all devices */
#endif DRIVER_PARSE_COMMANDS(DRIVER_DRV_DETECT_ALL)
#ifdef USE_MODMINER
modminer_drv.drv_detect();
#endif
#ifdef USE_ZTEX
ztex_drv.drv_detect();
#endif
/* Detect avalon last since it will try to claim the device regardless
* as detection is unreliable. */
#ifdef USE_AVALON
avalon_drv.drv_detect();
#endif
} }
if (opt_display_devs) { if (opt_display_devs) {

27
configure.ac

@ -1,8 +1,8 @@
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
m4_define([v_maj], [3]) m4_define([v_maj], [3])
m4_define([v_min], [4]) m4_define([v_min], [5])
m4_define([v_mic], [3]) m4_define([v_mic], [0])
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
m4_define([v_ver], [v_maj.v_min.v_mic]) m4_define([v_ver], [v_maj.v_min.v_mic])
m4_define([lt_rev], m4_eval(v_maj + v_min)) m4_define([lt_rev], m4_eval(v_maj + v_min))
@ -253,6 +253,17 @@ if test "x$bitforce" = xyes; then
fi fi
AM_CONDITIONAL([HAS_BITFORCE], [test x$bitforce = xyes]) AM_CONDITIONAL([HAS_BITFORCE], [test x$bitforce = xyes])
bitfury="no"
AC_ARG_ENABLE([bitfury],
[AC_HELP_STRING([--enable-bitfury],[Compile support for BitFury ASICs (default disabled)])],
[bitfury=$enableval]
)
if test "x$bitfury" = xyes; then
AC_DEFINE([USE_BITFURY], [1], [Defined to 1 if BitForce support is wanted])
fi
AM_CONDITIONAL([HAS_BITFURY], [test x$bitfury = xyes])
hashfast="no" hashfast="no"
AC_ARG_ENABLE([hashfast], AC_ARG_ENABLE([hashfast],
@ -321,7 +332,7 @@ else
]) ])
fi fi
if test x$avalon$bitforce$modminer$bflsc$icarus$hashfast != xnononononono; then if test x$avalon$bitforce$bitfury$modminer$bflsc$icarus$hashfast != xnonononononono; then
want_usbutils=true want_usbutils=true
else else
want_usbutils=false want_usbutils=false
@ -493,14 +504,14 @@ if test "x$opencl" != xno; then
else else
echo " OpenCL...............: NOT FOUND. GPU mining support DISABLED" echo " OpenCL...............: NOT FOUND. GPU mining support DISABLED"
if test "x$bitforce$avalon$icarus$ztex$modminer$bflsc$hashfast" = xnonononononono; then if test "x$avalon$bitforce$bitfury$icarus$ztex$modminer$bflsc$hashfast" = xnononononononono; then
AC_MSG_ERROR([No mining configured in]) AC_MSG_ERROR([No mining configured in])
fi fi
echo " scrypt...............: Disabled (needs OpenCL)" echo " scrypt...............: Disabled (needs OpenCL)"
fi fi
else else
echo " OpenCL...............: Detection overrided. GPU mining support DISABLED" echo " OpenCL...............: Detection overrided. GPU mining support DISABLED"
if test "x$bitforce$icarus$avalon$ztex$modminer$bflsc$hashfast" = xnonononononono; then if test "x$avalon$bitforce$bitfury$icarus$ztex$modminer$bflsc$hashfast" = xnononononononono; then
AC_MSG_ERROR([No mining configured in]) AC_MSG_ERROR([No mining configured in])
fi fi
echo " scrypt...............: Disabled (needs OpenCL)" echo " scrypt...............: Disabled (needs OpenCL)"
@ -535,6 +546,12 @@ else
echo " BitForce.FPGAs.......: Disabled" echo " BitForce.FPGAs.......: Disabled"
fi fi
if test "x$bitfury" = xyes; then
echo " BitFury.ASICs........: Enabled"
else
echo " BitFury.ASICs........: Disabled"
fi
if test "x$hashfast" = xyes; then if test "x$hashfast" = xyes; then
echo " Hashfast.ASICs.......: Enabled" echo " Hashfast.ASICs.......: Enabled"
else else

23
driver-avalon.c

@ -52,7 +52,6 @@ int opt_bitburner_core_voltage = BITBURNER_DEFAULT_CORE_VOLTAGE;
bool opt_avalon_auto; bool opt_avalon_auto;
static int option_offset = -1; static int option_offset = -1;
struct device_drv avalon_drv;
static int avalon_init_task(struct avalon_task *at, static int avalon_init_task(struct avalon_task *at,
uint8_t reset, uint8_t ff, uint8_t fan, uint8_t reset, uint8_t ff, uint8_t fan,
@ -273,6 +272,7 @@ static int avalon_reset(struct cgpu_info *avalon, bool initial)
struct avalon_task at; struct avalon_task at;
uint8_t *buf, *tmp; uint8_t *buf, *tmp;
struct timespec p; struct timespec p;
struct avalon_info *info = avalon->device_data;
/* Send reset, then check for result */ /* Send reset, then check for result */
avalon_init_task(&at, 1, 0, avalon_init_task(&at, 1, 0,
@ -329,9 +329,17 @@ static int avalon_reset(struct cgpu_info *avalon, bool initial)
" (%d: %02x %02x %02x %02x)", avalon->drv->name, avalon->device_id, " (%d: %02x %02x %02x %02x)", avalon->drv->name, avalon->device_id,
i, buf[0], buf[1], buf[2], buf[3]); i, buf[0], buf[1], buf[2], buf[3]);
/* FIXME: return 1; */ /* FIXME: return 1; */
} else } else {
applog(LOG_WARNING, "%s%d: Reset succeeded", /* buf[44]: minor
avalon->drv->name, avalon->device_id); * buf[45]: day
* buf[46]: year,month, d6: 201306
*/
info->ctlr_ver = ((buf[46] >> 4) + 2000) * 1000000 +
(buf[46] & 0x0f) * 10000 +
buf[45] * 100 + buf[44];
applog(LOG_WARNING, "%s%d: Reset succeeded (Controller version: %d)",
avalon->drv->name, avalon->device_id, info->ctlr_ver);
}
return 0; return 0;
} }
@ -711,7 +719,7 @@ static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found
/* Even though this is an FTDI type chip, we want to do the parsing /* Even though this is an FTDI type chip, we want to do the parsing
* all ourselves so set it to std usb type */ * all ourselves so set it to std usb type */
avalon->usbdev->usb_type = USB_TYPE_STD; avalon->usbdev->usb_type = USB_TYPE_STD;
avalon->usbdev->PrefPacketSize = AVALON_USB_PACKETSIZE; usb_set_pps(avalon, AVALON_USB_PACKETSIZE);
/* We have a real Avalon! */ /* We have a real Avalon! */
avalon_initialise(avalon); avalon_initialise(avalon);
@ -791,7 +799,7 @@ shin:
return false; return false;
} }
static void avalon_detect(void) static void avalon_detect(bool __maybe_unused hotplug)
{ {
usb_detect(&avalon_drv, avalon_detect_one); usb_detect(&avalon_drv, avalon_detect_one);
} }
@ -1522,6 +1530,7 @@ static struct api_data *avalon_api_stats(struct cgpu_info *cgpu)
info->version1, info->version2, info->version3); info->version1, info->version2, info->version3);
root = api_add_string(root, "version", buf, true); root = api_add_string(root, "version", buf, true);
} }
root = api_add_uint32(root, "Controller Version", &(info->ctlr_ver), false);
return root; return root;
} }
@ -1590,7 +1599,7 @@ static char *avalon_set_device(struct cgpu_info *avalon, char *option, char *set
} }
struct device_drv avalon_drv = { struct device_drv avalon_drv = {
.drv_id = DRIVER_AVALON, .drv_id = DRIVER_avalon,
.dname = "avalon", .dname = "avalon",
.name = "AVA", .name = "AVA",
.drv_detect = avalon_detect, .drv_detect = avalon_detect,

1
driver-avalon.h

@ -125,6 +125,7 @@ struct avalon_info {
int matching_work[AVALON_DEFAULT_MINER_NUM]; int matching_work[AVALON_DEFAULT_MINER_NUM];
int frequency; int frequency;
uint32_t ctlr_ver;
struct thr_info *thr; struct thr_info *thr;
pthread_t read_thr; pthread_t read_thr;

6
driver-bflsc.c

@ -33,8 +33,6 @@ int opt_bflsc_overheat = BFLSC_TEMP_OVERHEAT;
static const char *blank = ""; static const char *blank = "";
struct device_drv bflsc_drv;
static enum driver_version drv_ver(struct cgpu_info *bflsc, const char *ver) static enum driver_version drv_ver(struct cgpu_info *bflsc, const char *ver)
{ {
char *tmp; char *tmp;
@ -895,7 +893,7 @@ shin:
return false; return false;
} }
static void bflsc_detect(void) static void bflsc_detect(bool __maybe_unused hotplug)
{ {
usb_detect(&bflsc_drv, bflsc_detect_one); usb_detect(&bflsc_drv, bflsc_detect_one);
} }
@ -1915,7 +1913,7 @@ else a whole lot of something like these ... etc
} }
struct device_drv bflsc_drv = { struct device_drv bflsc_drv = {
.drv_id = DRIVER_BFLSC, .drv_id = DRIVER_bflsc,
.dname = "BitForceSC", .dname = "BitForceSC",
.name = BFLSC_SINGLE, .name = BFLSC_SINGLE,
.drv_detect = bflsc_detect, .drv_detect = bflsc_detect,

6
driver-bitforce.c

@ -77,8 +77,6 @@
static const char *blank = ""; static const char *blank = "";
struct device_drv bitforce_drv;
static void bitforce_initialise(struct cgpu_info *bitforce, bool lock) static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
{ {
int err, interface; int err, interface;
@ -290,7 +288,7 @@ shin:
return false; return false;
} }
static void bitforce_detect(void) static void bitforce_detect(bool __maybe_unused hotplug)
{ {
usb_detect(&bitforce_drv, bitforce_detect_one); usb_detect(&bitforce_drv, bitforce_detect_one);
} }
@ -742,7 +740,7 @@ static struct api_data *bitforce_api_stats(struct cgpu_info *cgpu)
} }
struct device_drv bitforce_drv = { struct device_drv bitforce_drv = {
.drv_id = DRIVER_BITFORCE, .drv_id = DRIVER_bitforce,
.dname = "BitForce", .dname = "BitForce",
.name = "BFL", .name = "BFL",
.drv_detect = bitforce_detect, .drv_detect = bitforce_detect,

330
driver-bitfury.c

@ -0,0 +1,330 @@
/*
* Copyright 2013 Con Kolivas
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version. See COPYING for more details.
*/
#include "config.h"
#include "miner.h"
#include "driver-bitfury.h"
#include "sha2.h"
/* Wait longer 1/3 longer than it would take for a full nonce range */
#define BF1WAIT 1600
static void bitfury_empty_buffer(struct cgpu_info *bitfury)
{
char buf[512];
int amount;
do {
usb_read_once(bitfury, buf, 512, &amount, C_BF1_FLUSH);
} while (amount);
}
static void bitfury_open(struct cgpu_info *bitfury)
{
uint32_t buf[2];
bitfury_empty_buffer(bitfury);
/* Magic sequence to reset device only really needed for windows but
* harmless on linux. */
buf[0] = 0x80250000;
buf[1] = 0x00000800;
usb_transfer(bitfury, 0, 9, 1, 0, C_BF1_RESET);
usb_transfer(bitfury, 0x21, 0x22, 0, 0, C_BF1_OPEN);
usb_transfer_data(bitfury, 0x21, 0x20, 0x0000, 0, buf, 7, C_BF1_INIT);
}
static void bitfury_close(struct cgpu_info *bitfury)
{
bitfury_empty_buffer(bitfury);
}
static void bitfury_identify(struct cgpu_info *bitfury)
{
int amount;
usb_write(bitfury, "L", 1, &amount, C_BF1_IDENTIFY);
}
static bool bitfury_getinfo(struct cgpu_info *bitfury, struct bitfury_info *info)
{
int amount, err;
char buf[16];
err = usb_write(bitfury, "I", 1, &amount, C_BF1_REQINFO);
if (err) {
applog(LOG_INFO, "%s %d: Failed to write REQINFO",
bitfury->drv->name, bitfury->device_id);
return false;
}
err = usb_read(bitfury, buf, 14, &amount, C_BF1_GETINFO);
if (err) {
applog(LOG_INFO, "%s %d: Failed to read GETINFO",
bitfury->drv->name, bitfury->device_id);
return false;
}
if (amount != 14) {
applog(LOG_INFO, "%s %d: Getinfo received %d bytes instead of 14",
bitfury->drv->name, bitfury->device_id, amount);
return false;
}
info->version = buf[1];
memcpy(&info->product, buf + 2, 8);
memcpy(&info->serial, buf + 10, 4);
applog(LOG_INFO, "%s %d: Getinfo returned version %d, product %s serial %08x", bitfury->drv->name,
bitfury->device_id, info->version, info->product, info->serial);
bitfury_empty_buffer(bitfury);
return true;
}
static bool bitfury_reset(struct cgpu_info *bitfury)
{
int amount, err;
char buf[16];
err = usb_write(bitfury, "R", 1, &amount, C_BF1_REQRESET);
if (err) {
applog(LOG_INFO, "%s %d: Failed to write REQRESET",
bitfury->drv->name, bitfury->device_id);
return false;
}
err = usb_read_timeout(bitfury, buf, 7, &amount, BF1WAIT, C_BF1_GETRESET);
if (err) {
applog(LOG_INFO, "%s %d: Failed to read GETRESET",
bitfury->drv->name, bitfury->device_id);
return false;
}
if (amount != 7) {
applog(LOG_INFO, "%s %d: Getreset received %d bytes instead of 7",
bitfury->drv->name, bitfury->device_id, amount);
return false;
}
applog(LOG_DEBUG, "%s %d: Getreset returned %s", bitfury->drv->name,
bitfury->device_id, buf);
bitfury_empty_buffer(bitfury);
return true;
}
static bool bitfury_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
{
struct cgpu_info *bitfury;
struct bitfury_info *info;
bitfury = usb_alloc_cgpu(&bitfury_drv, 1);
if (!usb_init(bitfury, dev, found))
goto out;
applog(LOG_INFO, "%s %d: Found at %s", bitfury->drv->name,
bitfury->device_id, bitfury->device_path);
info = calloc(sizeof(struct bitfury_info), 1);
if (!info)
quit(1, "Failed to calloc info in bitfury_detect_one");
bitfury->device_data = info;
usb_buffer_enable(bitfury);
bitfury_open(bitfury);
/* Send getinfo request */
if (!bitfury_getinfo(bitfury, info))
goto out_close;
/* Send reset request */
if (!bitfury_reset(bitfury))
goto out_close;
bitfury_identify(bitfury);
bitfury_empty_buffer(bitfury);
if (!add_cgpu(bitfury))
goto out_close;
update_usb_stats(bitfury);
applog(LOG_INFO, "%s %d: Found at %s",
bitfury->drv->name, bitfury->device_id, bitfury->device_path);
return true;
out_close:
bitfury_close(bitfury);
usb_uninit(bitfury);
out:
bitfury = usb_free_cgpu(bitfury);
return false;
}
static void bitfury_detect(bool __maybe_unused hotplug)
{
usb_detect(&bitfury_drv, bitfury_detect_one);
}
static uint32_t decnonce(uint32_t in)
{
uint32_t out;
/* First part load */
out = (in & 0xFF) << 24; in >>= 8;
/* Byte reversal */
in = (((in & 0xaaaaaaaa) >> 1) | ((in & 0x55555555) << 1));
in = (((in & 0xcccccccc) >> 2) | ((in & 0x33333333) << 2));
in = (((in & 0xf0f0f0f0) >> 4) | ((in & 0x0f0f0f0f) << 4));
out |= (in >> 2)&0x3FFFFF;
/* Extraction */
if (in & 1) out |= (1 << 23);
if (in & 2) out |= (1 << 22);
out -= 0x800004;
return out;
}
#define BT_OFFSETS 3
const uint32_t bf_offsets[] = {-0x800000, 0, -0x400000};
static bool bitfury_checkresults(struct thr_info *thr, struct work *work, uint32_t nonce)
{
int i;
for (i = 0; i < BT_OFFSETS; i++) {
if (test_nonce(work, nonce + bf_offsets[i])) {
submit_tested_work(thr, work);
return true;
}
}
return false;
}
static int64_t bitfury_scanhash(struct thr_info *thr, struct work *work,
int64_t __maybe_unused max_nonce)
{
struct cgpu_info *bitfury = thr->cgpu;
struct bitfury_info *info = bitfury->device_data;
struct timeval tv_now;
int amount, i;
char buf[45];
int ms_diff;
buf[0] = 'W';
memcpy(buf + 1, work->midstate, 32);
memcpy(buf + 33, work->data + 64, 12);
/* New results may spill out from the latest work, making us drop out
* too early so read whatever we get for the first half nonce and then
* look for the results to prev work. */
cgtime(&tv_now);
ms_diff = 600 - ms_tdiff(&tv_now, &info->tv_start);
if (ms_diff > 0) {
usb_read_timeout(bitfury, info->buf, 512, &amount, ms_diff, C_BF1_GETRES);
info->tot += amount;
}
if (unlikely(thr->work_restart))
goto cascade;
/* Now look for the bulk of the previous work results, they will come
* in a batch following the first data. */
cgtime(&tv_now);
ms_diff = BF1WAIT - ms_tdiff(&tv_now, &info->tv_start);
if (unlikely(ms_diff < 10))
ms_diff = 10;
usb_read_once_timeout(bitfury, info->buf + info->tot, 7, &amount, ms_diff, C_BF1_GETRES);
info->tot += amount;
while (amount) {
usb_read_once_timeout(bitfury, info->buf + info->tot, 512, &amount, 10, C_BF1_GETRES);
info->tot += amount;
};
if (unlikely(thr->work_restart))
goto cascade;
/* Send work */
usb_write(bitfury, buf, 45, &amount, C_BF1_REQWORK);
cgtime(&info->tv_start);
/* Get response acknowledging work */
usb_read(bitfury, buf, 7, &amount, C_BF1_GETWORK);
/* Only happens on startup */
if (unlikely(!info->prevwork[BF1ARRAY_SIZE]))
goto cascade;
/* Search for what work the nonce matches in order of likelihood. Last
* entry is end of result marker. */
for (i = 0; i < info->tot - 7; i += 7) {
uint32_t nonce;
int j;
/* Ignore state & switched data in results for now. */
memcpy(&nonce, info->buf + i + 3, 4);
nonce = decnonce(nonce);
for (j = 0; j < BF1ARRAY_SIZE; j++) {
if (bitfury_checkresults(thr, info->prevwork[j], nonce)) {
info->nonces++;
break;
}
}
}
info->tot = 0;
free_work(info->prevwork[BF1ARRAY_SIZE]);
cascade:
for (i = BF1ARRAY_SIZE; i > 0; i--)
info->prevwork[i] = info->prevwork[i - 1];
info->prevwork[0] = copy_work(work);
work->blk.nonce = 0xffffffff;
if (info->nonces) {
info->nonces--;
return (int64_t)0xffffffff;
}
return 0;
}
static struct api_data *bitfury_api_stats(struct cgpu_info *cgpu)
{
struct bitfury_info *info = cgpu->device_data;
struct api_data *root = NULL;
char serial[16];
int version;
version = info->version;
root = api_add_int(root, "Version", &version, true);
root = api_add_string(root, "Product", info->product, false);
sprintf(serial, "%08x", info->serial);
root = api_add_string(root, "Serial", serial, true);
return root;
}
static void bitfury_init(struct cgpu_info *bitfury)
{
bitfury_close(bitfury);
bitfury_open(bitfury);
bitfury_reset(bitfury);
}
static void bitfury_shutdown(struct thr_info *thr)
{
struct cgpu_info *bitfury = thr->cgpu;
bitfury_close(bitfury);
}
/* Currently hardcoded to BF1 devices */
struct device_drv bitfury_drv = {
.drv_id = DRIVER_bitfury,
.dname = "bitfury",
.name = "BF1",
.drv_detect = bitfury_detect,
.scanhash = bitfury_scanhash,
.get_api_stats = bitfury_api_stats,
.reinit_device = bitfury_init,
.thread_shutdown = bitfury_shutdown,
.identify_device = bitfury_identify
};

30
driver-bitfury.h

@ -0,0 +1,30 @@
/*
* Copyright 2013 Con Kolivas
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at your option)
* any later version. See COPYING for more details.
*/
#ifndef BITFURY_H
#define BITFURY_H
#include "miner.h"
#include "usbutils.h"
#define BF1ARRAY_SIZE 2
struct bitfury_info {
struct cgpu_info *base_cgpu;
uint8_t version;
char product[8];
uint32_t serial;
struct work *prevwork[BF1ARRAY_SIZE + 1];
char buf[512];
int tot;
int nonces;
struct timeval tv_start;
};
#endif /* BITFURY_H */

11
driver-hashfast.c

@ -285,7 +285,7 @@ static bool hashfast_detect_one_usb(libusb_device *dev, struct usb_find_devices
} }
hashfast->usbdev->usb_type = USB_TYPE_STD; hashfast->usbdev->usb_type = USB_TYPE_STD;
hashfast->usbdev->PrefPacketSize = HASHFAST_USB_PACKETSIZE; usb_set_pps(hashfast, HASHFAST_USB_PACKETSIZE);
hashfast_usb_initialise(hashfast); hashfast_usb_initialise(hashfast);
@ -293,8 +293,13 @@ static bool hashfast_detect_one_usb(libusb_device *dev, struct usb_find_devices
return hashfast_detect_common(hashfast, baud); return hashfast_detect_common(hashfast, baud);
} }
static void hashfast_detect(void) static void hashfast_detect(bool hotplug)
{ {
/* Set up the CRC tables only once. */
if (!hotplug) {
hf_init_crc8();
hf_init_crc32();
}
usb_detect(&hashfast_drv, hashfast_detect_one_usb); usb_detect(&hashfast_drv, hashfast_detect_one_usb);
} }
@ -328,7 +333,7 @@ static void hashfast_shutdown(struct thr_info __maybe_unused *thr)
} }
struct device_drv hashfast_drv = { struct device_drv hashfast_drv = {
.drv_id = DRIVER_HASHFAST, .drv_id = DRIVER_hashfast,
.dname = "Hashfast", .dname = "Hashfast",
.name = "HFA", .name = "HFA",
.drv_detect = hashfast_detect, .drv_detect = hashfast_detect,

103
driver-icarus.c

@ -74,6 +74,7 @@ ASSERT1(sizeof(uint32_t) == 4);
// USB ms timeout to wait - user specified timeouts are multiples of this // USB ms timeout to wait - user specified timeouts are multiples of this
#define ICARUS_WAIT_TIMEOUT 100 #define ICARUS_WAIT_TIMEOUT 100
#define ICARUS_CMR2_TIMEOUT 1
// Defined in multiples of ICARUS_WAIT_TIMEOUT // Defined in multiples of ICARUS_WAIT_TIMEOUT
// Must of course be greater than ICARUS_READ_COUNT_TIMING/ICARUS_WAIT_TIMEOUT // Must of course be greater than ICARUS_READ_COUNT_TIMING/ICARUS_WAIT_TIMEOUT
@ -177,6 +178,8 @@ static const char *MODE_VALUE_STR = "value";
static const char *MODE_UNKNOWN_STR = "unknown"; static const char *MODE_UNKNOWN_STR = "unknown";
struct ICARUS_INFO { struct ICARUS_INFO {
int intinfo;
// time to calculate the golden_ob // time to calculate the golden_ob
uint64_t golden_hashes; uint64_t golden_hashes;
struct timeval golden_tv; struct timeval golden_tv;
@ -184,6 +187,8 @@ struct ICARUS_INFO {
struct ICARUS_HISTORY history[INFO_HISTORY+1]; struct ICARUS_HISTORY history[INFO_HISTORY+1];
uint32_t min_data_count; uint32_t min_data_count;
int timeout;
// seconds per Hash // seconds per Hash
double Hs; double Hs;
// ms til we abort // ms til we abort
@ -233,8 +238,6 @@ struct ICARUS_INFO {
// //
static int option_offset = -1; static int option_offset = -1;
struct device_drv icarus_drv;
/* /*
#define ICA_BUFSIZ (0x200) #define ICA_BUFSIZ (0x200)
@ -277,7 +280,7 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
usb_set_cps(icarus, baud / 10); usb_set_cps(icarus, baud / 10);
usb_enable_cps(icarus); usb_enable_cps(icarus);
interface = usb_interface(icarus); interface = _usb_interface(icarus, info->intinfo);
ident = usb_ident(icarus); ident = usb_ident(icarus);
switch (ident) { switch (ident) {
@ -287,9 +290,6 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
case IDENT_CMR2: case IDENT_CMR2:
usb_set_pps(icarus, BLT_PREF_PACKET); usb_set_pps(icarus, BLT_PREF_PACKET);
if (ident == IDENT_CMR2) // Chip hack
interface++;
// Reset // Reset
transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET, transfer(icarus, FTDI_TYPE_OUT, FTDI_REQUEST_RESET, FTDI_VALUE_RESET,
interface, C_RESET); interface, C_RESET);
@ -298,7 +298,7 @@ static void icarus_initialise(struct cgpu_info *icarus, int baud)
return; return;
// Latency // Latency
usb_ftdi_set_latency(icarus); _usb_ftdi_set_latency(icarus, info->intinfo);
if (icarus->usbinfo.nodev) if (icarus->usbinfo.nodev)
return; return;
@ -434,9 +434,10 @@ static void rev(unsigned char *s, size_t l)
static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct timeval *tv_start, struct timeval *tv_finish, struct thr_info *thr, int read_time) static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct timeval *tv_start, struct timeval *tv_finish, struct thr_info *thr, int read_time)
{ {
struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data);
struct timeval read_start, read_finish; struct timeval read_start, read_finish;
int err, amt; int err, amt;
int rc = 0; int rc = 0, delay;
int read_amount = ICARUS_READ_SIZE; int read_amount = ICARUS_READ_SIZE;
bool first = true; bool first = true;
@ -446,7 +447,9 @@ static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct
return ICA_NONCE_ERROR; return ICA_NONCE_ERROR;
cgtime(&read_start); cgtime(&read_start);
err = usb_read_timeout(icarus, (char *)buf, read_amount, &amt, ICARUS_WAIT_TIMEOUT, C_GETRESULTS); err = usb_read_ii_timeout(icarus, info->intinfo,
(char *)buf, read_amount, &amt,
info->timeout, C_GETRESULTS);
cgtime(&read_finish); cgtime(&read_finish);
if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) { if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
applog(LOG_ERR, "%s%i: Comms error (rerr=%d amt=%d)", applog(LOG_ERR, "%s%i: Comms error (rerr=%d amt=%d)",
@ -471,10 +474,7 @@ static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct
} }
if (thr && thr->work_restart) { if (thr && thr->work_restart) {
if (opt_debug) { applog(LOG_DEBUG, "Icarus Read: Work restart at %d ms", rc);
applog(LOG_DEBUG,
"Icarus Read: Work restart at %d ms", rc);
}
return ICA_NONCE_RESTART; return ICA_NONCE_RESTART;
} }
@ -483,6 +483,18 @@ static int icarus_get_nonce(struct cgpu_info *icarus, unsigned char *buf, struct
read_amount -= amt; read_amount -= amt;
first = false; first = false;
} }
if (info->timeout < ICARUS_WAIT_TIMEOUT) {
delay = ICARUS_WAIT_TIMEOUT - rc;
if (delay > 0) {
cgsleep_ms(delay);
if (thr && thr->work_restart) {
applog(LOG_DEBUG, "Icarus Read: Work restart at %d ms", rc);
return ICA_NONCE_RESTART;
}
}
}
} }
} }
@ -796,6 +808,7 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
int baud, uninitialised_var(work_division), uninitialised_var(fpga_count); int baud, uninitialised_var(work_division), uninitialised_var(fpga_count);
struct cgpu_info *icarus; struct cgpu_info *icarus;
int ret, err, amount, tries; int ret, err, amount, tries;
enum sub_ident ident;
bool ok; bool ok;
icarus = usb_alloc_cgpu(&icarus_drv, 1); icarus = usb_alloc_cgpu(&icarus_drv, 1);
@ -814,6 +827,23 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
quit(1, "Failed to malloc ICARUS_INFO"); quit(1, "Failed to malloc ICARUS_INFO");
icarus->device_data = (void *)info; icarus->device_data = (void *)info;
ident = usb_ident(icarus);
switch (ident) {
case IDENT_ICA:
case IDENT_BLT:
case IDENT_LLT:
case IDENT_AMU:
case IDENT_CMR1:
info->timeout = ICARUS_WAIT_TIMEOUT;
break;
case IDENT_CMR2:
info->timeout = ICARUS_CMR2_TIMEOUT;
break;
default:
quit(1, "%s icarus_detect_one() invalid %s ident=%d",
icarus->drv->dname, icarus->drv->dname, ident);
}
tries = 2; tries = 2;
ok = false; ok = false;
while (!ok && tries-- > 0) { while (!ok && tries-- > 0) {
@ -879,7 +909,7 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
struct cgpu_info *cgtmp; struct cgpu_info *cgtmp;
struct ICARUS_INFO *intmp; struct ICARUS_INFO *intmp;
cgtmp = usb_init_intinfo(icarus, i); cgtmp = usb_copy_cgpu(icarus);
if (!cgtmp) { if (!cgtmp) {
applog(LOG_ERR, "%s%d: Init failed initinfo %d", applog(LOG_ERR, "%s%d: Init failed initinfo %d",
icarus->drv->name, icarus->device_id, i); icarus->drv->name, icarus->device_id, i);
@ -888,13 +918,6 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
cgtmp->usbinfo.usbstat = USB_NOSTAT; cgtmp->usbinfo.usbstat = USB_NOSTAT;
if (!add_cgpu(cgtmp)) {
usb_uninit(cgtmp);
continue;
}
update_usb_stats(cgtmp);
intmp = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO)); intmp = (struct ICARUS_INFO *)malloc(sizeof(struct ICARUS_INFO));
if (unlikely(!intmp)) if (unlikely(!intmp))
quit(1, "Failed2 to malloc ICARUS_INFO"); quit(1, "Failed2 to malloc ICARUS_INFO");
@ -903,6 +926,18 @@ static bool icarus_detect_one(struct libusb_device *dev, struct usb_find_devices
// Initialise everything to match // Initialise everything to match
memcpy(intmp, info, sizeof(struct ICARUS_INFO)); memcpy(intmp, info, sizeof(struct ICARUS_INFO));
intmp->intinfo = i;
icarus_initialise(cgtmp, baud);
if (!add_cgpu(cgtmp)) {
usb_uninit(cgtmp);
free(intmp);
continue;
}
update_usb_stats(cgtmp);
} }
} }
@ -921,7 +956,7 @@ shin:
return false; return false;
} }
static void icarus_detect() static void icarus_detect(bool __maybe_unused hotplug)
{ {
usb_detect(&icarus_drv, icarus_detect_one); usb_detect(&icarus_drv, icarus_detect_one);
} }
@ -976,7 +1011,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
// We only want results for the work we are about to send // We only want results for the work we are about to send
usb_buffer_clear(icarus); usb_buffer_clear(icarus);
err = usb_write(icarus, (char *)ob_bin, sizeof(ob_bin), &amount, C_SENDWORK); err = usb_write_ii(icarus, info->intinfo, (char *)ob_bin, sizeof(ob_bin), &amount, C_SENDWORK);
if (err < 0 || amount != sizeof(ob_bin)) { if (err < 0 || amount != sizeof(ob_bin)) {
applog(LOG_ERR, "%s%i: Comms error (werr=%d amt=%d)", applog(LOG_ERR, "%s%i: Comms error (werr=%d amt=%d)",
icarus->drv->name, icarus->device_id, err, amount); icarus->drv->name, icarus->device_id, err, amount);
@ -1014,12 +1049,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
if (unlikely(estimate_hashes > 0xffffffff)) if (unlikely(estimate_hashes > 0xffffffff))
estimate_hashes = 0xffffffff; estimate_hashes = 0xffffffff;
if (opt_debug) { applog(LOG_DEBUG, "%s%d: no nonce = 0x%08lX hashes (%ld.%06lds)",
applog(LOG_DEBUG, "%s%d: no nonce = 0x%08lX hashes (%ld.%06lds)", icarus->drv->name, icarus->device_id,
icarus->drv->name, icarus->device_id, (long unsigned int)estimate_hashes,
(long unsigned int)estimate_hashes, elapsed.tv_sec, elapsed.tv_usec);
elapsed.tv_sec, elapsed.tv_usec);
}
return estimate_hashes; return estimate_hashes;
} }
@ -1051,12 +1084,10 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
if (opt_debug || info->do_icarus_timing) if (opt_debug || info->do_icarus_timing)
timersub(&tv_finish, &tv_start, &elapsed); timersub(&tv_finish, &tv_start, &elapsed);
if (opt_debug) { applog(LOG_DEBUG, "%s%d: nonce = 0x%08x = 0x%08lX hashes (%ld.%06lds)",
applog(LOG_DEBUG, "%s%d: nonce = 0x%08x = 0x%08lX hashes (%ld.%06lds)", icarus->drv->name, icarus->device_id,
icarus->drv->name, icarus->device_id, nonce, (long unsigned int)hash_count,
nonce, (long unsigned int)hash_count, elapsed.tv_sec, elapsed.tv_usec);
elapsed.tv_sec, elapsed.tv_usec);
}
// Ignore possible end condition values ... and hw errors // Ignore possible end condition values ... and hw errors
// TODO: set limitations on calculated values depending on the device // TODO: set limitations on calculated values depending on the device
@ -1203,7 +1234,7 @@ static void icarus_shutdown(__maybe_unused struct thr_info *thr)
} }
struct device_drv icarus_drv = { struct device_drv icarus_drv = {
.drv_id = DRIVER_ICARUS, .drv_id = DRIVER_icarus,
.dname = "Icarus", .dname = "Icarus",
.name = "ICA", .name = "ICA",
.drv_detect = icarus_detect, .drv_detect = icarus_detect,

6
driver-modminer.c

@ -87,8 +87,6 @@
// Limit when reducing shares_to_good // Limit when reducing shares_to_good
#define MODMINER_MIN_BACK 12 #define MODMINER_MIN_BACK 12
struct device_drv modminer_drv;
// 45 noops sent when detecting, in case the device was left in "start job" reading // 45 noops sent when detecting, in case the device was left in "start job" reading
static const char NOOP[] = MODMINER_PING "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; static const char NOOP[] = MODMINER_PING "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
@ -239,7 +237,7 @@ shin:
return false; return false;
} }
static void modminer_detect() static void modminer_detect(bool __maybe_unused hotplug)
{ {
usb_detect(&modminer_drv, modminer_detect_one); usb_detect(&modminer_drv, modminer_detect_one);
} }
@ -1132,7 +1130,7 @@ static char *modminer_set_device(struct cgpu_info *modminer, char *option, char
} }
struct device_drv modminer_drv = { struct device_drv modminer_drv = {
.drv_id = DRIVER_MODMINER, .drv_id = DRIVER_modminer,
.dname = "ModMiner", .dname = "ModMiner",
.name = "MMQ", .name = "MMQ",
.drv_detect = modminer_detect, .drv_detect = modminer_detect,

20
driver-opencl.c

@ -56,10 +56,6 @@ extern void decay_time(double *f, double fadd);
/**********************************************/ /**********************************************/
#ifdef HAVE_OPENCL
struct device_drv opencl_drv;
#endif
#ifdef HAVE_ADL #ifdef HAVE_ADL
extern float gpu_temp(int gpu); extern float gpu_temp(int gpu);
extern int gpu_fanspeed(int gpu); extern int gpu_fanspeed(int gpu);
@ -585,7 +581,7 @@ char *set_intensity(char *arg)
void print_ndevs(int *ndevs) void print_ndevs(int *ndevs)
{ {
opt_log_output = true; opt_log_output = true;
opencl_drv.drv_detect(); opencl_drv.drv_detect(false);
clear_adl(*ndevs); clear_adl(*ndevs);
applog(LOG_INFO, "%i GPU devices max detected", *ndevs); applog(LOG_INFO, "%i GPU devices max detected", *ndevs);
} }
@ -753,7 +749,7 @@ retry:
for (i = 0; i < mining_threads; ++i) { for (i = 0; i < mining_threads; ++i) {
thr = get_thread(i); thr = get_thread(i);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->drv->drv_id != DRIVER_OPENCL) if (cgpu->drv->drv_id != DRIVER_opencl)
continue; continue;
if (dev_from_id(i) != selected) if (dev_from_id(i) != selected)
continue; continue;
@ -1148,7 +1144,7 @@ select_cgpu:
for (thr_id = 0; thr_id < mining_threads; ++thr_id) { for (thr_id = 0; thr_id < mining_threads; ++thr_id) {
thr = get_thread(thr_id); thr = get_thread(thr_id);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->drv->drv_id != DRIVER_OPENCL) if (cgpu->drv->drv_id != DRIVER_opencl)
continue; continue;
if (dev_from_id(thr_id) != gpu) if (dev_from_id(thr_id) != gpu)
continue; continue;
@ -1173,7 +1169,7 @@ select_cgpu:
thr = get_thread(thr_id); thr = get_thread(thr_id);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->drv->drv_id != DRIVER_OPENCL) if (cgpu->drv->drv_id != DRIVER_opencl)
continue; continue;
if (dev_from_id(thr_id) != gpu) if (dev_from_id(thr_id) != gpu)
continue; continue;
@ -1210,7 +1206,7 @@ select_cgpu:
for (thr_id = 0; thr_id < mining_threads; ++thr_id) { for (thr_id = 0; thr_id < mining_threads; ++thr_id) {
thr = get_thread(thr_id); thr = get_thread(thr_id);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->drv->drv_id != DRIVER_OPENCL) if (cgpu->drv->drv_id != DRIVER_opencl)
continue; continue;
if (dev_from_id(thr_id) != gpu) if (dev_from_id(thr_id) != gpu)
continue; continue;
@ -1231,10 +1227,12 @@ void *reinit_gpu(__maybe_unused void *userdata)
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
static void opencl_detect() static void opencl_detect(bool hotplug)
{ {
int i; int i;
if (opt_nogpu || hotplug)
return;
nDevs = clDevicesNum(); nDevs = clDevicesNum();
if (nDevs < 0) { if (nDevs < 0) {
applog(LOG_ERR, "clDevicesNum returned error, no GPUs usable"); applog(LOG_ERR, "clDevicesNum returned error, no GPUs usable");
@ -1575,7 +1573,7 @@ static void opencl_thread_shutdown(struct thr_info *thr)
} }
struct device_drv opencl_drv = { struct device_drv opencl_drv = {
.drv_id = DRIVER_OPENCL, .drv_id = DRIVER_opencl,
.dname = "opencl", .dname = "opencl",
.name = "GPU", .name = "GPU",
.drv_detect = opencl_detect, .drv_detect = opencl_detect,

6
driver-ztex.c

@ -31,8 +31,6 @@
#define GOLDEN_BACKLOG 5 #define GOLDEN_BACKLOG 5
struct device_drv ztex_drv;
// Forward declarations // Forward declarations
static void ztex_disable(struct thr_info* thr); static void ztex_disable(struct thr_info* thr);
static bool ztex_prepare(struct thr_info *thr); static bool ztex_prepare(struct thr_info *thr);
@ -54,7 +52,7 @@ static void ztex_releaseFpga(struct libztex_device* ztex)
} }
} }
static void ztex_detect(void) static void ztex_detect(bool __maybe_unused hotplug)
{ {
int cnt; int cnt;
int i,j; int i,j;
@ -413,7 +411,7 @@ static void ztex_disable(struct thr_info *thr)
} }
struct device_drv ztex_drv = { struct device_drv ztex_drv = {
.drv_id = DRIVER_ZTEX, .drv_id = DRIVER_ztex,
.dname = "ztex", .dname = "ztex",
.name = "ZTX", .name = "ZTX",
.drv_detect = ztex_detect, .drv_detect = ztex_detect,

56
miner.h

@ -230,18 +230,39 @@ static inline int fsync (int fd)
#define MIN(x, y) ((x) > (y) ? (y) : (x)) #define MIN(x, y) ((x) > (y) ? (y) : (x))
#define MAX(x, y) ((x) > (y) ? (x) : (y)) #define MAX(x, y) ((x) > (y) ? (x) : (y))
/* Put avalon last to make it the last device it tries to detect to prevent it
* trying to claim same chip but different devices. Adding a device here will
* update all macros in the code that use the *_PARSE_COMMANDS macros for each
* listed driver. */
#define FPGA_PARSE_COMMANDS(DRIVER_ADD_COMMAND) \
DRIVER_ADD_COMMAND(bitforce) \
DRIVER_ADD_COMMAND(icarus) \
DRIVER_ADD_COMMAND(modminer) \
DRIVER_ADD_COMMAND(ztex)
#define ASIC_PARSE_COMMANDS(DRIVER_ADD_COMMAND) \
DRIVER_ADD_COMMAND(bflsc) \
DRIVER_ADD_COMMAND(bitfury) \
DRIVER_ADD_COMMAND(hashfast) \
DRIVER_ADD_COMMAND(avalon)
#define DRIVER_PARSE_COMMANDS(DRIVER_ADD_COMMAND) \
DRIVER_ADD_COMMAND(opencl) \
FPGA_PARSE_COMMANDS(DRIVER_ADD_COMMAND) \
ASIC_PARSE_COMMANDS(DRIVER_ADD_COMMAND)
#define DRIVER_ENUM(X) DRIVER_##X,
#define DRIVER_PROTOTYPE(X) struct device_drv X##_drv;
/* Create drv_driver enum from DRIVER_PARSE_COMMANDS macro */
enum drv_driver { enum drv_driver {
DRIVER_OPENCL = 0, DRIVER_PARSE_COMMANDS(DRIVER_ENUM)
DRIVER_ICARUS,
DRIVER_BITFORCE,
DRIVER_MODMINER,
DRIVER_ZTEX,
DRIVER_BFLSC,
DRIVER_AVALON,
DRIVER_HASHFAST,
DRIVER_MAX DRIVER_MAX
}; };
/* Use DRIVER_PARSE_COMMANDS to generate extern device_drv prototypes */
DRIVER_PARSE_COMMANDS(DRIVER_PROTOTYPE)
enum alive { enum alive {
LIFE_WELL, LIFE_WELL,
LIFE_SICK, LIFE_SICK,
@ -318,7 +339,7 @@ struct device_drv {
char *name; char *name;
// DRV-global functions // DRV-global functions
void (*drv_detect)(); void (*drv_detect)(bool);
// Device-specific functions // Device-specific functions
void (*reinit_device)(struct cgpu_info *); void (*reinit_device)(struct cgpu_info *);
@ -823,7 +844,7 @@ static inline void cglock_init(cglock_t *lock)
rwlock_init(&lock->rwlock); rwlock_init(&lock->rwlock);
} }
/* Read lock variant of cglock */ /* Read lock variant of cglock. Cannot be promoted. */
static inline void cg_rlock(cglock_t *lock) static inline void cg_rlock(cglock_t *lock)
{ {
mutex_lock(&lock->mutex); mutex_lock(&lock->mutex);
@ -831,7 +852,8 @@ static inline void cg_rlock(cglock_t *lock)
mutex_unlock_noyield(&lock->mutex); mutex_unlock_noyield(&lock->mutex);
} }
/* Intermediate variant of cglock */ /* Intermediate variant of cglock - behaves as a read lock but can be promoted
* to a write lock or demoted to read lock. */
static inline void cg_ilock(cglock_t *lock) static inline void cg_ilock(cglock_t *lock)
{ {
mutex_lock(&lock->mutex); mutex_lock(&lock->mutex);
@ -858,6 +880,12 @@ static inline void cg_dwlock(cglock_t *lock)
mutex_unlock_noyield(&lock->mutex); mutex_unlock_noyield(&lock->mutex);
} }
/* Demote a write variant to an intermediate variant */
static inline void cg_dwilock(cglock_t *lock)
{
wr_unlock(&lock->rwlock);
}
/* Downgrade intermediate variant to a read lock */ /* Downgrade intermediate variant to a read lock */
static inline void cg_dlock(cglock_t *lock) static inline void cg_dlock(cglock_t *lock)
{ {
@ -872,7 +900,7 @@ static inline void cg_runlock(cglock_t *lock)
static inline void cg_wunlock(cglock_t *lock) static inline void cg_wunlock(cglock_t *lock)
{ {
wr_unlock(&lock->rwlock); wr_unlock_noyield(&lock->rwlock);
mutex_unlock(&lock->mutex); mutex_unlock(&lock->mutex);
} }
@ -903,6 +931,7 @@ extern bool opt_api_listen;
extern bool opt_api_network; extern bool opt_api_network;
extern bool opt_delaynet; extern bool opt_delaynet;
extern bool opt_restart; extern bool opt_restart;
extern bool opt_nogpu;
extern char *opt_icarus_options; extern char *opt_icarus_options;
extern char *opt_icarus_timing; extern char *opt_icarus_timing;
extern bool opt_worktime; extern bool opt_worktime;
@ -1263,6 +1292,7 @@ struct work {
#endif #endif
double device_diff; double device_diff;
uint64_t share_diff; uint64_t share_diff;
unsigned char hash2[32];
int rolls; int rolls;
@ -1356,6 +1386,8 @@ struct modminer_fpga_state {
extern void get_datestamp(char *, size_t, struct timeval *); extern void get_datestamp(char *, size_t, struct timeval *);
extern void inc_hw_errors(struct thr_info *thr); extern void inc_hw_errors(struct thr_info *thr);
extern bool test_nonce(struct work *work, uint32_t nonce);
extern void submit_tested_work(struct thr_info *thr, struct work *work);
extern bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce); extern bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
extern struct work *get_queued(struct cgpu_info *cgpu); extern struct work *get_queued(struct cgpu_info *cgpu);
extern struct work *__find_work_bymidstate(struct work *que, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen); extern struct work *__find_work_bymidstate(struct work *que, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen);

681
usbutils.c

File diff suppressed because it is too large Load Diff

92
usbutils.h

@ -109,6 +109,9 @@
// Use the device defined timeout // Use the device defined timeout
#define DEVTIMEOUT 0 #define DEVTIMEOUT 0
// The default intinfo structure used is the first one
#define DEFAULT_INTINFO 0
// For endpoints defined in usb_find_devices.intinfos.epinfos, // For endpoints defined in usb_find_devices.intinfos.epinfos,
// the first two must be the default IN and OUT and both must always exist // the first two must be the default IN and OUT and both must always exist
#define DEFAULT_EP_IN 0 #define DEFAULT_EP_IN 0
@ -118,11 +121,14 @@ struct usb_epinfo {
uint8_t att; uint8_t att;
uint16_t size; uint16_t size;
unsigned char ep; unsigned char ep;
uint16_t wMaxPacketSize;
uint16_t PrefPacketSize;
bool found; bool found;
}; };
struct usb_intinfo { struct usb_intinfo {
int interface; int interface;
int ctrl_transfer;
int epinfo_count; int epinfo_count;
struct usb_epinfo *epinfos; struct usb_epinfo *epinfos;
}; };
@ -134,6 +140,7 @@ enum sub_ident {
IDENT_BAS, IDENT_BAS,
IDENT_BAM, IDENT_BAM,
IDENT_BFL, IDENT_BFL,
IDENT_BFU,
IDENT_MMQ, IDENT_MMQ,
IDENT_AVA, IDENT_AVA,
IDENT_BTB, IDENT_BTB,
@ -157,9 +164,7 @@ struct usb_find_devices {
char *iProduct; char *iProduct;
int config; int config;
unsigned int timeout; unsigned int timeout;
uint16_t wMaxPacketSize;
uint16_t latency; uint16_t latency;
int which_intinfo;
int intinfo_count; int intinfo_count;
struct usb_intinfo *intinfos; struct usb_intinfo *intinfos;
}; };
@ -193,7 +198,6 @@ struct cg_usb_device {
char *buffer; char *buffer;
uint32_t bufsiz; uint32_t bufsiz;
uint32_t bufamt; uint32_t bufamt;
uint16_t PrefPacketSize;
cgtimer_t cgt_last_write; cgtimer_t cgt_last_write;
size_t last_write_siz; size_t last_write_siz;
}; };
@ -234,7 +238,7 @@ struct cg_usb_info {
* that uses the lock - however, all usbutils code MUST use it * that uses the lock - however, all usbutils code MUST use it
* to avoid devices disappearing while in use by multiple threads * to avoid devices disappearing while in use by multiple threads
*/ */
pthread_rwlock_t *devlock; pthread_mutex_t *devlock;
time_t last_pipe; time_t last_pipe;
uint64_t pipe_count; uint64_t pipe_count;
@ -258,7 +262,10 @@ struct cg_usb_info {
struct cg_usb_tmo usb_tmo[USB_TMOS]; struct cg_usb_tmo usb_tmo[USB_TMOS];
}; };
#define USB_PARSE_COMMANDS \ #define ENUMERATION(a,b) a,
#define JUMPTABLE(a,b) b,
#define USB_PARSE_COMMANDS(USB_ADD_COMMAND) \
USB_ADD_COMMAND(C_REJECTED, "RejectedNoDevice") \ USB_ADD_COMMAND(C_REJECTED, "RejectedNoDevice") \
USB_ADD_COMMAND(C_PING, "Ping") \ USB_ADD_COMMAND(C_PING, "Ping") \
USB_ADD_COMMAND(C_CLEAR, "Clear") \ USB_ADD_COMMAND(C_CLEAR, "Clear") \
@ -322,6 +329,20 @@ struct cg_usb_info {
USB_ADD_COMMAND(C_ENABLE_UART, "EnableUART") \ USB_ADD_COMMAND(C_ENABLE_UART, "EnableUART") \
USB_ADD_COMMAND(C_BB_SET_VOLTAGE, "SetCoreVoltage") \ USB_ADD_COMMAND(C_BB_SET_VOLTAGE, "SetCoreVoltage") \
USB_ADD_COMMAND(C_BB_GET_VOLTAGE, "GetCoreVoltage") \ USB_ADD_COMMAND(C_BB_GET_VOLTAGE, "GetCoreVoltage") \
USB_ADD_COMMAND(C_BF1_RESET, "BF1Reset") \
USB_ADD_COMMAND(C_BF1_OPEN, "BF1Open") \
USB_ADD_COMMAND(C_BF1_INIT, "BF1Init") \
USB_ADD_COMMAND(C_BF1_CLOSE, "BF1Close") \
USB_ADD_COMMAND(C_BF1_REQINFO, "BF1RequestInfo") \
USB_ADD_COMMAND(C_BF1_GETINFO, "BF1GetInfo") \
USB_ADD_COMMAND(C_BF1_REQRESET, "BF1RequestReset") \
USB_ADD_COMMAND(C_BF1_GETRESET, "BF1GetReset") \
USB_ADD_COMMAND(C_BF1_REQWORK, "BF1RequestWork") \
USB_ADD_COMMAND(C_BF1_GETWORK, "BF1GetWork") \
USB_ADD_COMMAND(C_BF1_GETRES, "BF1GetResults") \
USB_ADD_COMMAND(C_BF1_FLUSH, "BF1Flush") \
USB_ADD_COMMAND(C_BF1_IFLUSH, "BF1InterruptFlush") \
USB_ADD_COMMAND(C_BF1_IDENTIFY, "BF1Identify") \
USB_ADD_COMMAND(C_HF_RESET, "HFReset") \ USB_ADD_COMMAND(C_HF_RESET, "HFReset") \
USB_ADD_COMMAND(C_HF_PLL_CONFIG, "HFPLLConfig") \ USB_ADD_COMMAND(C_HF_PLL_CONFIG, "HFPLLConfig") \
USB_ADD_COMMAND(C_HF_ADDRESS, "HFAddress") \ USB_ADD_COMMAND(C_HF_ADDRESS, "HFAddress") \
@ -335,12 +356,10 @@ struct cg_usb_info {
USB_ADD_COMMAND(C_HF_CLOCKGATE, "HFClockGate") USB_ADD_COMMAND(C_HF_CLOCKGATE, "HFClockGate")
/* Create usb_cmds enum from USB_PARSE_COMMANDS macro */ /* Create usb_cmds enum from USB_PARSE_COMMANDS macro */
#define USB_ADD_COMMAND(X, Y) X,
enum usb_cmds { enum usb_cmds {
USB_PARSE_COMMANDS USB_PARSE_COMMANDS(ENUMERATION)
C_MAX C_MAX
}; };
#undef USB_ADD_COMMAND
struct device_drv; struct device_drv;
struct cgpu_info; struct cgpu_info;
@ -353,17 +372,17 @@ struct cgpu_info *usb_alloc_cgpu(struct device_drv *drv, int threads);
struct cgpu_info *usb_free_cgpu_devlock(struct cgpu_info *cgpu, bool free_devlock); struct cgpu_info *usb_free_cgpu_devlock(struct cgpu_info *cgpu, bool free_devlock);
#define usb_free_cgpu(cgpu) usb_free_cgpu_devlock(cgpu, true) #define usb_free_cgpu(cgpu) usb_free_cgpu_devlock(cgpu, true)
void usb_uninit(struct cgpu_info *cgpu); void usb_uninit(struct cgpu_info *cgpu);
struct cgpu_info *usb_init_intinfo(struct cgpu_info *orig, int intinfo);
bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found); bool usb_init(struct cgpu_info *cgpu, struct libusb_device *dev, struct usb_find_devices *found);
void usb_detect(struct device_drv *drv, bool (*device_detect)(struct libusb_device *, struct usb_find_devices *)); void usb_detect(struct device_drv *drv, 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, const char *end, enum usb_cmds cmd, bool readonce); int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t bufsiz, int *processed, unsigned int timeout, const char *end, enum usb_cmds cmd, bool readonce);
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 intinfo, int epinfo, 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, uint32_t *data, int siz, unsigned int timeout, enum usb_cmds cmd); int _usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, uint32_t *data, int siz, unsigned int timeout, enum usb_cmds cmd);
int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, char *buf, int bufsiz, int *amount, unsigned int timeout, enum usb_cmds cmd); int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRequest, uint16_t wValue, uint16_t wIndex, char *buf, int bufsiz, int *amount, unsigned int timeout, enum usb_cmds cmd);
int usb_ftdi_cts(struct cgpu_info *cgpu); int usb_ftdi_cts(struct cgpu_info *cgpu);
int usb_ftdi_set_latency(struct cgpu_info *cgpu); int _usb_ftdi_set_latency(struct cgpu_info *cgpu, int intinfo);
#define usb_ftdi_set_latency(_cgpu) _usb_ftdi_set_latency(_cgpu, DEFAULT_INTINFO)
void usb_buffer_enable(struct cgpu_info *cgpu); void usb_buffer_enable(struct cgpu_info *cgpu);
void usb_buffer_disable(struct cgpu_info *cgpu); void usb_buffer_disable(struct cgpu_info *cgpu);
void usb_buffer_clear(struct cgpu_info *cgpu); void usb_buffer_clear(struct cgpu_info *cgpu);
@ -371,55 +390,72 @@ uint32_t usb_buffer_size(struct cgpu_info *cgpu);
void usb_set_cps(struct cgpu_info *cgpu, int cps); void usb_set_cps(struct cgpu_info *cgpu, int cps);
void usb_enable_cps(struct cgpu_info *cgpu); void usb_enable_cps(struct cgpu_info *cgpu);
void usb_disable_cps(struct cgpu_info *cgpu); void usb_disable_cps(struct cgpu_info *cgpu);
int usb_interface(struct cgpu_info *cgpu); int _usb_interface(struct cgpu_info *cgpu, int intinfo);
#define usb_interface(_cgpu) _usb_interface(_cgpu, DEFAULT_INTINFO)
enum sub_ident usb_ident(struct cgpu_info *cgpu); enum sub_ident usb_ident(struct cgpu_info *cgpu);
void usb_set_pps(struct cgpu_info *cgpu, uint16_t PrefPacketSize); void _usb_set_pps(struct cgpu_info *cgpu, int intinfo, int epinfo, uint16_t PrefPacketSize);
#define usb_set_pps(_cgpu, _pps) _usb_set_pps(_cgpu, -1, -1, _pps)
void usb_set_dev_start(struct cgpu_info *cgpu); void usb_set_dev_start(struct cgpu_info *cgpu);
void usb_cleanup(); void usb_cleanup();
void usb_initialise(); void usb_initialise();
void *usb_resource_thread(void *userdata); void *usb_resource_thread(void *userdata);
#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, NULL, cmd, false) _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)
#define usb_read_ii(cgpu, intinfo, buf, bufsiz, read, cmd) \
_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, false)
#define usb_read_once(cgpu, buf, bufsiz, read, cmd) \ #define usb_read_once(cgpu, buf, bufsiz, read, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true) _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true)
#define usb_read_ii_once(cgpu, intinfo, buf, bufsiz, read, cmd) \
_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, NULL, cmd, true)
#define usb_read_once_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \ #define usb_read_once_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true) _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true)
#define usb_read_ii_once_timeout(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \
_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, true)
#define usb_read_nl(cgpu, buf, bufsiz, read, cmd) \ #define usb_read_nl(cgpu, buf, bufsiz, read, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "\n", cmd, false) _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "\n", cmd, false)
#define usb_read_nl_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \ #define usb_read_nl_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "\n", cmd, false) _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "\n", cmd, false)
#define usb_read_ok(cgpu, buf, bufsiz, read, cmd) \ #define usb_read_ok(cgpu, buf, bufsiz, read, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "OK\n", cmd, false) _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, DEVTIMEOUT, "OK\n", cmd, false)
#define usb_read_ok_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \ #define usb_read_ok_timeout(cgpu, buf, bufsiz, read, timeout, cmd) \
_usb_read(cgpu, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "OK\n", cmd, false) _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, "OK\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, NULL, cmd, false) _usb_read(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, read, DEVTIMEOUT, NULL, 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, NULL, cmd, false) _usb_read(cgpu, DEFAULT_INTINFO, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, cmd, false)
#define usb_read_ii_timeout(cgpu, intinfo, buf, bufsiz, read, timeout, cmd) \
_usb_read(cgpu, intinfo, DEFAULT_EP_IN, buf, bufsiz, read, timeout, NULL, 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, NULL, cmd, false) _usb_read(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, read, timeout, NULL, 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_INTINFO, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
#define usb_write_ii(cgpu, intinfo, buf, bufsiz, wrote, cmd) \
_usb_write(cgpu, intinfo, DEFAULT_EP_OUT, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
#define usb_write_ep(cgpu, ep, buf, bufsiz, wrote, cmd) \ #define usb_write_ep(cgpu, ep, buf, bufsiz, wrote, cmd) \
_usb_write(cgpu, ep, buf, bufsiz, wrote, DEVTIMEOUT, cmd) _usb_write(cgpu, DEFAULT_INTINFO, ep, buf, bufsiz, wrote, DEVTIMEOUT, cmd)
#define usb_write_timeout(cgpu, buf, bufsiz, wrote, timeout, cmd) \ #define usb_write_timeout(cgpu, buf, bufsiz, wrote, timeout, cmd) \
_usb_write(cgpu, DEFAULT_EP_OUT, buf, bufsiz, wrote, timeout, cmd) _usb_write(cgpu, DEFAULT_INTINFO, DEFAULT_EP_OUT, buf, bufsiz, wrote, timeout, cmd)
#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, DEFAULT_INTINFO, ep, buf, bufsiz, wrote, timeout, cmd)
#define usb_transfer(cgpu, typ, req, val, idx, cmd) \ #define usb_transfer(cgpu, typ, req, val, idx, cmd) \
_usb_transfer(cgpu, typ, req, val, idx, NULL, 0, DEVTIMEOUT, cmd) _usb_transfer(cgpu, typ, req, val, idx, NULL, 0, DEVTIMEOUT, cmd)

6
util.c

@ -1074,6 +1074,12 @@ double us_tdiff(struct timeval *end, struct timeval *start)
return end->tv_sec * 1000000 + end->tv_usec - start->tv_sec * 1000000 - start->tv_usec; return end->tv_sec * 1000000 + end->tv_usec - start->tv_sec * 1000000 - start->tv_usec;
} }
/* Returns the milliseconds difference between end and start times */
int ms_tdiff(struct timeval *end, struct timeval *start)
{
return end->tv_sec * 1000 + end->tv_usec / 1000 - start->tv_sec * 1000 - start->tv_usec / 1000;
}
/* Returns the seconds difference between end and start times as a double */ /* Returns the seconds difference between end and start times as a double */
double tdiff(struct timeval *end, struct timeval *start) double tdiff(struct timeval *end, struct timeval *start)
{ {

1
util.h

@ -99,6 +99,7 @@ void cgsleep_us_r(cgtimer_t *ts_start, int64_t us);
int cgtimer_to_ms(cgtimer_t *cgt); int cgtimer_to_ms(cgtimer_t *cgt);
void cgtimer_sub(cgtimer_t *a, cgtimer_t *b, cgtimer_t *res); void cgtimer_sub(cgtimer_t *a, cgtimer_t *b, cgtimer_t *res);
double us_tdiff(struct timeval *end, struct timeval *start); double us_tdiff(struct timeval *end, struct timeval *start);
int ms_tdiff(struct timeval *end, struct timeval *start);
double tdiff(struct timeval *end, struct timeval *start); double tdiff(struct timeval *end, struct timeval *start);
bool stratum_send(struct pool *pool, char *s, ssize_t len); bool stratum_send(struct pool *pool, char *s, ssize_t len);
bool sock_full(struct pool *pool); bool sock_full(struct pool *pool);

Loading…
Cancel
Save