Browse Source

Merge branch 'usb-dev'

nfactor-troky
Con Kolivas 12 years ago
parent
commit
357294a70e
  1. 62
      API-README
  2. BIN
      API.class
  3. 13
      API.java
  4. 25
      FPGA-README
  5. 6
      Makefile.am
  6. 20
      README
  7. 2
      adl.c
  8. 225
      api.c
  9. 814
      cgminer.c
  10. 7
      configure.ac
  11. 683
      driver-bitforce.c
  12. 9
      driver-cpu.c
  13. 2
      driver-cpu.h
  14. 19
      driver-icarus.c
  15. 260
      driver-modminer.c
  16. 58
      driver-opencl.c
  17. 2
      driver-opencl.h
  18. 15
      driver-ztex.c
  19. 2
      findnonce.c
  20. 10
      fpgautils.c
  21. 14
      fpgautils.h
  22. 70
      miner.h
  23. 289
      miner.php
  24. 728
      usbutils.c
  25. 76
      usbutils.h
  26. 34
      util.c

62
API-README

@ -347,6 +347,18 @@ The list of requests - a (*) means it requires privileged access - and replies a
The current options are: The current options are:
MMQ opt=clock val=160 to 230 (and a multiple of 2) MMQ opt=clock val=160 to 230 (and a multiple of 2)
zero|Which,true/false (*)
none There is no reply section just the STATUS section
stating that the zero, and optional summary, was done
If Which='all', all normal cgminer and API statistics
will be zeroed other than the numbers displayed by the
usbstats and stats commands
If Which='bestshare', only the 'Best Share' values
are zeroed for each pool and the global 'Best Share'
The true/false option determines if a full summary is
shown on the cgminer display like is normally displayed
on exit.
When you enable, disable or restart a GPU or PGA, you will also get Thread messages When you enable, disable or restart a GPU or PGA, you will also get Thread messages
in the cgminer status window in the cgminer status window
@ -400,7 +412,18 @@ miner.php - an example web page to access the API
Feature Changelog for external applications using the API: Feature Changelog for external applications using the API:
API V1.23 API V1.24
Added API commands:
'zero'
Modified API commands:
'pools' - add 'Best Share'
'devs' and 'pga' - add 'No Device' for PGAs if MMQ or BFL compiled
----------
API V1.23 (cgminer v2.10.2)
Added API commands: Added API commands:
'pgaset' - with: MMQ opt=clock val=160 to 230 (and a multiple of 2) 'pgaset' - with: MMQ opt=clock val=160 to 230 (and a multiple of 2)
@ -930,6 +953,38 @@ true
--------- ---------
Default:
$userlist = null;
Define password checking and default access
null means there is no password checking
$userlist is an array of 3 arrays e.g.
$userlist = array('sys' => array('boss' => 'bpass'),
'usr' => array('user' => 'upass', 'pleb' => 'ppass'),
'def' => array('Pools'));
'sys' is an array of system users and passwords (full access)
'usr' is an array of user level users and passwords (readonly access)
'def' is an array of custompages that anyone not logged in can view
Any of the 3 can be null, meaning there are none of that item
All validated 'usr' users are given $readonly = true; access
All validated 'sys' users are given the $readonly access you defined
If 'def' has one or more values, and allowcustompages is true, then
anyone without a password can see the list of custompage buttons given
in 'def' and will see the first one when they go to the web page, with
a login button at the top right
From the login page, if you login with no username or password, it will
show the first 'def' custompage (if there are any)
If you are logged in, it will show a logout button at the top right
---------
Default: Default:
$notify = true; $notify = true;
@ -1302,9 +1357,12 @@ You can only see fields listed in 'group' and 'calc'
A 'calc' is formatted as: 'Field' => 'function' A 'calc' is formatted as: 'Field' => 'function'
The current list of operations available for 'calc' are: The current list of operations available for 'calc' are:
'sum', 'avg', 'min', 'max', 'lo', 'hi', 'any' 'sum', 'avg', 'min', 'max', 'lo', 'hi', 'coount', 'any'
The first 4 are as expected - the numerical sum, average, minimum or maximum The first 4 are as expected - the numerical sum, average, minimum or maximum
'lo' is the first string of the list, sorted ignoring case 'lo' is the first string of the list, sorted ignoring case
'hi' is the last string of the list, sorted ignoring case 'hi' is the last string of the list, sorted ignoring case
'count' is the number of rows in the section specified in the calc e.g.
('DEVS.Name' => 'count') would be the number of DEVS selected in the 'where'
of course any valid 'DEVS.Xyz' would give the same 'count' value
'any' is effectively random: the field value in the first row of the grouped data 'any' is effectively random: the field value in the first row of the grouped data
An unrecognised 'function' uses 'any' An unrecognised 'function' uses 'any'

BIN
API.class

Binary file not shown.

13
API.java

@ -76,6 +76,7 @@ class API
public void process(String cmd, InetAddress ip, int port) throws Exception public void process(String cmd, InetAddress ip, int port) throws Exception
{ {
StringBuffer sb = new StringBuffer();
char buf[] = new char[MAXRECEIVESIZE]; char buf[] = new char[MAXRECEIVESIZE];
int len = 0; int len = 0;
@ -89,7 +90,15 @@ System.out.println("Attempting to send '"+cmd+"' to "+ip.getHostAddress()+":"+po
ps.flush(); ps.flush();
InputStreamReader isr = new InputStreamReader(socket.getInputStream()); InputStreamReader isr = new InputStreamReader(socket.getInputStream());
len = isr.read(buf, 0, MAXRECEIVESIZE); while (0x80085 > 0)
{
len = isr.read(buf, 0, MAXRECEIVESIZE);
if (len < 1)
break;
sb.append(buf, 0, len);
if (buf[len-1] == '\0')
break;
}
closeAll(); closeAll();
} }
@ -100,7 +109,7 @@ System.out.println("Attempting to send '"+cmd+"' to "+ip.getHostAddress()+":"+po
return; return;
} }
String result = new String(buf, 0, len); String result = sb.toString();
System.out.println("Answer='"+result+"'"); System.out.println("Answer='"+result+"'");

25
FPGA-README

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

6
Makefile.am

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

20
README

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

2
adl.c

@ -1392,7 +1392,7 @@ updated:
clear_logwin(); clear_logwin();
return; return;
} }
sleep(1); nmsleep(1000);
goto updated; goto updated;
} }
#endif #endif

225
api.c

@ -1,5 +1,5 @@
/* /*
* Copyright 2011-2012 Andrew Smith * Copyright 2011-2013 Andrew Smith
* Copyright 2011-2012 Con Kolivas * Copyright 2011-2012 Con Kolivas
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@ -133,7 +133,7 @@ static const char SEPARATOR = '|';
#define SEPSTR "|" #define SEPSTR "|"
static const char GPUSEP = ','; static const char GPUSEP = ',';
static const char *APIVERSION = "1.23"; static const char *APIVERSION = "1.24";
static const char *DEAD = "Dead"; static const char *DEAD = "Dead";
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA) #if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA)
static const char *SICK = "Sick"; static const char *SICK = "Sick";
@ -387,6 +387,12 @@ static const char *JSON_PARAMETER = "parameter";
#define MSG_PGASETERR 93 #define MSG_PGASETERR 93
#endif #endif
#define MSG_ZERMIS 94
#define MSG_ZERINV 95
#define MSG_ZERSUM 96
#define MSG_ZERNOSUM 97
#define MSG_USBNODEV 98
enum code_severity { enum code_severity {
SEVERITY_ERR, SEVERITY_ERR,
SEVERITY_WARN, SEVERITY_WARN,
@ -558,6 +564,13 @@ struct CODES {
{ SEVERITY_INFO, MSG_PGAHELP, PARAM_BOTH, "PGA %d set help: %s" }, { SEVERITY_INFO, MSG_PGAHELP, PARAM_BOTH, "PGA %d set help: %s" },
{ SEVERITY_SUCC, MSG_PGASETOK, PARAM_BOTH, "PGA %d set OK" }, { SEVERITY_SUCC, MSG_PGASETOK, PARAM_BOTH, "PGA %d set OK" },
{ SEVERITY_ERR, MSG_PGASETERR, PARAM_BOTH, "PGA %d set failed: %s" }, { SEVERITY_ERR, MSG_PGASETERR, PARAM_BOTH, "PGA %d set failed: %s" },
#endif
{ SEVERITY_ERR, MSG_ZERMIS, PARAM_NONE, "Missing zero parameters" },
{ SEVERITY_ERR, MSG_ZERINV, PARAM_STR, "Invalid zero parameter '%s'" },
{ SEVERITY_SUCC, MSG_ZERSUM, PARAM_STR, "Zeroed %s stats with summary" },
{ SEVERITY_SUCC, MSG_ZERNOSUM, PARAM_STR, "Zeroed %s stats without summary" },
#if defined(USE_MODMINER) || defined(USE_BITFORCE)
{ SEVERITY_ERR, MSG_USBNODEV, PARAM_PGA, "PGA%d has no device" },
#endif #endif
{ SEVERITY_FAIL, 0, 0, NULL } { SEVERITY_FAIL, 0, 0, NULL }
}; };
@ -599,22 +612,6 @@ struct APIGROUPS {
static struct IP4ACCESS *ipaccess = NULL; static struct IP4ACCESS *ipaccess = NULL;
static int ips = 0; static int ips = 0;
#ifdef USE_BITFORCE
extern struct device_api bitforce_api;
#endif
#ifdef USE_ICARUS
extern struct device_api icarus_api;
#endif
#ifdef USE_ZTEX
extern struct device_api ztex_api;
#endif
#ifdef USE_MODMINER
extern struct device_api modminer_api;
#endif
struct io_data { struct io_data {
size_t siz; size_t siz;
char *ptr; char *ptr;
@ -1151,24 +1148,26 @@ static int numpgas()
int count = 0; int count = 0;
int i; int i;
mutex_lock(&devices_lock);
for (i = 0; i < total_devices; i++) { for (i = 0; i < total_devices; i++) {
#ifdef USE_BITFORCE #ifdef USE_BITFORCE
if (devices[i]->api == &bitforce_api) if (devices[i]->drv->drv_id == DRIVER_BITFORCE)
count++; count++;
#endif #endif
#ifdef USE_ICARUS #ifdef USE_ICARUS
if (devices[i]->api == &icarus_api) if (devices[i]->drv->drv_id == DRIVER_ICARUS)
count++; count++;
#endif #endif
#ifdef USE_ZTEX #ifdef USE_ZTEX
if (devices[i]->api == &ztex_api) if (devices[i]->drv->drv_id == DRIVER_ZTEX)
count++; count++;
#endif #endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
if (devices[i]->api == &modminer_api) if (devices[i]->drv->drv_id == DRIVER_MODMINER)
count++; count++;
#endif #endif
} }
mutex_unlock(&devices_lock);
return count; return count;
} }
@ -1177,27 +1176,35 @@ static int pgadevice(int pgaid)
int count = 0; int count = 0;
int i; int i;
mutex_lock(&devices_lock);
for (i = 0; i < total_devices; i++) { for (i = 0; i < total_devices; i++) {
#ifdef USE_BITFORCE #ifdef USE_BITFORCE
if (devices[i]->api == &bitforce_api) if (devices[i]->drv->drv_id == DRIVER_BITFORCE)
count++; count++;
#endif #endif
#ifdef USE_ICARUS #ifdef USE_ICARUS
if (devices[i]->api == &icarus_api) if (devices[i]->drv->drv_id == DRIVER_ICARUS)
count++; count++;
#endif #endif
#ifdef USE_ZTEX #ifdef USE_ZTEX
if (devices[i]->api == &ztex_api) if (devices[i]->drv->drv_id == DRIVER_ZTEX)
count++; count++;
#endif #endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
if (devices[i]->api == &modminer_api) if (devices[i]->drv->drv_id == DRIVER_MODMINER)
count++; count++;
#endif #endif
if (count == (pgaid + 1)) if (count == (pgaid + 1))
return i; goto foundit;
} }
mutex_unlock(&devices_lock);
return -1; return -1;
foundit:
mutex_unlock(&devices_lock);
return i;
} }
#endif #endif
@ -1530,16 +1537,16 @@ static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom
if (dev < 0) // Should never happen if (dev < 0) // Should never happen
return; return;
struct cgpu_info *cgpu = devices[dev]; struct cgpu_info *cgpu = get_devices(dev);
double frequency = 0; double frequency = 0;
float temp = cgpu->temp; float temp = cgpu->temp;
#ifdef USE_ZTEX #ifdef USE_ZTEX
if (cgpu->api == &ztex_api && 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->api == &modminer_api) if (cgpu->drv->drv_id == DRIVER_MODMINER)
frequency = cgpu->clock; frequency = cgpu->clock;
#endif #endif
@ -1553,7 +1560,7 @@ static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom
status = (char *)status2str(cgpu->status); status = (char *)status2str(cgpu->status);
root = api_add_int(root, "PGA", &pga, false); root = api_add_int(root, "PGA", &pga, false);
root = api_add_string(root, "Name", cgpu->api->name, false); root = api_add_string(root, "Name", cgpu->drv->name, false);
root = api_add_int(root, "ID", &(cgpu->device_id), false); root = api_add_int(root, "ID", &(cgpu->device_id), false);
root = api_add_string(root, "Enabled", enabled, false); root = api_add_string(root, "Enabled", enabled, false);
root = api_add_string(root, "Status", status, false); root = api_add_string(root, "Status", status, false);
@ -1577,6 +1584,9 @@ static void pgastatus(struct io_data *io_data, int pga, bool isjson, bool precom
root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false); root = api_add_diff(root, "Difficulty Accepted", &(cgpu->diff_accepted), false);
root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false); root = api_add_diff(root, "Difficulty Rejected", &(cgpu->diff_rejected), false);
root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false); root = api_add_diff(root, "Last Share Difficulty", &(cgpu->last_share_diff), false);
#if defined(USE_MODMINER) || defined(USE_BITFORCE)
root = api_add_bool(root, "No Device", &(cgpu->usbinfo.nodev), false);
#endif
root = print_data(root, buf, isjson, precom); root = print_data(root, buf, isjson, precom);
io_add(io_data, buf); io_add(io_data, buf);
@ -1747,6 +1757,7 @@ static void pgadev(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *p
static void pgaenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) static void pgaenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
{ {
struct cgpu_info *cgpu;
int numpga = numpgas(); int numpga = numpgas();
struct thr_info *thr; struct thr_info *thr;
int pga; int pga;
@ -1775,7 +1786,10 @@ static void pgaenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char
return; return;
} }
struct cgpu_info *cgpu = devices[dev]; cgpu = get_devices(dev);
applog(LOG_DEBUG, "API: request to pgaenable pgaid %d device %d %s%u",
id, dev, cgpu->drv->name, cgpu->device_id);
if (cgpu->deven != DEV_DISABLED) { if (cgpu->deven != DEV_DISABLED) {
message(io_data, MSG_PGALRENA, id, NULL, isjson); message(io_data, MSG_PGALRENA, id, NULL, isjson);
@ -1789,11 +1803,19 @@ static void pgaenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char
} }
#endif #endif
#if defined(USE_MODMINER) || defined(USE_BITFORCE)
if (cgpu->usbinfo.nodev) {
message(io_data, MSG_USBNODEV, id, NULL, isjson);
return;
}
#endif
for (i = 0; i < mining_threads; i++) { for (i = 0; i < mining_threads; i++) {
pga = thr_info[i].cgpu->device_id; thr = get_thread(i);
pga = thr->cgpu->cgminer_id;
if (pga == dev) { if (pga == dev) {
thr = &thr_info[i];
cgpu->deven = DEV_ENABLED; cgpu->deven = DEV_ENABLED;
applog(LOG_DEBUG, "API: pushing ping (%d) to thread %d", ping, thr->id);
tq_push(thr->q, &ping); tq_push(thr->q, &ping);
} }
} }
@ -1803,6 +1825,7 @@ static void pgaenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char
static void pgadisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) static void pgadisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
{ {
struct cgpu_info *cgpu;
int numpga = numpgas(); int numpga = numpgas();
int id; int id;
@ -1828,7 +1851,10 @@ static void pgadisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
return; return;
} }
struct cgpu_info *cgpu = devices[dev]; cgpu = get_devices(dev);
applog(LOG_DEBUG, "API: request to pgadisable pgaid %d device %d %s%u",
id, dev, cgpu->drv->name, cgpu->device_id);
if (cgpu->deven == DEV_DISABLED) { if (cgpu->deven == DEV_DISABLED) {
message(io_data, MSG_PGALRDIS, id, NULL, isjson); message(io_data, MSG_PGALRDIS, id, NULL, isjson);
@ -1842,6 +1868,8 @@ static void pgadisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
static void pgaidentify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group) static void pgaidentify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
{ {
struct cgpu_info *cgpu;
struct device_drv *drv;
int numpga = numpgas(); int numpga = numpgas();
int id; int id;
@ -1867,13 +1895,13 @@ static void pgaidentify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, ch
return; return;
} }
struct cgpu_info *cgpu = devices[dev]; cgpu = get_devices(dev);
struct device_api *api = cgpu->api; drv = cgpu->drv;
if (!api->identify_device) if (!drv->identify_device)
message(io_data, MSG_PGANOID, id, NULL, isjson); message(io_data, MSG_PGANOID, id, NULL, isjson);
else { else {
api->identify_device(cgpu); drv->identify_device(cgpu);
message(io_data, MSG_PGAIDENT, id, NULL, isjson); message(io_data, MSG_PGAIDENT, id, NULL, isjson);
} }
} }
@ -1993,6 +2021,7 @@ static void poolstatus(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m
else else
root = api_add_const(root, "Stratum URL", BLANK, false); root = api_add_const(root, "Stratum URL", BLANK, false);
root = api_add_bool(root, "Has GBT", &(pool->has_gbt), false); root = api_add_bool(root, "Has GBT", &(pool->has_gbt), false);
root = api_add_uint64(root, "Best Share", &(pool->best_diff), true);
root = print_data(root, buf, isjson, isjson && (i > 0)); root = print_data(root, buf, isjson, isjson && (i > 0));
io_add(io_data, buf); io_add(io_data, buf);
@ -2081,23 +2110,25 @@ static void gpuenable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char
return; return;
} }
applog(LOG_DEBUG, "API: request to gpuenable gpuid %d %s%u",
id, gpus[id].drv->name, gpus[id].device_id);
if (gpus[id].deven != DEV_DISABLED) { if (gpus[id].deven != DEV_DISABLED) {
message(io_data, MSG_ALRENA, id, NULL, isjson); message(io_data, MSG_ALRENA, id, NULL, isjson);
return; return;
} }
for (i = 0; i < gpu_threads; i++) { for (i = 0; i < gpu_threads; i++) {
gpu = thr_info[i].cgpu->device_id; thr = get_thread(i);
gpu = thr->cgpu->device_id;
if (gpu == id) { if (gpu == id) {
thr = &thr_info[i];
if (thr->cgpu->status != LIFE_WELL) { if (thr->cgpu->status != LIFE_WELL) {
message(io_data, MSG_GPUMRE, id, NULL, isjson); message(io_data, MSG_GPUMRE, id, NULL, isjson);
return; return;
} }
gpus[id].deven = DEV_ENABLED; gpus[id].deven = DEV_ENABLED;
applog(LOG_DEBUG, "API: pushing ping (%d) to thread %d", ping, thr->id);
tq_push(thr->q, &ping); tq_push(thr->q, &ping);
} }
} }
@ -2124,6 +2155,9 @@ static void gpudisable(struct io_data *io_data, __maybe_unused SOCKETTYPE c, cha
return; return;
} }
applog(LOG_DEBUG, "API: request to gpudisable gpuid %d %s%u",
id, gpus[id].drv->name, gpus[id].device_id);
if (gpus[id].deven == DEV_DISABLED) { if (gpus[id].deven == DEV_DISABLED) {
message(io_data, MSG_ALRDIS, id, NULL, isjson); message(io_data, MSG_ALRDIS, id, NULL, isjson);
return; return;
@ -2752,7 +2786,7 @@ void notifystatus(struct io_data *io_data, int device, struct cgpu_info *cgpu, b
// ALL counters (and only counters) must start the name with a '*' // ALL counters (and only counters) must start the name with a '*'
// Simplifies future external support for identifying new counters // Simplifies future external support for identifying new counters
root = api_add_int(root, "NOTIFY", &device, false); root = api_add_int(root, "NOTIFY", &device, false);
root = api_add_string(root, "Name", cgpu->api->name, false); root = api_add_string(root, "Name", cgpu->drv->name, false);
root = api_add_int(root, "ID", &(cgpu->device_id), false); root = api_add_int(root, "ID", &(cgpu->device_id), false);
root = api_add_time(root, "Last Well", &(cgpu->device_last_well), false); root = api_add_time(root, "Last Well", &(cgpu->device_last_well), false);
root = api_add_time(root, "Last Not Well", &(cgpu->device_last_not_well), false); root = api_add_time(root, "Last Not Well", &(cgpu->device_last_not_well), false);
@ -2774,6 +2808,7 @@ void notifystatus(struct io_data *io_data, int device, struct cgpu_info *cgpu, b
static void notify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, char group) static void notify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, char group)
{ {
struct cgpu_info *cgpu;
bool io_open = false; bool io_open = false;
int i; int i;
@ -2787,8 +2822,10 @@ static void notify(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe
if (isjson) if (isjson)
io_open = io_add(io_data, COMSTR JSON_NOTIFY); io_open = io_add(io_data, COMSTR JSON_NOTIFY);
for (i = 0; i < total_devices; i++) for (i = 0; i < total_devices; i++) {
notifystatus(io_data, i, devices[i], isjson, group); cgpu = get_devices(i);
notifystatus(io_data, i, cgpu, isjson, group);
}
if (isjson && io_open) if (isjson && io_open)
io_close(io_data); io_close(io_data);
@ -2813,12 +2850,12 @@ static void devdetails(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m
io_open = io_add(io_data, COMSTR JSON_DEVDETAILS); io_open = io_add(io_data, COMSTR JSON_DEVDETAILS);
for (i = 0; i < total_devices; i++) { for (i = 0; i < total_devices; i++) {
cgpu = devices[i]; cgpu = get_devices(i);
root = api_add_int(root, "DEVDETAILS", &i, false); root = api_add_int(root, "DEVDETAILS", &i, false);
root = api_add_string(root, "Name", cgpu->api->name, false); root = api_add_string(root, "Name", cgpu->drv->name, false);
root = api_add_int(root, "ID", &(cgpu->device_id), false); root = api_add_int(root, "ID", &(cgpu->device_id), false);
root = api_add_string(root, "Driver", cgpu->api->dname, false); root = api_add_string(root, "Driver", cgpu->drv->dname, false);
root = api_add_const(root, "Kernel", cgpu->kname ? : BLANK, false); root = api_add_const(root, "Kernel", cgpu->kname ? : BLANK, false);
root = api_add_const(root, "Model", cgpu->name ? : BLANK, false); root = api_add_const(root, "Model", cgpu->name ? : BLANK, false);
root = api_add_const(root, "Device Path", cgpu->device_path ? : BLANK, false); root = api_add_const(root, "Device Path", cgpu->device_path ? : BLANK, false);
@ -2895,6 +2932,8 @@ static int itemstats(struct io_data *io_data, int i, char *id, struct cgminer_st
root = api_add_uint64(root, "Bytes Sent", &(pool_stats->bytes_sent), false); root = api_add_uint64(root, "Bytes Sent", &(pool_stats->bytes_sent), false);
root = api_add_uint64(root, "Times Recv", &(pool_stats->times_received), false); root = api_add_uint64(root, "Times Recv", &(pool_stats->times_received), false);
root = api_add_uint64(root, "Bytes Recv", &(pool_stats->bytes_received), false); root = api_add_uint64(root, "Bytes Recv", &(pool_stats->bytes_received), false);
root = api_add_uint64(root, "Net Bytes Sent", &(pool_stats->net_bytes_sent), false);
root = api_add_uint64(root, "Net Bytes Recv", &(pool_stats->net_bytes_received), false);
} }
if (extra) if (extra)
@ -2908,6 +2947,7 @@ static int itemstats(struct io_data *io_data, int i, char *id, struct cgminer_st
static void minerstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) static void minerstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
{ {
struct cgpu_info *cgpu;
bool io_open = false; bool io_open = false;
struct api_data *extra; struct api_data *extra;
char id[20]; char id[20];
@ -2920,15 +2960,15 @@ static void minerstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __m
i = 0; i = 0;
for (j = 0; j < total_devices; j++) { for (j = 0; j < total_devices; j++) {
struct cgpu_info *cgpu = devices[j]; cgpu = get_devices(j);
if (cgpu && cgpu->api) { if (cgpu && cgpu->drv) {
if (cgpu->api->get_api_stats) if (cgpu->drv->get_api_stats)
extra = cgpu->api->get_api_stats(cgpu); extra = cgpu->drv->get_api_stats(cgpu);
else else
extra = NULL; extra = NULL;
sprintf(id, "%s%d", cgpu->api->name, cgpu->device_id); sprintf(id, "%s%d", cgpu->drv->name, cgpu->device_id);
i = itemstats(io_data, i, id, &(cgpu->cgminer_stats), NULL, extra, isjson); i = itemstats(io_data, i, id, &(cgpu->cgminer_stats), NULL, extra, isjson);
} }
} }
@ -3120,7 +3160,7 @@ static void usbstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __may
{ {
struct api_data *root = NULL; struct api_data *root = NULL;
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
char buf[TMPBUFSIZ]; char buf[TMPBUFSIZ];
bool io_open = false; bool io_open = false;
int count = 0; int count = 0;
@ -3133,7 +3173,7 @@ static void usbstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __may
return; return;
} }
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
message(io_data, MSG_USBSTA, 0, NULL, isjson); message(io_data, MSG_USBSTA, 0, NULL, isjson);
@ -3160,6 +3200,8 @@ static void usbstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __may
#ifdef HAVE_AN_FPGA #ifdef HAVE_AN_FPGA
static void pgaset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) static void pgaset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
{ {
struct cgpu_info *cgpu;
struct device_drv *drv;
char buf[TMPBUFSIZ]; char buf[TMPBUFSIZ];
int numpga = numpgas(); int numpga = numpgas();
@ -3193,17 +3235,17 @@ static void pgaset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe
return; return;
} }
struct cgpu_info *cgpu = devices[dev]; cgpu = get_devices(dev);
struct device_api *api = cgpu->api; drv = cgpu->drv;
char *set = strchr(opt, ','); char *set = strchr(opt, ',');
if (set) if (set)
*(set++) = '\0'; *(set++) = '\0';
if (!api->set_device) if (!drv->set_device)
message(io_data, MSG_PGANOSET, id, NULL, isjson); message(io_data, MSG_PGANOSET, id, NULL, isjson);
else { else {
char *ret = api->set_device(cgpu, opt, set, buf); char *ret = drv->set_device(cgpu, opt, set, buf);
if (ret) { if (ret) {
if (strcasecmp(opt, "help") == 0) if (strcasecmp(opt, "help") == 0)
message(io_data, MSG_PGAHELP, id, ret, isjson); message(io_data, MSG_PGAHELP, id, ret, isjson);
@ -3215,6 +3257,54 @@ static void pgaset(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe
} }
#endif #endif
static void dozero(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, __maybe_unused char group)
{
if (param == NULL || *param == '\0') {
message(io_data, MSG_ZERMIS, 0, NULL, isjson);
return;
}
char *sum = strchr(param, ',');
if (sum)
*(sum++) = '\0';
if (!sum || !*sum) {
message(io_data, MSG_MISBOOL, 0, NULL, isjson);
return;
}
bool all = false;
bool bs = false;
if (strcasecmp(param, "all") == 0)
all = true;
else if (strcasecmp(param, "bestshare") == 0)
bs = true;
if (all == false && bs == false) {
message(io_data, MSG_ZERINV, 0, param, isjson);
return;
}
*sum = tolower(*sum);
if (*sum != 't' && *sum != 'f') {
message(io_data, MSG_INVBOOL, 0, NULL, isjson);
return;
}
bool dosum = (*sum == 't');
if (dosum)
print_summary();
if (all)
zero_stats();
if (bs)
zero_bestshare();
if (dosum)
message(io_data, MSG_ZERSUM, 0, all ? "All" : "BestShare", isjson);
else
message(io_data, MSG_ZERNOSUM, 0, all ? "All" : "BestShare", isjson);
}
static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group); static void checkcommand(struct io_data *io_data, __maybe_unused SOCKETTYPE c, char *param, bool isjson, char group);
struct CMDS { struct CMDS {
@ -3274,6 +3364,7 @@ struct CMDS {
#ifdef HAVE_AN_FPGA #ifdef HAVE_AN_FPGA
{ "pgaset", pgaset, true }, { "pgaset", pgaset, true },
#endif #endif
{ "zero", dozero, true },
{ NULL, NULL, false } { NULL, NULL, false }
}; };
@ -3342,12 +3433,10 @@ static void send_result(struct io_data *io_data, SOCKETTYPE c, bool isjson)
// ignore failure - it's closed immediately anyway // ignore failure - it's closed immediately anyway
n = send(c, buf, len+1, 0); n = send(c, buf, len+1, 0);
if (opt_debug) { if (SOCKETFAIL(n))
if (SOCKETFAIL(n)) applog(LOG_WARNING, "API: send failed: %s", SOCKERRMSG);
applog(LOG_DEBUG, "API: send failed: %s", SOCKERRMSG); else
else applog(LOG_DEBUG, "API: sent %d", n);
applog(LOG_DEBUG, "API: sent %d", n);
}
} }
static void tidyup(__maybe_unused void *arg) static void tidyup(__maybe_unused void *arg)
@ -3701,7 +3790,7 @@ void api(int api_thr_id)
/* This should be done before curl in needed /* This should be done before curl in needed
* to ensure curl has already called WSAStartup() in windows */ * to ensure curl has already called WSAStartup() in windows */
sleep(opt_log_interval); nmsleep(opt_log_interval*1000);
sock = socket(AF_INET, SOCK_STREAM, 0); sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVSOCK) { if (sock == INVSOCK) {
@ -3747,7 +3836,7 @@ void api(int api_thr_id)
break; break;
else { else {
applog(LOG_WARNING, "API bind to port %d failed - trying again in 30sec", port); applog(LOG_WARNING, "API bind to port %d failed - trying again in 30sec", port);
sleep(30); nmsleep(30000);
} }
} else } else
bound = 1; bound = 1;

814
cgminer.c

File diff suppressed because it is too large Load Diff

7
configure.ac

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

683
driver-bitforce.c

@ -1,4 +1,5 @@
/* /*
* Copyright 2012-2013 Andrew Smith
* Copyright 2012 Luke Dashjr * Copyright 2012 Luke Dashjr
* Copyright 2012 Con Kolivas * Copyright 2012 Con Kolivas
* *
@ -19,34 +20,35 @@
#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)
// Either of Nonce or No-nonce start with:
#define BITFORCE_EITHER "N"
#define BITFORCE_EITHER_LEN 1
#define BITFORCE_NONCE "NONCE-FOUND"
#define BITFORCE_NONCE_LEN (sizeof(BITFORCE_NONCE)-1)
#define BITFORCE_NO_NONCE "NO-NONCE"
#define BITFORCE_NO_NONCE_MATCH 3
#define BITFORCE_IDLE "IDLE"
#define BITFORCE_IDLE_MATCH 1
#define BITFORCE_SLEEP_MS 500 #define BITFORCE_SLEEP_MS 500
#define BITFORCE_TIMEOUT_S 7 #define BITFORCE_TIMEOUT_S 7
@ -62,62 +64,200 @@ enum {
#define KNAME_WORK "full work" #define KNAME_WORK "full work"
#define KNAME_RANGE "nonce range" #define KNAME_RANGE "nonce range"
struct device_api bitforce_api; #define BITFORCE_BUFSIZ (0x200)
static void BFgets(char *buf, size_t bufLen, int fd) // If initialisation fails the first time,
{ // sleep this amount (ms) and try again
do { #define REINIT_TIME_FIRST_MS 100
buf[0] = '\0'; // Max ms per sleep
--bufLen; #define REINIT_TIME_MAX_MS 800
} while (likely(bufLen && read(fd, buf, 1) == 1 && (buf++)[0] != '\n')); // Keep trying up to this many us
#define REINIT_TIME_MAX 3000000
buf[0] = '\0'; static const char *blank = "";
}
struct device_drv bitforce_drv;
static ssize_t BFwrite(int fd, const void *buf, ssize_t bufLen) static void bitforce_initialise(struct cgpu_info *bitforce, bool lock)
{ {
if ((bufLen) != write(fd, buf, bufLen)) int err;
return 0;
else
return bufLen;
}
#define BFclose(fd) close(fd) if (lock)
mutex_lock(&bitforce->device_mutex);
static bool bitforce_detect_one(const char *devpath) if (bitforce->usbinfo.nodev)
goto failed;
// Reset
err = usb_transfer(bitforce, FTDI_TYPE_OUT, FTDI_REQUEST_RESET,
FTDI_VALUE_RESET, bitforce->usbdev->found->interface, C_RESET);
if (opt_debug)
applog(LOG_DEBUG, "%s%i: reset got err %d",
bitforce->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// 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->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// 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->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// 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->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// 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->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// 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->drv->name, bitforce->device_id, err);
if (bitforce->usbinfo.nodev)
goto failed;
// 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->drv->name, bitforce->device_id, err);
failed:
if (lock)
mutex_unlock(&bitforce->device_mutex);
}
static bool bitforce_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
{ {
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;
struct timeval init_start, init_now;
int init_sleep, init_count;
bool ident_first;
applog(LOG_DEBUG, "BFL: Attempting to open %s", devpath); struct cgpu_info *bitforce = NULL;
bitforce = calloc(1, sizeof(*bitforce));
bitforce->drv = &bitforce_drv;
bitforce->deven = DEV_ENABLED;
bitforce->threads = 1;
if (unlikely(fdDev == -1)) { if (!usb_init(bitforce, dev, found)) {
applog(LOG_ERR, "BFL: Failed to open %s", devpath); applog(LOG_ERR, "%s detect (%d:%d) failed to initialise (incorrect device?)",
return false; bitforce->drv->dname,
(int)(bitforce->usbinfo.bus_number),
(int)(bitforce->usbinfo.device_address));
goto shin;
} }
BFwrite(fdDev, "ZGX", 3); sprintf(devpath, "%d:%d",
pdevbuf[0] = '\0'; (int)(bitforce->usbinfo.bus_number),
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); (int)(bitforce->usbinfo.device_address));
if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "BFL: Error reading/timeout (ZGX)");
return 0; // Allow 2 complete attempts if the 1st time returns an unrecognised reply
ident_first = true;
retry:
init_count = 0;
init_sleep = REINIT_TIME_FIRST_MS;
gettimeofday(&init_start, NULL);
reinit:
bitforce_initialise(bitforce, false);
if ((err = usb_write(bitforce, BITFORCE_IDENTIFY, BITFORCE_IDENTIFY_LEN, &amount, C_REQUESTIDENTIFY)) < 0 || amount != BITFORCE_IDENTIFY_LEN) {
applog(LOG_ERR, "%s detect (%s) send identify request failed (%d:%d)",
bitforce->drv->dname, devpath, amount, err);
goto unshin;
} }
BFclose(fdDev); if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETIDENTIFY)) < 0 || amount < 1) {
if (unlikely(!strstr(pdevbuf, "SHA256"))) { init_count++;
applog(LOG_ERR, "BFL: Didn't recognise BitForce on %s", devpath); gettimeofday(&init_now, NULL);
return false; if (us_tdiff(&init_now, &init_start) <= REINIT_TIME_MAX) {
if (init_count == 2) {
applog(LOG_WARNING, "%s detect (%s) 2nd init failed (%d:%d) - retrying",
bitforce->drv->dname, devpath, amount, err);
}
nmsleep(init_sleep);
if ((init_sleep * 2) <= REINIT_TIME_MAX_MS)
init_sleep *= 2;
goto reinit;
}
if (init_count > 0)
applog(LOG_WARNING, "%s detect (%s) init failed %d times %.2fs",
bitforce->drv->dname, devpath, init_count, tdiff(&init_now, &init_start));
if (err < 0) {
applog(LOG_ERR, "%s detect (%s) error identify reply (%d:%d)",
bitforce->drv->dname, devpath, amount, err);
} else {
applog(LOG_ERR, "%s detect (%s) empty identify reply (%d)",
bitforce->drv->dname, devpath, amount);
}
goto unshin;
}
buf[amount] = '\0';
if (unlikely(!strstr(buf, "SHA256"))) {
if (ident_first) {
applog(LOG_WARNING, "%s detect (%s) didn't recognise '%s' trying again ...",
bitforce->drv->dname, devpath, buf);
ident_first = false;
goto retry;
}
applog(LOG_ERR, "%s detect (%s) didn't recognise '%s' on 2nd attempt",
bitforce->drv->dname, devpath, buf);
goto unshin;
}
if (likely((!memcmp(buf, ">>>ID: ", 7)) && (s = strstr(buf + 3, ">>>")))) {
s[0] = '\0';
bitforce->name = strdup(buf + 7);
} else {
bitforce->name = (char *)blank;
} }
// We have a real BitForce! // We have a real BitForce!
bitforce = calloc(1, sizeof(*bitforce)); applog(LOG_DEBUG, "%s (%s) identified as: '%s'",
bitforce->api = &bitforce_api; bitforce->drv->dname, devpath, bitforce->name);
bitforce->device_path = strdup(devpath);
bitforce->deven = DEV_ENABLED;
bitforce->threads = 1;
/* Initially enable support for nonce range and disable it later if it /* Initially enable support for nonce range and disable it later if it
* fails */ * fails */
if (opt_bfl_noncerange) { if (opt_bfl_noncerange) {
@ -129,108 +269,39 @@ static bool bitforce_detect_one(const char *devpath)
bitforce->kname = KNAME_WORK; bitforce->kname = KNAME_WORK;
} }
if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) { bitforce->device_path = strdup(devpath);
s[0] = '\0';
bitforce->name = strdup(pdevbuf + 7); if (!add_cgpu(bitforce))
} goto unshin;
update_usb_stats(bitforce);
mutex_init(&bitforce->device_mutex); mutex_init(&bitforce->device_mutex);
return add_cgpu(bitforce); return true;
}
#define LOAD_SYM(sym) do { \ unshin:
if (!(sym = dlsym(dll, #sym))) { \
applog(LOG_DEBUG, "Failed to load " #sym ", not using FTDI bitforce autodetect"); \
goto out; \
} \
} while(0)
#ifdef WIN32 usb_uninit(bitforce);
static int bitforce_autodetect_ftdi(void)
{
char devpath[] = "\\\\.\\COMnnnnn";
char *devpathnum = &devpath[7];
char **bufptrs;
char *buf;
int found = 0;
DWORD i;
FT_STATUS ftStatus;
DWORD numDevs;
HMODULE dll = LoadLibrary("FTD2XX.DLL");
if (!dll) {
applog(LOG_DEBUG, "FTD2XX.DLL failed to load, not using FTDI bitforce autodetect");
return 0;
}
LOAD_SYM(FT_ListDevices);
LOAD_SYM(FT_Open);
LOAD_SYM(FT_GetComPortNumber);
LOAD_SYM(FT_Close);
ftStatus = FT_ListDevices(&numDevs, NULL, FT_LIST_NUMBER_ONLY);
if (ftStatus != FT_OK) {
applog(LOG_DEBUG, "FTDI device count failed, not using FTDI bitforce autodetect");
goto out;
}
applog(LOG_DEBUG, "FTDI reports %u devices", (unsigned)numDevs);
buf = alloca(65 * numDevs);
bufptrs = alloca(sizeof(*bufptrs) * (numDevs + 1));
for (i = 0; i < numDevs; ++i)
bufptrs[i] = &buf[i * 65];
bufptrs[numDevs] = NULL;
ftStatus = FT_ListDevices(bufptrs, &numDevs, FT_LIST_ALL | FT_OPEN_BY_DESCRIPTION);
if (ftStatus != FT_OK) {
applog(LOG_DEBUG, "FTDI device list failed, not using FTDI bitforce autodetect");
goto out;
}
for (i = numDevs; i > 0; ) {
--i;
bufptrs[i][64] = '\0';
if (!(strstr(bufptrs[i], "BitFORCE") && strstr(bufptrs[i], "SHA256")))
continue;
FT_HANDLE ftHandle;
if (FT_OK != FT_Open(i, &ftHandle))
continue;
LONG lComPortNumber;
ftStatus = FT_GetComPortNumber(ftHandle, &lComPortNumber);
FT_Close(ftHandle);
if (FT_OK != ftStatus || lComPortNumber < 0)
continue;
sprintf(devpathnum, "%d", (int)lComPortNumber);
if (bitforce_detect_one(devpath))
++found;
}
out: shin:
dlclose(dll);
return found;
}
#else
static int bitforce_autodetect_ftdi(void)
{
return 0;
}
#endif
static int bitforce_detect_auto(void) free(bitforce->device_path);
{
return (serial_autodetect_udev (bitforce_detect_one, "BitFORCE*SHA256") ?: if (bitforce->name != blank)
serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?: free(bitforce->name);
bitforce_autodetect_ftdi() ?:
0); if (bitforce->drv->copy)
free(bitforce->drv);
free(bitforce);
return false;
} }
static void bitforce_detect(void) static void bitforce_detect(void)
{ {
serial_detect_auto(&bitforce_api, bitforce_detect_one, bitforce_detect_auto); usb_detect(&bitforce_drv, 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 +318,17 @@ static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
static bool bitforce_thread_prepare(struct thr_info *thr) static bool bitforce_thread_prepare(struct thr_info *thr)
{ {
struct cgpu_info *bitforce = thr->cgpu; struct cgpu_info *bitforce = thr->cgpu;
int fdDev = BFopen(bitforce->device_path);
struct timeval now; struct timeval now;
if (unlikely(fdDev == -1)) {
applog(LOG_ERR, "BFL%i: Failed to open %s", bitforce->device_id, bitforce->device_path);
return false;
}
bitforce->device_fd = fdDev;
applog(LOG_INFO, "BFL%i: Opened %s", bitforce->device_id, bitforce->device_path);
gettimeofday(&now, NULL); gettimeofday(&now, NULL);
get_datestamp(bitforce->init, &now); get_datestamp(bitforce->init, &now);
return true; return true;
} }
static void bitforce_clear_buffer(struct cgpu_info *bitforce)
{
int fdDev = bitforce->device_fd;
char pdevbuf[0x100];
int count = 0;
if (!fdDev)
return;
applog(LOG_DEBUG, "BFL%i: Clearing read buffer", bitforce->device_id);
mutex_lock(&bitforce->device_mutex);
do {
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
} while (pdevbuf[0] && (++count < 10));
mutex_unlock(&bitforce->device_mutex);
}
void bitforce_init(struct cgpu_info *bitforce)
{
char *devpath = bitforce->device_path;
int fdDev = bitforce->device_fd, retries = 0;
char pdevbuf[0x100];
char *s;
applog(LOG_WARNING, "BFL%i: Re-initialising", bitforce->device_id);
bitforce_clear_buffer(bitforce);
mutex_lock(&bitforce->device_mutex);
if (fdDev) {
BFclose(fdDev);
sleep(5);
}
bitforce->device_fd = 0;
fdDev = BFopen(devpath);
if (unlikely(fdDev == -1)) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "BFL%i: Failed to open %s", bitforce->device_id, devpath);
return;
}
do {
BFwrite(fdDev, "ZGX", 3);
pdevbuf[0] = '\0';
BFgets(pdevbuf, sizeof(pdevbuf), fdDev);
if (unlikely(!pdevbuf[0])) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "BFL%i: Error reading/timeout (ZGX)", bitforce->device_id);
return;
}
if (retries++)
nmsleep(10);
} while (!strstr(pdevbuf, "BUSY") && (retries * 10 < BITFORCE_TIMEOUT_MS));
if (unlikely(!strstr(pdevbuf, "SHA256"))) {
mutex_unlock(&bitforce->device_mutex);
applog(LOG_ERR, "BFL%i: Didn't recognise BitForce on %s returned: %s", bitforce->device_id, devpath, pdevbuf);
return;
}
if (likely((!memcmp(pdevbuf, ">>>ID: ", 7)) && (s = strstr(pdevbuf + 3, ">>>")))) {
s[0] = '\0';
bitforce->name = strdup(pdevbuf + 7);
}
bitforce->device_fd = fdDev;
bitforce->sleep_ms = BITFORCE_SLEEP_MS;
mutex_unlock(&bitforce->device_mutex);
}
static void bitforce_flash_led(struct cgpu_info *bitforce) static void bitforce_flash_led(struct cgpu_info *bitforce)
{ {
int fdDev = bitforce->device_fd; int err, amount;
if (!fdDev)
return;
/* Do not try to flash the led if we're polling for a result to /* Do not try to flash the led if we're polling for a result to
* minimise the chance of interleaved results */ * minimise the chance of interleaved results */
@ -353,19 +336,22 @@ static void bitforce_flash_led(struct cgpu_info *bitforce)
return; return;
/* It is not critical flashing the led so don't get stuck if we /* It is not critical flashing the led so don't get stuck if we
* can't grab the mutex here */ * can't grab the mutex now */
if (mutex_trylock(&bitforce->device_mutex)) if (mutex_trylock(&bitforce->device_mutex))
return; return;
BFwrite(fdDev, "ZMX", 3); if ((err = usb_write(bitforce, BITFORCE_FLASH, BITFORCE_FLASH_LEN, &amount, C_REQUESTFLASH)) < 0 || amount != BITFORCE_FLASH_LEN) {
applog(LOG_ERR, "%s%i: flash request failed (%d:%d)",
bitforce->drv->name, bitforce->device_id, amount, err);
} else {
/* However, this stops anything else getting a reply
* So best to delay any other access to the BFL */
nmsleep(4000);
}
/* Once we've tried - don't do it until told to again */ /* Once we've tried - don't do it until told to again */
bitforce->flash_led = false; bitforce->flash_led = false;
/* However, this stops anything else getting a reply
* So best to delay any other access to the BFL */
sleep(4);
mutex_unlock(&bitforce->device_mutex); mutex_unlock(&bitforce->device_mutex);
return; // nothing is returned by the BFL return; // nothing is returned by the BFL
@ -373,11 +359,12 @@ 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) // Device is gone
if (bitforce->usbinfo.nodev)
return false; 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
@ -396,18 +383,30 @@ static bool bitforce_get_temp(struct cgpu_info *bitforce)
if (mutex_trylock(&bitforce->device_mutex)) if (mutex_trylock(&bitforce->device_mutex))
return false; return false;
BFwrite(fdDev, "ZLX", 3); if ((err = usb_write(bitforce, BITFORCE_TEMPERATURE, BITFORCE_TEMPERATURE_LEN, &amount, C_REQUESTTEMPERATURE)) < 0 || amount != BITFORCE_TEMPERATURE_LEN) {
pdevbuf[0] = '\0'; mutex_unlock(&bitforce->device_mutex);
BFgets(pdevbuf, sizeof(pdevbuf), fdDev); applog(LOG_ERR, "%s%i: Error: Request temp invalid/timed out (%d:%d)",
mutex_unlock(&bitforce->device_mutex); bitforce->drv->name, bitforce->device_id, amount, err);
if (unlikely(!pdevbuf[0])) {
applog(LOG_ERR, "BFL%i: Error: Get temp returned empty string/timed out", bitforce->device_id);
bitforce->hw_errors++; bitforce->hw_errors++;
return false; return false;
} }
if ((!strncasecmp(pdevbuf, "TEMP", 4)) && (s = strchr(pdevbuf + 4, ':'))) { if ((err = usb_ftdi_read_nl(bitforce, buf, sizeof(buf)-1, &amount, C_GETTEMPERATURE)) < 0 || amount < 1) {
mutex_unlock(&bitforce->device_mutex);
if (err < 0) {
applog(LOG_ERR, "%s%i: Error: Get temp return invalid/timed out (%d:%d)",
bitforce->drv->name, bitforce->device_id, amount, err);
} else {
applog(LOG_ERR, "%s%i: Error: Get temp returned nothing (%d:%d)",
bitforce->drv->name, bitforce->device_id, amount, err);
}
bitforce->hw_errors++;
return false;
}
mutex_unlock(&bitforce->device_mutex);
if ((!strncasecmp(buf, "TEMP", 4)) && (s = strchr(buf + 4, ':'))) {
float temp = strtof(s + 1, NULL); float temp = strtof(s + 1, NULL);
/* Cope with older software that breaks and reads nonsense /* Cope with older software that breaks and reads nonsense
@ -418,7 +417,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->drv->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 +427,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->drv->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 +442,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->drv->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->drv->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->drv->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->drv->name, bitforce->device_id, buf);
return false; return false;
} }
@ -479,7 +498,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 +510,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->drv->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->drv->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->drv->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->drv->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->drv->name, bitforce->device_id, buf);
return false; return false;
} }
@ -521,53 +555,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->drv->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->drv->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, BITFORCE_EITHER, BITFORCE_EITHER_LEN)) {
/* 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 +617,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->drv->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->drv->name, bitforce->device_id,
bitforce->wait_ms, buf);
if (!strncasecmp(buf, BITFORCE_NO_NONCE, BITFORCE_NO_NONCE_MATCH))
return bitforce->nonces; /* No valid nonce found */ return bitforce->nonces; /* No valid nonce found */
else if (!strncasecmp(pdevbuf, "I", 1)) else if (!strncasecmp(buf, BITFORCE_IDLE, BITFORCE_IDLE_MATCH))
return 0; /* Device idle */ return 0; /* Device idle */
else if (strncasecmp(pdevbuf, "NONCE-FOUND", 11)) { else if (strncasecmp(buf, BITFORCE_NONCE, BITFORCE_NONCE_LEN)) {
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->drv->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 +650,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->drv->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 +667,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)
@ -649,6 +685,10 @@ static int64_t bitforce_scanhash(struct thr_info *thr, struct work *work, int64_
bool send_ret; bool send_ret;
int64_t ret; int64_t ret;
// Device is gone
if (bitforce->usbinfo.nodev)
return -1;
send_ret = bitforce_send_work(thr, work); send_ret = bitforce_send_work(thr, work);
if (!restart_wait(bitforce->sleep_ms)) if (!restart_wait(bitforce->sleep_ms))
@ -665,11 +705,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->drv->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 +732,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->drv->name, bitforce->device_id, wait / 1000);
nmsleep(wait); nmsleep(wait);
return true; return true;
@ -712,12 +753,12 @@ static struct api_data *bitforce_api_stats(struct cgpu_info *cgpu)
return root; return root;
} }
struct device_api bitforce_api = { struct device_drv bitforce_drv = {
.dname = "bitforce", .drv_id = DRIVER_BITFORCE,
.dname = "BitForce",
.name = "BFL", .name = "BFL",
.api_detect = bitforce_detect, .drv_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,

9
driver-cpu.c

@ -758,7 +758,7 @@ static void cpu_detect()
struct cgpu_info *cgpu; struct cgpu_info *cgpu;
cgpu = &cpus[i]; cgpu = &cpus[i];
cgpu->api = &cpu_api; cgpu->drv = &cpu_drv;
cgpu->deven = DEV_ENABLED; cgpu->deven = DEV_ENABLED;
cgpu->threads = 1; cgpu->threads = 1;
cgpu->kname = algo_names[opt_algo]; cgpu->kname = algo_names[opt_algo];
@ -768,7 +768,7 @@ static void cpu_detect()
static void reinit_cpu_device(struct cgpu_info *cpu) static void reinit_cpu_device(struct cgpu_info *cpu)
{ {
tq_push(thr_info[cpur_thr_id].q, cpu); tq_push(control_thr[cpur_thr_id].q, cpu);
} }
static bool cpu_thread_prepare(struct thr_info *thr) static bool cpu_thread_prepare(struct thr_info *thr)
@ -843,10 +843,11 @@ CPUSearch:
return last_nonce - first_nonce + 1; return last_nonce - first_nonce + 1;
} }
struct device_api cpu_api = { struct device_drv cpu_drv = {
.drv_id = DRIVER_CPU,
.dname = "cpu", .dname = "cpu",
.name = "CPU", .name = "CPU",
.api_detect = cpu_detect, .drv_detect = cpu_detect,
.reinit_device = reinit_cpu_device, .reinit_device = reinit_cpu_device,
.thread_prepare = cpu_thread_prepare, .thread_prepare = cpu_thread_prepare,
.can_limit_work = cpu_can_limit_work, .can_limit_work = cpu_can_limit_work,

2
driver-cpu.h

@ -53,7 +53,7 @@ enum sha256_algos {
extern const char *algo_names[]; extern const char *algo_names[];
extern bool opt_usecpu; extern bool opt_usecpu;
extern struct device_api cpu_api; extern struct device_drv cpu_drv;
extern char *set_algo(const char *arg, enum sha256_algos *algo); extern char *set_algo(const char *arg, enum sha256_algos *algo);
extern void show_algo(char buf[OPT_SHOW_LEN], const enum sha256_algos *algo); extern void show_algo(char buf[OPT_SHOW_LEN], const enum sha256_algos *algo);

19
driver-icarus.c

@ -208,7 +208,7 @@ static struct ICARUS_INFO **icarus_info;
// //
static int option_offset = -1; static int option_offset = -1;
struct device_api icarus_api; struct device_drv icarus_drv;
static void rev(unsigned char *s, size_t l) static void rev(unsigned char *s, size_t l)
{ {
@ -571,7 +571,7 @@ static bool icarus_detect_one(const char *devpath)
/* We have a real Icarus! */ /* We have a real Icarus! */
struct cgpu_info *icarus; struct cgpu_info *icarus;
icarus = calloc(1, sizeof(struct cgpu_info)); icarus = calloc(1, sizeof(struct cgpu_info));
icarus->api = &icarus_api; icarus->drv = &icarus_drv;
icarus->device_path = strdup(devpath); icarus->device_path = strdup(devpath);
icarus->device_fd = -1; icarus->device_fd = -1;
icarus->threads = 1; icarus->threads = 1;
@ -609,7 +609,7 @@ static bool icarus_detect_one(const char *devpath)
static void icarus_detect() static void icarus_detect()
{ {
serial_detect(&icarus_api, icarus_detect_one); serial_detect(&icarus_drv, icarus_detect_one);
} }
static bool icarus_prepare(struct thr_info *thr) static bool icarus_prepare(struct thr_info *thr)
@ -668,7 +668,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
icarus = thr->cgpu; icarus = thr->cgpu;
if (icarus->device_fd == -1) if (icarus->device_fd == -1)
if (!icarus_prepare(thr)) { if (!icarus_prepare(thr)) {
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); applog(LOG_ERR, "%s%i: Comms error", icarus->drv->name, icarus->device_id);
dev_error(icarus, REASON_DEV_COMMS_ERROR); dev_error(icarus, REASON_DEV_COMMS_ERROR);
// fail the device if the reopen attempt fails // fail the device if the reopen attempt fails
@ -688,7 +688,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
ret = icarus_write(fd, ob_bin, sizeof(ob_bin)); ret = icarus_write(fd, ob_bin, sizeof(ob_bin));
if (ret) { if (ret) {
do_icarus_close(thr); do_icarus_close(thr);
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); applog(LOG_ERR, "%s%i: Comms error", icarus->drv->name, icarus->device_id);
dev_error(icarus, REASON_DEV_COMMS_ERROR); dev_error(icarus, REASON_DEV_COMMS_ERROR);
return 0; /* This should never happen */ return 0; /* This should never happen */
} }
@ -708,7 +708,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
ret = icarus_gets(nonce_bin, fd, &tv_finish, thr, info->read_count); ret = icarus_gets(nonce_bin, fd, &tv_finish, thr, info->read_count);
if (ret == ICA_GETS_ERROR) { if (ret == ICA_GETS_ERROR) {
do_icarus_close(thr); do_icarus_close(thr);
applog(LOG_ERR, "ICA%i: Comms error", icarus->device_id); applog(LOG_ERR, "%s%i: Comms error", icarus->drv->name, icarus->device_id);
dev_error(icarus, REASON_DEV_COMMS_ERROR); dev_error(icarus, REASON_DEV_COMMS_ERROR);
return 0; return 0;
} }
@ -900,10 +900,11 @@ static void icarus_shutdown(struct thr_info *thr)
do_icarus_close(thr); do_icarus_close(thr);
} }
struct device_api icarus_api = { struct device_drv icarus_drv = {
.dname = "icarus", .drv_id = DRIVER_ICARUS,
.dname = "Icarus",
.name = "ICA", .name = "ICA",
.api_detect = icarus_detect, .drv_detect = icarus_detect,
.get_api_stats = icarus_api_stats, .get_api_stats = icarus_api_stats,
.thread_prepare = icarus_prepare, .thread_prepare = icarus_prepare,
.scanhash = icarus_scanhash, .scanhash = icarus_scanhash,

260
driver-modminer.c

@ -1,5 +1,5 @@
/* /*
* Copyright 2012 Andrew Smith * Copyright 2012-2013 Andrew Smith
* Copyright 2012 Luke Dashjr * Copyright 2012 Luke Dashjr
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@ -87,7 +87,7 @@
// Limit when reducing shares_to_good // Limit when reducing shares_to_good
#define MODMINER_MIN_BACK 12 #define MODMINER_MIN_BACK 12
struct device_api modminer_api; 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";
@ -100,15 +100,15 @@ static void do_ping(struct cgpu_info *modminer)
// Don't care if it fails // Don't care if it fails
err = usb_write(modminer, (char *)NOOP, sizeof(NOOP)-1, &amount, C_PING); err = usb_write(modminer, (char *)NOOP, sizeof(NOOP)-1, &amount, C_PING);
applog(LOG_DEBUG, "%s%u: flush noop got %d err %d", applog(LOG_DEBUG, "%s%u: flush noop got %d err %d",
modminer->api->name, modminer->fpgaid, amount, err); modminer->drv->name, modminer->fpgaid, amount, err);
// Clear any outstanding data // Clear any outstanding data
while ((err = usb_read(modminer, buf, sizeof(buf)-1, &amount, C_CLEAR)) == 0 && amount > 0) while ((err = usb_read(modminer, buf, sizeof(buf)-1, &amount, C_CLEAR)) == 0 && amount > 0)
applog(LOG_DEBUG, "%s%u: clear got %d", applog(LOG_DEBUG, "%s%u: clear got %d",
modminer->api->name, modminer->fpgaid, amount); modminer->drv->name, modminer->fpgaid, amount);
applog(LOG_DEBUG, "%s%u: final clear got %d err %d", applog(LOG_DEBUG, "%s%u: final clear got %d err %d",
modminer->api->name, modminer->fpgaid, amount, err); modminer->drv->name, modminer->fpgaid, amount, err);
} }
static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devices *found) static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
@ -121,42 +121,57 @@ static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devic
struct cgpu_info *modminer = NULL; struct cgpu_info *modminer = NULL;
modminer = calloc(1, sizeof(*modminer)); modminer = calloc(1, sizeof(*modminer));
modminer->api = &modminer_api; modminer->drv = &modminer_drv;
modminer->modminer_mutex = calloc(1, sizeof(*(modminer->modminer_mutex))); modminer->modminer_mutex = calloc(1, sizeof(*(modminer->modminer_mutex)));
mutex_init(modminer->modminer_mutex); mutex_init(modminer->modminer_mutex);
modminer->fpgaid = (char)0; modminer->fpgaid = (char)0;
if (!usb_init(modminer, dev, found)) if (!usb_init(modminer, dev, found)) {
applog(LOG_ERR, "%s detect (%d:%d) failed to initialise (incorrect device?)",
modminer->drv->dname,
(int)(modminer->usbinfo.bus_number),
(int)(modminer->usbinfo.device_address));
goto shin; goto shin;
}
sprintf(devpath, "%d:%d",
(int)(modminer->usbinfo.bus_number),
(int)(modminer->usbinfo.device_address));
do_ping(modminer); do_ping(modminer);
if ((err = usb_write(modminer, MODMINER_GET_VERSION, 1, &amount, C_REQUESTVERSION)) < 0 || amount != 1) { if ((err = usb_write(modminer, MODMINER_GET_VERSION, 1, &amount, C_REQUESTVERSION)) < 0 || amount != 1) {
applog(LOG_ERR, "ModMiner detect: send version request failed (%d:%d)", amount, err); applog(LOG_ERR, "%s detect (%s) send version request failed (%d:%d)",
modminer->drv->dname, devpath, amount, err);
goto unshin; goto unshin;
} }
if ((err = usb_read(modminer, buf, sizeof(buf)-1, &amount, C_GETVERSION)) < 0 || amount < 1) { if ((err = usb_read(modminer, buf, sizeof(buf)-1, &amount, C_GETVERSION)) < 0 || amount < 1) {
if (err < 0) if (err < 0)
applog(LOG_ERR, "ModMiner detect: no version reply (%d)", err); applog(LOG_ERR, "%s detect (%s) no version reply (%d)",
modminer->drv->dname, devpath, err);
else else
applog(LOG_ERR, "ModMiner detect: empty version reply (%d)", amount); applog(LOG_ERR, "%s detect (%s) empty version reply (%d)",
modminer->drv->dname, devpath, amount);
applog(LOG_DEBUG, "ModMiner detect: check the firmware"); applog(LOG_DEBUG, "%s detect (%s) check the firmware",
modminer->drv->dname, devpath);
goto unshin; goto unshin;
} }
buf[amount] = '\0'; buf[amount] = '\0';
devname = strdup(buf); devname = strdup(buf);
applog(LOG_DEBUG, "ModMiner identified as: %s", devname); applog(LOG_DEBUG, "%s (%s) identified as: %s", modminer->drv->dname, devpath, devname);
if ((err = usb_write(modminer, MODMINER_FPGA_COUNT, 1, &amount, C_REQUESTFPGACOUNT) < 0 || amount != 1)) { if ((err = usb_write(modminer, MODMINER_FPGA_COUNT, 1, &amount, C_REQUESTFPGACOUNT) < 0 || amount != 1)) {
applog(LOG_ERR, "ModMiner detect: FPGA count request failed (%d:%d)", amount, err); applog(LOG_ERR, "%s detect (%s) FPGA count request failed (%d:%d)",
modminer->drv->dname, devpath, amount, err);
goto unshin; goto unshin;
} }
if ((err = usb_read(modminer, buf, 1, &amount, C_GETFPGACOUNT)) < 0 || amount != 1) { if ((err = usb_read(modminer, buf, 1, &amount, C_GETFPGACOUNT)) < 0 || amount != 1) {
applog(LOG_ERR, "ModMiner detect: no FPGA count reply (%d:%d)", amount, err); applog(LOG_ERR, "%s detect (%s) no FPGA count reply (%d:%d)",
modminer->drv->dname, devpath, amount, err);
goto unshin; goto unshin;
} }
@ -164,16 +179,19 @@ static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devic
// can detect with modminer->cgusb->serial ? // can detect with modminer->cgusb->serial ?
if (buf[0] == 0) { if (buf[0] == 0) {
applog(LOG_ERR, "ModMiner detect: zero FPGA count from %s", devname); applog(LOG_ERR, "%s detect (%s) zero FPGA count from %s",
modminer->drv->dname, devpath, devname);
goto unshin; goto unshin;
} }
if (buf[0] < 1 || buf[0] > 4) { if (buf[0] < 1 || buf[0] > 4) {
applog(LOG_ERR, "ModMiner detect: invalid FPGA count (%u) from %s", buf[0], devname); applog(LOG_ERR, "%s detect (%s) invalid FPGA count (%u) from %s",
modminer->drv->dname, devpath, buf[0], devname);
goto unshin; goto unshin;
} }
applog(LOG_DEBUG, "ModMiner %s has %u FPGAs", devname, buf[0]); applog(LOG_DEBUG, "%s (%s) %s has %u FPGAs",
modminer->drv->dname, devpath, devname, buf[0]);
modminer->name = devname; modminer->name = devname;
@ -182,19 +200,21 @@ static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devic
for (i = 0; i < buf[0]; i++) { for (i = 0; i < buf[0]; i++) {
struct cgpu_info *tmp = calloc(1, sizeof(*tmp)); struct cgpu_info *tmp = calloc(1, sizeof(*tmp));
tmp->api = modminer->api; tmp->drv = copy_drv(modminer->drv);
tmp->name = devname; tmp->name = devname;
sprintf(devpath, "%d:%d:%d", sprintf(devpath, "%d:%d:%d",
(int)(modminer->usbdev->bus_number), (int)(modminer->usbinfo.bus_number),
(int)(modminer->usbdev->device_address), (int)(modminer->usbinfo.device_address),
i); i);
tmp->device_path = strdup(devpath); tmp->device_path = strdup(devpath);
tmp->usbdev = modminer->usbdev; tmp->usbdev = modminer->usbdev;
tmp->usbinfo.bus_number = modminer->usbinfo.bus_number;
tmp->usbinfo.device_address = modminer->usbinfo.device_address;
// Only the first copy gets the already used stats // Only the first copy gets the already used stats
if (!added) if (!added)
tmp->usbstat = modminer->usbstat; tmp->usbinfo.usbstat = modminer->usbinfo.usbstat;
tmp->fpgaid = (char)i; tmp->fpgaid = (char)i;
tmp->modminer_mutex = modminer->modminer_mutex; tmp->modminer_mutex = modminer->modminer_mutex;
tmp->deven = DEV_ENABLED; tmp->deven = DEV_ENABLED;
@ -202,6 +222,8 @@ static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devic
if (!add_cgpu(tmp)) { if (!add_cgpu(tmp)) {
free(tmp->device_path); free(tmp->device_path);
if (tmp->drv->copy)
free(tmp->drv);
free(tmp); free(tmp);
goto unshin; goto unshin;
} }
@ -211,6 +233,9 @@ static bool modminer_detect_one(struct libusb_device *dev, struct usb_find_devic
added = true; added = true;
} }
if (modminer->drv->copy)
free(modminer->drv);
free(modminer); free(modminer);
return true; return true;
@ -223,6 +248,9 @@ shin:
if (!added) if (!added)
free(modminer->modminer_mutex); free(modminer->modminer_mutex);
if (modminer->drv->copy)
free(modminer->drv);
free(modminer); free(modminer);
if (added) if (added)
@ -233,7 +261,7 @@ shin:
static void modminer_detect() static void modminer_detect()
{ {
usb_detect(&modminer_api, modminer_detect_one); usb_detect(&modminer_drv, modminer_detect_one);
} }
static bool get_expect(struct cgpu_info *modminer, FILE *f, char c) static bool get_expect(struct cgpu_info *modminer, FILE *f, char c)
@ -242,13 +270,13 @@ static bool get_expect(struct cgpu_info *modminer, FILE *f, char c)
if (fread(&buf, 1, 1, f) != 1) { if (fread(&buf, 1, 1, f) != 1) {
applog(LOG_ERR, "%s%u: Error (%d) reading bitstream (%c)", applog(LOG_ERR, "%s%u: Error (%d) reading bitstream (%c)",
modminer->api->name, modminer->device_id, errno, c); modminer->drv->name, modminer->device_id, errno, c);
return false; return false;
} }
if (buf != c) { if (buf != c) {
applog(LOG_ERR, "%s%u: firmware code mismatch (%c)", applog(LOG_ERR, "%s%u: bitstream code mismatch (%c)",
modminer->api->name, modminer->device_id, c); modminer->drv->name, modminer->device_id, c);
return false; return false;
} }
@ -262,7 +290,7 @@ static bool get_info(struct cgpu_info *modminer, FILE *f, char *buf, int bufsiz,
if (fread(siz, 2, 1, f) != 1) { if (fread(siz, 2, 1, f) != 1) {
applog(LOG_ERR, "%s%u: Error (%d) reading bitstream '%s' len", applog(LOG_ERR, "%s%u: Error (%d) reading bitstream '%s' len",
modminer->api->name, modminer->device_id, errno, name); modminer->drv->name, modminer->device_id, errno, name);
return false; return false;
} }
@ -270,13 +298,13 @@ static bool get_info(struct cgpu_info *modminer, FILE *f, char *buf, int bufsiz,
if (len >= bufsiz) { if (len >= bufsiz) {
applog(LOG_ERR, "%s%u: Bitstream '%s' len too large (%d)", applog(LOG_ERR, "%s%u: Bitstream '%s' len too large (%d)",
modminer->api->name, modminer->device_id, name, len); modminer->drv->name, modminer->device_id, name, len);
return false; return false;
} }
if (fread(buf, len, 1, f) != 1) { if (fread(buf, len, 1, f) != 1) {
applog(LOG_ERR, "%s%u: Error (%d) reading bitstream '%s'", errno, applog(LOG_ERR, "%s%u: Error (%d) reading bitstream '%s'", errno,
modminer->api->name, modminer->device_id, errno, name); modminer->drv->name, modminer->device_id, errno, name);
return false; return false;
} }
@ -302,7 +330,7 @@ static bool get_status_timeout(struct cgpu_info *modminer, char *msg, unsigned i
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error (%d:%d) getting %s reply", applog(LOG_ERR, "%s%u: Error (%d:%d) getting %s reply",
modminer->api->name, modminer->device_id, amount, err, msg); modminer->drv->name, modminer->device_id, amount, err, msg);
return false; return false;
} }
@ -311,7 +339,7 @@ static bool get_status_timeout(struct cgpu_info *modminer, char *msg, unsigned i
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error, invalid %s reply (was %d should be 1)", applog(LOG_ERR, "%s%u: Error, invalid %s reply (was %d should be 1)",
modminer->api->name, modminer->device_id, msg, buf[0]); modminer->drv->name, modminer->device_id, msg, buf[0]);
return false; return false;
} }
@ -343,7 +371,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error (%d) opening bitstream file %s", applog(LOG_ERR, "%s%u: Error (%d) opening bitstream file %s",
modminer->api->name, modminer->device_id, errno, bsfile); modminer->drv->name, modminer->device_id, errno, bsfile);
return false; return false;
} }
@ -352,7 +380,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error (%d) reading bitstream magic", applog(LOG_ERR, "%s%u: Error (%d) reading bitstream magic",
modminer->api->name, modminer->device_id, errno); modminer->drv->name, modminer->device_id, errno);
goto dame; goto dame;
} }
@ -361,7 +389,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: bitstream has incorrect magic (%u,%u) instead of (%u,%u)", applog(LOG_ERR, "%s%u: bitstream has incorrect magic (%u,%u) instead of (%u,%u)",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
buf[0], buf[1], buf[0], buf[1],
BITSTREAM_MAGIC_0, BITSTREAM_MAGIC_1); BITSTREAM_MAGIC_0, BITSTREAM_MAGIC_1);
@ -372,7 +400,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error (%d) bitstream seek failed", applog(LOG_ERR, "%s%u: Error (%d) bitstream seek failed",
modminer->api->name, modminer->device_id, errno); modminer->drv->name, modminer->device_id, errno);
goto dame; goto dame;
} }
@ -384,7 +412,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
goto undame; goto undame;
applog(LOG_DEBUG, "%s%u: bitstream file '%s' info:", applog(LOG_DEBUG, "%s%u: bitstream file '%s' info:",
modminer->api->name, modminer->device_id, bsfile); modminer->drv->name, modminer->device_id, bsfile);
applog(LOG_DEBUG, " Design name: '%s'", buf); applog(LOG_DEBUG, " Design name: '%s'", buf);
@ -399,7 +427,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Bad usercode in bitstream file", applog(LOG_ERR, "%s%u: Bad usercode in bitstream file",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
goto dame; goto dame;
} }
@ -408,7 +436,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: bitstream doesn't support user code", applog(LOG_ERR, "%s%u: bitstream doesn't support user code",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
goto dame; goto dame;
} }
@ -446,7 +474,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error (%d) reading bitstream data len", applog(LOG_ERR, "%s%u: Error (%d) reading bitstream data len",
modminer->api->name, modminer->device_id, errno); modminer->drv->name, modminer->device_id, errno);
goto dame; goto dame;
} }
@ -460,7 +488,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
*ptr = '\0'; *ptr = '\0';
applog(LOG_WARNING, "%s%u: Programming all FPGA on %s ... Mining will not start until complete", applog(LOG_WARNING, "%s%u: Programming all FPGA on %s ... Mining will not start until complete",
modminer->api->name, modminer->device_id, devmsg); modminer->drv->name, modminer->device_id, devmsg);
buf[0] = MODMINER_PROGRAM; buf[0] = MODMINER_PROGRAM;
buf[1] = fpgaid; buf[1] = fpgaid;
@ -473,7 +501,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Program init failed (%d:%d)", applog(LOG_ERR, "%s%u: Program init failed (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
goto dame; goto dame;
} }
@ -492,7 +520,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: bitstream file read error %d (%d bytes left)", applog(LOG_ERR, "%s%u: bitstream file read error %d (%d bytes left)",
modminer->api->name, modminer->device_id, errno, len); modminer->drv->name, modminer->device_id, errno, len);
goto dame; goto dame;
} }
@ -507,7 +535,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
if (opt_debug) if (opt_debug)
applog(LOG_DEBUG, "%s%u: Program timeout (%d:%d) sent %d tries %d", applog(LOG_DEBUG, "%s%u: Program timeout (%d:%d) sent %d tries %d",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
amount, err, remaining, tries); amount, err, remaining, tries);
if (!get_status(modminer, "write status", C_PROGRAMSTATUS2)) if (!get_status(modminer, "write status", C_PROGRAMSTATUS2))
@ -517,7 +545,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Program failed (%d:%d) sent %d", applog(LOG_ERR, "%s%u: Program failed (%d:%d) sent %d",
modminer->api->name, modminer->device_id, amount, err, remaining); modminer->drv->name, modminer->device_id, amount, err, remaining);
goto dame; goto dame;
} }
@ -532,7 +560,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
if (upto >= nextmsg) { if (upto >= nextmsg) {
applog(LOG_WARNING, applog(LOG_WARNING,
"%s%u: Programming %.1f%% (%d out of %d)", "%s%u: Programming %.1f%% (%d out of %d)",
modminer->api->name, modminer->device_id, upto*100, (totlen - len), totlen); modminer->drv->name, modminer->device_id, upto*100, (totlen - len), totlen);
nextmsg += 0.1; nextmsg += 0.1;
} }
@ -542,7 +570,7 @@ static bool modminer_fpga_upload_bitstream(struct cgpu_info *modminer)
goto undame; goto undame;
applog(LOG_WARNING, "%s%u: Programming completed for all FPGA on %s", applog(LOG_WARNING, "%s%u: Programming completed for all FPGA on %s",
modminer->api->name, modminer->device_id, devmsg); modminer->drv->name, modminer->device_id, devmsg);
// Give it a 2/3s delay after programming // Give it a 2/3s delay after programming
nmsleep(666); nmsleep(666);
@ -567,8 +595,6 @@ static bool modminer_fpga_prepare(struct thr_info *thr)
struct modminer_fpga_state *state; struct modminer_fpga_state *state;
state = thr->cgpu_data = calloc(1, sizeof(struct modminer_fpga_state)); state = thr->cgpu_data = calloc(1, sizeof(struct modminer_fpga_state));
state->next_work_cmd[0] = MODMINER_SEND_WORK;
state->next_work_cmd[1] = modminer->fpgaid;
state->shares_to_good = MODMINER_EARLY_UP; state->shares_to_good = MODMINER_EARLY_UP;
state->overheated = false; state->overheated = false;
@ -599,6 +625,7 @@ static bool modminer_fpga_prepare(struct thr_info *thr)
* *
* N.B. clock must always be a multiple of 2 * N.B. clock must always be a multiple of 2
*/ */
static const char *clocknodev = "clock failed - no device";
static const char *clockoldwork = "clock already changed for this work"; static const char *clockoldwork = "clock already changed for this work";
static const char *clocktoolow = "clock too low"; static const char *clocktoolow = "clock too low";
static const char *clocktoohi = "clock too high"; static const char *clocktoohi = "clock too high";
@ -612,6 +639,10 @@ static const char *modminer_delta_clock(struct thr_info *thr, int delta, bool te
unsigned char cmd[6], buf[1]; unsigned char cmd[6], buf[1];
int err, amount; int err, amount;
// Device is gone
if (modminer->usbinfo.nodev)
return clocknodev;
// Only do once if multiple shares per work or multiple reasons // Only do once if multiple shares per work or multiple reasons
if (!state->new_work && !force) if (!state->new_work && !force)
return clockoldwork; return clockoldwork;
@ -653,7 +684,7 @@ static const char *modminer_delta_clock(struct thr_info *thr, int delta, bool te
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error writing set clock speed (%d:%d)", applog(LOG_ERR, "%s%u: Error writing set clock speed (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return clocksetfail; return clocksetfail;
} }
@ -662,7 +693,7 @@ static const char *modminer_delta_clock(struct thr_info *thr, int delta, bool te
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error reading set clock speed (%d:%d)", applog(LOG_ERR, "%s%u: Error reading set clock speed (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return clockreplyfail; return clockreplyfail;
} }
@ -670,7 +701,7 @@ static const char *modminer_delta_clock(struct thr_info *thr, int delta, bool te
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_WARNING, "%s%u: Set clock speed %sto %u", applog(LOG_WARNING, "%s%u: Set clock speed %sto %u",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
(delta < 0) ? "down " : (delta > 0 ? "up " : ""), (delta < 0) ? "down " : (delta > 0 ? "up " : ""),
modminer->clock); modminer->clock);
@ -691,7 +722,7 @@ static bool modminer_fpga_init(struct thr_info *thr)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error requesting USER code (%d:%d)", applog(LOG_ERR, "%s%u: Error requesting USER code (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return false; return false;
} }
@ -700,14 +731,14 @@ static bool modminer_fpga_init(struct thr_info *thr)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Error reading USER code (%d:%d)", applog(LOG_ERR, "%s%u: Error reading USER code (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return false; return false;
} }
if (memcmp(buf, BISTREAM_USER_ID, 4)) { if (memcmp(buf, BISTREAM_USER_ID, 4)) {
applog(LOG_ERR, "%s%u: FPGA not programmed", applog(LOG_ERR, "%s%u: FPGA not programmed",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
if (!modminer_fpga_upload_bitstream(modminer)) if (!modminer_fpga_upload_bitstream(modminer))
return false; return false;
@ -717,7 +748,7 @@ static bool modminer_fpga_init(struct thr_info *thr)
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_DEBUG, "%s%u: FPGA is already programmed :)", applog(LOG_DEBUG, "%s%u: FPGA is already programmed :)",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
} }
modminer->clock = MODMINER_DEF_CLOCK; modminer->clock = MODMINER_DEF_CLOCK;
@ -740,24 +771,19 @@ static void get_modminer_statline_before(char *buf, struct cgpu_info *modminer)
strcat(buf, info); strcat(buf, info);
} }
static bool modminer_prepare_next_work(struct modminer_fpga_state *state, struct work *work) static bool modminer_start_work(struct thr_info *thr, struct work *work)
{
char *midstate = state->next_work_cmd + 2;
char *taildata = midstate + 32;
if (!(memcmp(midstate, work->midstate, 32) || memcmp(taildata, work->data + 64, 12)))
return false;
memcpy(midstate, work->midstate, 32);
memcpy(taildata, work->data + 64, 12);
return true;
}
static bool modminer_start_work(struct thr_info *thr)
{ {
struct cgpu_info *modminer = thr->cgpu; struct cgpu_info *modminer = thr->cgpu;
struct modminer_fpga_state *state = thr->cgpu_data; struct modminer_fpga_state *state = thr->cgpu_data;
int err, amount; int err, amount;
char cmd[48];
bool sta; bool sta;
cmd[0] = MODMINER_SEND_WORK;
cmd[1] = modminer->fpgaid;
memcpy(&cmd[2], work->midstate, 32);
memcpy(&cmd[34], work->data + 64, 12);
if (state->first_work.tv_sec == 0) if (state->first_work.tv_sec == 0)
gettimeofday(&state->first_work, NULL); gettimeofday(&state->first_work, NULL);
@ -766,20 +792,16 @@ static bool modminer_start_work(struct thr_info *thr)
mutex_lock(modminer->modminer_mutex); mutex_lock(modminer->modminer_mutex);
if ((err = usb_write(modminer, (char *)(state->next_work_cmd), 46, &amount, C_SENDWORK)) < 0 || amount != 46) { if ((err = usb_write(modminer, cmd, 46, &amount, C_SENDWORK)) < 0 || amount != 46) {
// TODO: err = LIBUSB_ERROR_NO_DEVICE means the MMQ disappeared
// - need to delete it and rescan for it? (after a delay?)
// but check all (4) disappeared
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
applog(LOG_ERR, "%s%u: Start work failed (%d:%d)", applog(LOG_ERR, "%s%u: Start work failed (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return false; return false;
} }
gettimeofday(&state->tv_workstart, NULL); gettimeofday(&state->tv_workstart, NULL);
state->hashes = 0;
sta = get_status(modminer, "start work", C_SENDWORKSTATUS); sta = get_status(modminer, "start work", C_SENDWORKSTATUS);
@ -799,6 +821,10 @@ static void check_temperature(struct thr_info *thr)
int tbytes, tamount; int tbytes, tamount;
int amount; int amount;
// Device is gone
if (modminer->usbinfo.nodev)
return;
if (state->one_byte_temp) { if (state->one_byte_temp) {
cmd[0] = MODMINER_TEMP1; cmd[0] = MODMINER_TEMP1;
tbytes = 1; tbytes = 1;
@ -827,14 +853,14 @@ static void check_temperature(struct thr_info *thr)
if (modminer->temp < MODMINER_RECOVER_TEMP) { if (modminer->temp < MODMINER_RECOVER_TEMP) {
state->overheated = false; state->overheated = false;
applog(LOG_WARNING, "%s%u: Recovered, temp less than (%.1f) now %.3f", applog(LOG_WARNING, "%s%u: Recovered, temp less than (%.1f) now %.3f",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
MODMINER_RECOVER_TEMP, modminer->temp); MODMINER_RECOVER_TEMP, modminer->temp);
} }
} }
else if (modminer->temp >= MODMINER_OVERHEAT_TEMP) { else if (modminer->temp >= MODMINER_OVERHEAT_TEMP) {
if (modminer->temp >= MODMINER_CUTOFF_TEMP) { if (modminer->temp >= MODMINER_CUTOFF_TEMP) {
applog(LOG_WARNING, "%s%u: Hit thermal cutoff limit! (%.1f) at %.3f", applog(LOG_WARNING, "%s%u: Hit thermal cutoff limit! (%.1f) at %.3f",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
MODMINER_CUTOFF_TEMP, modminer->temp); MODMINER_CUTOFF_TEMP, modminer->temp);
modminer_delta_clock(thr, MODMINER_CLOCK_CUTOFF, true, false); modminer_delta_clock(thr, MODMINER_CLOCK_CUTOFF, true, false);
@ -842,7 +868,7 @@ static void check_temperature(struct thr_info *thr)
dev_error(modminer, REASON_DEV_THERMAL_CUTOFF); dev_error(modminer, REASON_DEV_THERMAL_CUTOFF);
} else { } else {
applog(LOG_WARNING, "%s%u: Overheat limit (%.1f) reached %.3f", applog(LOG_WARNING, "%s%u: Overheat limit (%.1f) reached %.3f",
modminer->api->name, modminer->device_id, modminer->drv->name, modminer->device_id,
MODMINER_OVERHEAT_TEMP, modminer->temp); MODMINER_OVERHEAT_TEMP, modminer->temp);
// If it's defined to be 0 then don't call modminer_delta_clock() // If it's defined to be 0 then don't call modminer_delta_clock()
@ -869,11 +895,10 @@ static const double processtime = 17.0;
// 160Mhz is 26.84 - when overheated ensure we don't throw away shares // 160Mhz is 26.84 - when overheated ensure we don't throw away shares
static const double overheattime = 26.9; static const double overheattime = 26.9;
static uint64_t modminer_process_results(struct thr_info *thr) static uint64_t modminer_process_results(struct thr_info *thr, struct work *work)
{ {
struct cgpu_info *modminer = thr->cgpu; struct cgpu_info *modminer = thr->cgpu;
struct modminer_fpga_state *state = thr->cgpu_data; struct modminer_fpga_state *state = thr->cgpu_data;
struct work *work = &state->running_work;
struct timeval now; struct timeval now;
char cmd[2]; char cmd[2];
uint32_t nonce; uint32_t nonce;
@ -883,6 +908,10 @@ static uint64_t modminer_process_results(struct thr_info *thr)
double timeout; double timeout;
int temploop; int temploop;
// Device is gone
if (modminer->usbinfo.nodev)
return -1;
// If we are overheated it will just keep checking for results // If we are overheated it will just keep checking for results
// since we can't stop the work // since we can't stop the work
// The next work will not start until the temp drops // The next work will not start until the temp drops
@ -893,23 +922,20 @@ static uint64_t modminer_process_results(struct thr_info *thr)
timeoutloop = 0; timeoutloop = 0;
temploop = 0; temploop = 0;
while (1) { while (0x80085) {
mutex_lock(modminer->modminer_mutex); mutex_lock(modminer->modminer_mutex);
if ((err = usb_write(modminer, cmd, 2, &amount, C_REQUESTWORKSTATUS)) < 0 || amount != 2) { if ((err = usb_write(modminer, cmd, 2, &amount, C_REQUESTWORKSTATUS)) < 0 || amount != 2) {
// TODO: err = LIBUSB_ERROR_NO_DEVICE means the MMQ disappeared
// - need to delete it and rescan for it? (after a delay?)
// but check all (4) disappeared
mutex_unlock(modminer->modminer_mutex); mutex_unlock(modminer->modminer_mutex);
// timeoutloop never resets so the timeouts can't // timeoutloop never resets so the timeouts can't
// accumulate much during a single item of work // accumulate much during a single item of work
if (err == LIBUSB_ERROR_TIMEOUT && ++timeoutloop < 10) { if (err == LIBUSB_ERROR_TIMEOUT && ++timeoutloop < 5) {
state->timeout_fail++; state->timeout_fail++;
goto tryagain; goto tryagain;
} }
applog(LOG_ERR, "%s%u: Error sending (get nonce) (%d:%d)", applog(LOG_ERR, "%s%u: Error sending (get nonce) (%d:%d)",
modminer->api->name, modminer->device_id, amount, err); modminer->drv->name, modminer->device_id, amount, err);
return -1; return -1;
} }
@ -936,7 +962,7 @@ static uint64_t modminer_process_results(struct thr_info *thr)
} }
applog(LOG_ERR, "%s%u: Error reading (get nonce) (%d:%d)", applog(LOG_ERR, "%s%u: Error reading (get nonce) (%d:%d)",
modminer->api->name, modminer->device_id, amount+amount2, err); modminer->drv->name, modminer->device_id, amount+amount2, err);
} }
if (memcmp(&nonce, "\xff\xff\xff\xff", 4)) { if (memcmp(&nonce, "\xff\xff\xff\xff", 4)) {
@ -975,7 +1001,7 @@ static uint64_t modminer_process_results(struct thr_info *thr)
if (state->death_stage_one) { if (state->death_stage_one) {
modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true); modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true);
applog(LOG_ERR, "%s%u: DEATH clock down", applog(LOG_ERR, "%s%u: DEATH clock down",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
// reset the death info and DISABLE it // reset the death info and DISABLE it
state->last_nonce.tv_sec = 0; state->last_nonce.tv_sec = 0;
@ -985,7 +1011,7 @@ static uint64_t modminer_process_results(struct thr_info *thr)
} else { } else {
modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true); modminer_delta_clock(thr, MODMINER_CLOCK_DEAD, false, true);
applog(LOG_ERR, "%s%u: death clock down", applog(LOG_ERR, "%s%u: death clock down",
modminer->api->name, modminer->device_id); modminer->drv->name, modminer->device_id);
state->death_stage_one = true; state->death_stage_one = true;
} }
@ -998,8 +1024,8 @@ tryagain:
break; break;
if (state->overheated == true) { if (state->overheated == true) {
// don't check every time // don't check every time (every ~1/2 sec)
if (++temploop > 30) { if (++temploop > 4) {
check_temperature(thr); check_temperature(thr);
temploop = 0; temploop = 0;
} }
@ -1015,7 +1041,8 @@ tryagain:
if (tdiff(&now, &state->tv_workstart) > timeout) if (tdiff(&now, &state->tv_workstart) > timeout)
break; break;
nmsleep(10); // 1/10th sec to lower CPU usage
nmsleep(100);
if (work_restart(thr)) if (work_restart(thr))
break; break;
} }
@ -1029,35 +1056,37 @@ tryagain:
// Overheat will complete the nonce range // Overheat will complete the nonce range
if (hashes > 0xffffffff) if (hashes > 0xffffffff)
hashes = 0xffffffff; hashes = 0xffffffff;
else
if (hashes <= state->hashes) work->blk.nonce = 0xffffffff;
hashes = 1;
else
hashes -= state->hashes;
state->hashes += hashes;
return hashes; return hashes;
} }
static int64_t modminer_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce) static int64_t modminer_scanhash(struct thr_info *thr, struct work *work, int64_t __maybe_unused max_nonce)
{ {
struct modminer_fpga_state *state = thr->cgpu_data; struct modminer_fpga_state *state = thr->cgpu_data;
int64_t hashes = 0;
bool startwork;
struct timeval tv1, tv2; struct timeval tv1, tv2;
int64_t hashes;
// Device is gone
if (thr->cgpu->usbinfo.nodev)
return -1;
// Don't start new work if overheated // Don't start new work if overheated
if (state->overheated == true) { if (state->overheated == true) {
gettimeofday(&tv1, NULL); gettimeofday(&tv1, NULL);
if (state->work_running)
state->work_running = false;
while (state->overheated == true) { while (state->overheated == true) {
check_temperature(thr); check_temperature(thr);
// Device is gone
if (thr->cgpu->usbinfo.nodev)
return -1;
if (state->overheated == true) { if (state->overheated == true) {
gettimeofday(&tv2, NULL); gettimeofday(&tv2, NULL);
// give up on this work item // give up on this work item after 30s
if (work_restart(thr) || tdiff(&tv2, &tv1) > 30) if (work_restart(thr) || tdiff(&tv2, &tv1) > 30)
return 0; return 0;
@ -1067,27 +1096,13 @@ static int64_t modminer_scanhash(struct thr_info *thr, struct work *work, int64_
} }
} }
startwork = modminer_prepare_next_work(state, work); if (!modminer_start_work(thr, work))
if (state->work_running) { return -1;
hashes = modminer_process_results(thr);
if (hashes == -1)
return hashes;
if (work_restart(thr)) {
state->work_running = false;
return 0;
}
} else
state->work_running = true;
if (startwork) { hashes = modminer_process_results(thr, work);
if (!modminer_start_work(thr)) if (hashes == -1)
return -1; return hashes;
__copy_work(&state->running_work, work);
}
// This is intentionally early
work->blk.nonce += hashes;
return hashes; return hashes;
} }
@ -1141,10 +1156,11 @@ static char *modminer_set_device(struct cgpu_info *modminer, char *option, char
return replybuf; return replybuf;
} }
struct device_api modminer_api = { struct device_drv modminer_drv = {
.dname = "modminer", .drv_id = DRIVER_MODMINER,
.dname = "ModMiner",
.name = "MMQ", .name = "MMQ",
.api_detect = modminer_detect, .drv_detect = modminer_detect,
.get_statline_before = get_modminer_statline_before, .get_statline_before = get_modminer_statline_before,
.set_device = modminer_set_device, .set_device = modminer_set_device,
.thread_prepare = modminer_fpga_prepare, .thread_prepare = modminer_fpga_prepare,

58
driver-opencl.c

@ -50,24 +50,24 @@ extern int gpur_thr_id;
extern bool opt_noadl; extern bool opt_noadl;
extern bool have_opencl; extern bool have_opencl;
extern void *miner_thread(void *userdata); extern void *miner_thread(void *userdata);
extern int dev_from_id(int thr_id); extern int dev_from_id(int thr_id);
extern void tailsprintf(char *f, const char *fmt, ...); extern void tailsprintf(char *f, const char *fmt, ...);
extern void wlog(const char *f, ...); extern void wlog(const char *f, ...);
extern void decay_time(double *f, double fadd); 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);
extern int gpu_fanpercent(int gpu); extern int gpu_fanpercent(int gpu);
#endif #endif
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
char *set_vector(char *arg) char *set_vector(char *arg)
{ {
@ -591,28 +591,20 @@ char *set_intensity(char *arg)
return NULL; return NULL;
} }
#endif
#ifdef HAVE_OPENCL
struct device_api opencl_api;
char *print_ndevs_and_exit(int *ndevs) char *print_ndevs_and_exit(int *ndevs)
{ {
opt_log_output = true; opt_log_output = true;
opencl_api.api_detect(); opencl_drv.drv_detect();
clear_adl(*ndevs); clear_adl(*ndevs);
applog(LOG_INFO, "%i GPU devices max detected", *ndevs); applog(LOG_INFO, "%i GPU devices max detected", *ndevs);
exit(*ndevs); exit(*ndevs);
} }
#endif #endif
struct cgpu_info gpus[MAX_GPUDEVICES]; /* Maximum number apparently possible */ struct cgpu_info gpus[MAX_GPUDEVICES]; /* Maximum number apparently possible */
struct cgpu_info *cpus; struct cgpu_info *cpus;
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
/* In dynamic mode, only the first thread of each device will be in use. /* In dynamic mode, only the first thread of each device will be in use.
@ -624,8 +616,9 @@ void pause_dynamic_threads(int gpu)
int i; int i;
for (i = 1; i < cgpu->threads; i++) { for (i = 1; i < cgpu->threads; i++) {
struct thr_info *thr = &thr_info[i]; struct thr_info *thr;
thr = get_thread(i);
if (!thr->pause && cgpu->dynamic) { if (!thr->pause && cgpu->dynamic) {
applog(LOG_WARNING, "Disabling extra threads due to dynamic mode."); applog(LOG_WARNING, "Disabling extra threads due to dynamic mode.");
applog(LOG_WARNING, "Tune dynamic intensity with --gpu-dyninterval"); applog(LOG_WARNING, "Tune dynamic intensity with --gpu-dyninterval");
@ -637,9 +630,6 @@ void pause_dynamic_threads(int gpu)
} }
} }
struct device_api opencl_api;
#endif /* HAVE_OPENCL */ #endif /* HAVE_OPENCL */
#if defined(HAVE_OPENCL) && defined(HAVE_CURSES) #if defined(HAVE_OPENCL) && defined(HAVE_CURSES)
@ -716,7 +706,7 @@ retry:
else else
wlog("%d\n", gpus[gpu].intensity); wlog("%d\n", gpus[gpu].intensity);
for (i = 0; i < mining_threads; i++) { for (i = 0; i < mining_threads; i++) {
thr = &thr_info[i]; thr = get_thread(i);
if (thr->cgpu != cgpu) if (thr->cgpu != cgpu)
continue; continue;
get_datestamp(checkin, &thr->last); get_datestamp(checkin, &thr->last);
@ -771,9 +761,9 @@ retry:
} }
gpus[selected].deven = DEV_ENABLED; gpus[selected].deven = DEV_ENABLED;
for (i = 0; i < mining_threads; ++i) { for (i = 0; i < mining_threads; ++i) {
thr = &thr_info[i]; thr = get_thread(i);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->api != &opencl_api) if (cgpu->drv->drv_id != DRIVER_OPENCL)
continue; continue;
if (dev_from_id(i) != selected) if (dev_from_id(i) != selected)
continue; continue;
@ -1158,14 +1148,14 @@ select_cgpu:
gpu = cgpu->device_id; gpu = cgpu->device_id;
for (thr_id = 0; thr_id < mining_threads; ++thr_id) { for (thr_id = 0; thr_id < mining_threads; ++thr_id) {
thr = &thr_info[thr_id]; thr = get_thread(thr_id);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->api != &opencl_api) 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;
thr = &thr_info[thr_id]; thr = get_thread(thr_id);
if (!thr) { if (!thr) {
applog(LOG_WARNING, "No reference to thread %d exists", thr_id); applog(LOG_WARNING, "No reference to thread %d exists", thr_id);
continue; continue;
@ -1183,9 +1173,9 @@ select_cgpu:
for (thr_id = 0; thr_id < mining_threads; ++thr_id) { for (thr_id = 0; thr_id < mining_threads; ++thr_id) {
int virtual_gpu; int virtual_gpu;
thr = &thr_info[thr_id]; thr = get_thread(thr_id);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->api != &opencl_api) 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;
@ -1220,9 +1210,9 @@ select_cgpu:
get_datestamp(cgpu->init, &now); get_datestamp(cgpu->init, &now);
for (thr_id = 0; thr_id < mining_threads; ++thr_id) { for (thr_id = 0; thr_id < mining_threads; ++thr_id) {
thr = &thr_info[thr_id]; thr = get_thread(thr_id);
cgpu = thr->cgpu; cgpu = thr->cgpu;
if (cgpu->api != &opencl_api) 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;
@ -1243,8 +1233,6 @@ void *reinit_gpu(__maybe_unused void *userdata)
#ifdef HAVE_OPENCL #ifdef HAVE_OPENCL
struct device_api opencl_api;
static void opencl_detect() static void opencl_detect()
{ {
int i; int i;
@ -1263,7 +1251,7 @@ static void opencl_detect()
cgpu = &gpus[i]; cgpu = &gpus[i];
cgpu->deven = DEV_ENABLED; cgpu->deven = DEV_ENABLED;
cgpu->api = &opencl_api; cgpu->drv = &opencl_drv;
cgpu->device_id = i; cgpu->device_id = i;
cgpu->threads = opt_g_threads; cgpu->threads = opt_g_threads;
cgpu->virtual_gpu = i; cgpu->virtual_gpu = i;
@ -1276,7 +1264,7 @@ static void opencl_detect()
static void reinit_opencl_device(struct cgpu_info *gpu) static void reinit_opencl_device(struct cgpu_info *gpu)
{ {
tq_push(thr_info[gpur_thr_id].q, gpu); tq_push(control_thr[gpur_thr_id].q, gpu);
} }
#ifdef HAVE_ADL #ifdef HAVE_ADL
@ -1299,7 +1287,8 @@ static void get_opencl_statline_before(char *buf, struct cgpu_info *gpu)
else else
tailsprintf(buf, " "); tailsprintf(buf, " ");
tailsprintf(buf, "| "); tailsprintf(buf, "| ");
} } else
gpu->drv->get_statline_before = &blank_get_statline_before;
} }
#endif #endif
@ -1570,10 +1559,11 @@ static void opencl_thread_shutdown(struct thr_info *thr)
clReleaseContext(clState->context); clReleaseContext(clState->context);
} }
struct device_api opencl_api = { struct device_drv opencl_drv = {
.drv_id = DRIVER_OPENCL,
.dname = "opencl", .dname = "opencl",
.name = "GPU", .name = "GPU",
.api_detect = opencl_detect, .drv_detect = opencl_detect,
.reinit_device = reinit_opencl_device, .reinit_device = reinit_opencl_device,
#ifdef HAVE_ADL #ifdef HAVE_ADL
.get_statline_before = get_opencl_statline_before, .get_statline_before = get_opencl_statline_before,

2
driver-opencl.h

@ -30,6 +30,6 @@ extern void pause_dynamic_threads(int gpu);
extern bool have_opencl; extern bool have_opencl;
extern int opt_platform_id; extern int opt_platform_id;
extern struct device_api opencl_api; extern struct device_drv opencl_drv;
#endif /* __DEVICE_GPU_H__ */ #endif /* __DEVICE_GPU_H__ */

15
driver-ztex.c

@ -30,7 +30,7 @@
#define GOLDEN_BACKLOG 5 #define GOLDEN_BACKLOG 5
struct device_api ztex_api; 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);
@ -68,7 +68,7 @@ static void ztex_detect(void)
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
ztex = calloc(1, sizeof(struct cgpu_info)); ztex = calloc(1, sizeof(struct cgpu_info));
ztex->api = &ztex_api; ztex->drv = &ztex_drv;
ztex->device_ztex = ztex_devices[i]->dev; ztex->device_ztex = ztex_devices[i]->dev;
ztex->threads = 1; ztex->threads = 1;
ztex->device_ztex->fpgaNum = 0; ztex->device_ztex->fpgaNum = 0;
@ -82,7 +82,7 @@ static void ztex_detect(void)
for (j = 1; j < fpgacount; j++) { for (j = 1; j < fpgacount; j++) {
ztex = calloc(1, sizeof(struct cgpu_info)); ztex = calloc(1, sizeof(struct cgpu_info));
ztex->api = &ztex_api; ztex->drv = &ztex_drv;
ztex_slave = calloc(1, sizeof(struct libztex_device)); ztex_slave = calloc(1, sizeof(struct libztex_device));
memcpy(ztex_slave, ztex_devices[i]->dev, sizeof(struct libztex_device)); memcpy(ztex_slave, ztex_devices[i]->dev, sizeof(struct libztex_device));
ztex->device_ztex = ztex_slave; ztex->device_ztex = ztex_slave;
@ -389,15 +389,18 @@ static void ztex_shutdown(struct thr_info *thr)
static void ztex_disable(struct thr_info *thr) static void ztex_disable(struct thr_info *thr)
{ {
struct cgpu_info *cgpu;
applog(LOG_ERR, "%s: Disabling!", thr->cgpu->device_ztex->repr); applog(LOG_ERR, "%s: Disabling!", thr->cgpu->device_ztex->repr);
devices[thr->cgpu->device_id]->deven = DEV_DISABLED; cgpu = get_devices(thr->cgpu->device_id);
cgpu->deven = DEV_DISABLED;
ztex_shutdown(thr); ztex_shutdown(thr);
} }
struct device_api ztex_api = { struct device_drv ztex_drv = {
.dname = "ztex", .dname = "ztex",
.name = "ZTX", .name = "ZTX",
.api_detect = ztex_detect, .drv_detect = ztex_detect,
.get_statline_before = ztex_statline_before, .get_statline_before = ztex_statline_before,
.thread_prepare = ztex_prepare, .thread_prepare = ztex_prepare,
.scanhash = ztex_scanhash, .scanhash = ztex_scanhash,

2
findnonce.c

@ -204,7 +204,7 @@ static void *postcalc_hash(void *userdata)
* end of the res[] array */ * end of the res[] array */
if (unlikely(pcd->res[FOUND] & ~FOUND)) { if (unlikely(pcd->res[FOUND] & ~FOUND)) {
applog(LOG_WARNING, "%s%d: invalid nonce count - HW error", applog(LOG_WARNING, "%s%d: invalid nonce count - HW error",
thr->cgpu->api->name, thr->cgpu->device_id); thr->cgpu->drv->name, thr->cgpu->device_id);
hw_errors++; hw_errors++;
thr->cgpu->hw_errors++; thr->cgpu->hw_errors++;
pcd->res[FOUND] &= FOUND; pcd->res[FOUND] &= FOUND;

10
fpgautils.c

@ -104,14 +104,14 @@ int serial_autodetect_devserial(__maybe_unused detectone_func_t detectone, __may
#endif #endif
} }
int _serial_detect(struct device_api *api, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto) int _serial_detect(struct device_drv *drv, detectone_func_t detectone, autoscan_func_t autoscan, bool forceauto)
{ {
struct string_elist *iter, *tmp; struct string_elist *iter, *tmp;
const char *dev, *colon; const char *dev, *colon;
bool inhibitauto = false; bool inhibitauto = false;
char found = 0; char found = 0;
size_t namel = strlen(api->name); size_t namel = strlen(drv->name);
size_t dnamel = strlen(api->dname); size_t dnamel = strlen(drv->dname);
list_for_each_entry_safe(iter, tmp, &scan_devices, list) { list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
dev = iter->string; dev = iter->string;
@ -119,8 +119,8 @@ int _serial_detect(struct device_api *api, detectone_func_t detectone, autoscan_
size_t idlen = colon - dev; size_t idlen = colon - dev;
// allow either name:device or dname:device // allow either name:device or dname:device
if ((idlen != namel || strncasecmp(dev, api->name, idlen)) if ((idlen != namel || strncasecmp(dev, drv->name, idlen))
&& (idlen != dnamel || strncasecmp(dev, api->dname, idlen))) && (idlen != dnamel || strncasecmp(dev, drv->dname, idlen)))
continue; continue;
dev = colon + 1; dev = colon + 1;

14
fpgautils.h

@ -16,13 +16,13 @@
typedef bool(*detectone_func_t)(const char*); typedef bool(*detectone_func_t)(const char*);
typedef int(*autoscan_func_t)(); typedef int(*autoscan_func_t)();
extern int _serial_detect(struct device_api *api, detectone_func_t, autoscan_func_t, bool force_autoscan); extern int _serial_detect(struct device_drv *drv, detectone_func_t, autoscan_func_t, bool force_autoscan);
#define serial_detect_fauto(api, detectone, autoscan) \ #define serial_detect_fauto(drv, detectone, autoscan) \
_serial_detect(api, detectone, autoscan, true) _serial_detect(drv, detectone, autoscan, true)
#define serial_detect_auto(api, detectone, autoscan) \ #define serial_detect_auto(drv, detectone, autoscan) \
_serial_detect(api, detectone, autoscan, false) _serial_detect(drv, detectone, autoscan, false)
#define serial_detect(api, detectone) \ #define serial_detect(drv, detectone) \
_serial_detect(api, detectone, NULL, false) _serial_detect(drv, detectone, NULL, false)
extern int serial_autodetect_devserial(detectone_func_t, const char *prodname); extern int serial_autodetect_devserial(detectone_func_t, const char *prodname);
extern int serial_autodetect_udev(detectone_func_t, const char *prodname); extern int serial_autodetect_udev(detectone_func_t, const char *prodname);

70
miner.h

@ -114,7 +114,7 @@ static inline int fsync (int fd)
#include "libztex.h" #include "libztex.h"
#endif #endif
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
#include "usbutils.h" #include "usbutils.h"
#endif #endif
@ -196,6 +196,15 @@ static inline int fsync (int fd)
#endif #endif
#endif #endif
enum drv_driver {
DRIVER_OPENCL,
DRIVER_ICARUS,
DRIVER_BITFORCE,
DRIVER_MODMINER,
DRIVER_ZTEX,
DRIVER_CPU,
};
enum alive { enum alive {
LIFE_WELL, LIFE_WELL,
LIFE_SICK, LIFE_SICK,
@ -259,16 +268,20 @@ struct gpu_adl {
}; };
#endif #endif
extern void blank_get_statline_before(char *buf, struct cgpu_info __maybe_unused *cgpu);
struct api_data; struct api_data;
struct thr_info; struct thr_info;
struct work; struct work;
struct device_api { struct device_drv {
enum drv_driver drv_id;
char *dname; char *dname;
char *name; char *name;
// API-global functions // DRV-global functions
void (*api_detect)(); void (*drv_detect)();
// Device-specific functions // Device-specific functions
void (*reinit_device)(struct cgpu_info *); void (*reinit_device)(struct cgpu_info *);
@ -284,12 +297,31 @@ struct device_api {
uint64_t (*can_limit_work)(struct thr_info *); uint64_t (*can_limit_work)(struct thr_info *);
bool (*thread_init)(struct thr_info *); bool (*thread_init)(struct thr_info *);
bool (*prepare_work)(struct thr_info *, struct work *); bool (*prepare_work)(struct thr_info *, struct work *);
/* Which hash work loop this driver uses. */
void (*hash_work)(struct thr_info *);
/* Two variants depending on whether the device divides work up into
* small pieces or works with whole work items and may or may not have
* a queue of its own. */
int64_t (*scanhash)(struct thr_info *, struct work *, int64_t); int64_t (*scanhash)(struct thr_info *, struct work *, int64_t);
int64_t (*scanwork)(struct thr_info *);
/* Used to extract work from the hash table of queued work and tell
* the main loop that it should not add any further work to the table.
*/
bool (*queue_full)(struct cgpu_info *);
void (*flush_work)(struct cgpu_info *);
void (*hw_error)(struct thr_info *); void (*hw_error)(struct thr_info *);
void (*thread_shutdown)(struct thr_info *); void (*thread_shutdown)(struct thr_info *);
void (*thread_enable)(struct thr_info *); void (*thread_enable)(struct thr_info *);
// Does it need to be free()d?
bool copy;
}; };
extern struct device_drv *copy_drv(struct device_drv*);
enum dev_enable { enum dev_enable {
DEV_ENABLED, DEV_ENABLED,
DEV_DISABLED, DEV_DISABLED,
@ -359,13 +391,15 @@ struct cgminer_pool_stats {
uint32_t max_diff_count; uint32_t max_diff_count;
uint64_t times_sent; uint64_t times_sent;
uint64_t bytes_sent; uint64_t bytes_sent;
uint64_t net_bytes_sent;
uint64_t times_received; uint64_t times_received;
uint64_t bytes_received; uint64_t bytes_received;
uint64_t net_bytes_received;
}; };
struct cgpu_info { struct cgpu_info {
int cgminer_id; int cgminer_id;
struct device_api *api; struct device_drv *drv;
int device_id; int device_id;
char *name; char *name;
char *device_path; char *device_path;
@ -374,13 +408,17 @@ struct cgpu_info {
#ifdef USE_ZTEX #ifdef USE_ZTEX
struct libztex_device *device_ztex; struct libztex_device *device_ztex;
#endif #endif
#ifdef USE_MODMINER #if defined(USE_MODMINER) || defined(USE_BITFORCE)
struct cg_usb_device *usbdev; struct cg_usb_device *usbdev;
#endif #endif
#ifdef USE_ICARUS
int device_fd; int device_fd;
#endif
}; };
#if defined(USE_MODMINER) || defined(USE_BITFORCE)
struct cg_usb_info usbinfo;
#endif
#ifdef USE_MODMINER #ifdef USE_MODMINER
int usbstat;
char fpgaid; char fpgaid;
unsigned char clock; unsigned char clock;
pthread_mutex_t *modminer_mutex; pthread_mutex_t *modminer_mutex;
@ -475,6 +513,9 @@ struct cgpu_info {
int dev_throttle_count; int dev_throttle_count;
struct cgminer_stats cgminer_stats; struct cgminer_stats cgminer_stats;
pthread_rwlock_t qlock;
struct work *queued_work;
}; };
extern bool add_cgpu(struct cgpu_info*); extern bool add_cgpu(struct cgpu_info*);
@ -715,6 +756,8 @@ extern pthread_mutex_t cgusb_lock;
extern pthread_mutex_t hash_lock; extern pthread_mutex_t hash_lock;
extern pthread_mutex_t console_lock; extern pthread_mutex_t console_lock;
extern pthread_mutex_t ch_lock; extern pthread_mutex_t ch_lock;
extern pthread_mutex_t mining_thr_lock;
extern pthread_mutex_t devices_lock;
extern pthread_mutex_t restart_lock; extern pthread_mutex_t restart_lock;
extern pthread_cond_t restart_cond; extern pthread_cond_t restart_cond;
@ -740,6 +783,7 @@ extern void api(int thr_id);
extern struct pool *current_pool(void); extern struct pool *current_pool(void);
extern int enabled_pools; extern int enabled_pools;
extern bool detect_stratum(struct pool *pool, char *url); extern bool detect_stratum(struct pool *pool, char *url);
extern void print_summary(void);
extern struct pool *add_pool(void); extern struct pool *add_pool(void);
extern void add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass); extern void add_pool_details(struct pool *pool, bool live, char *url, char *user, char *pass);
@ -755,6 +799,7 @@ extern void add_pool_details(struct pool *pool, bool live, char *url, char *user
#define _MAX_INTENSITY_STR "14" #define _MAX_INTENSITY_STR "14"
#endif #endif
extern bool hotplug_mode;
extern struct list_head scan_devices; extern struct list_head scan_devices;
extern int nDevs; extern int nDevs;
extern int opt_n_threads; extern int opt_n_threads;
@ -762,7 +807,8 @@ extern int num_processors;
extern int hw_errors; extern int hw_errors;
extern bool use_syslog; extern bool use_syslog;
extern bool opt_quiet; extern bool opt_quiet;
extern struct thr_info *thr_info; extern struct thr_info *control_thr;
extern struct thr_info **mining_thr;
extern struct cgpu_info gpus[MAX_GPUDEVICES]; extern struct cgpu_info gpus[MAX_GPUDEVICES];
extern int gpu_threads; extern int gpu_threads;
#ifdef USE_SCRYPT #ifdef USE_SCRYPT
@ -927,6 +973,7 @@ struct pool {
time_t last_work_time; time_t last_work_time;
time_t last_share_time; time_t last_share_time;
double last_share_diff; double last_share_diff;
uint64_t best_diff;
struct cgminer_stats cgminer_stats; struct cgminer_stats cgminer_stats;
struct cgminer_pool_stats cgminer_pool_stats; struct cgminer_pool_stats cgminer_pool_stats;
@ -1058,6 +1105,9 @@ struct modminer_fpga_state {
extern void get_datestamp(char *, struct timeval *); extern void get_datestamp(char *, struct timeval *);
extern void submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce); extern void submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
extern struct work *get_queued(struct cgpu_info *cgpu);
extern void work_completed(struct cgpu_info *cgpu, struct work *work);
extern void hash_queued_work(struct thr_info *mythr);
extern void tailsprintf(char *f, const char *fmt, ...); extern void tailsprintf(char *f, const char *fmt, ...);
extern void wlogprint(const char *f, ...); extern void wlogprint(const char *f, ...);
extern int curses_int(const char *query); extern int curses_int(const char *query);
@ -1066,6 +1116,8 @@ extern void kill_work(void);
extern void switch_pools(struct pool *selected); extern void switch_pools(struct pool *selected);
extern void remove_pool(struct pool *pool); extern void remove_pool(struct pool *pool);
extern void write_config(FILE *fcfg); extern void write_config(FILE *fcfg);
extern void zero_bestshare(void);
extern void zero_stats(void);
extern void default_save_file(char *filename); extern void default_save_file(char *filename);
extern bool log_curses_only(int prio, const char *f, va_list ap); extern bool log_curses_only(int prio, const char *f, va_list ap);
extern void clear_logwin(void); extern void clear_logwin(void);
@ -1083,6 +1135,8 @@ extern void clean_work(struct work *work);
extern void free_work(struct work *work); extern void free_work(struct work *work);
extern void __copy_work(struct work *work, struct work *base_work); extern void __copy_work(struct work *work, struct work *base_work);
extern struct work *copy_work(struct work *base_work); extern struct work *copy_work(struct work *base_work);
extern struct thr_info *get_thread(int thr_id);
extern struct cgpu_info *get_devices(int id);
enum api_data_type { enum api_data_type {
API_ESCAPE, API_ESCAPE,

289
miner.php

@ -8,7 +8,7 @@ global $checklastshare, $poolinputs, $hidefields;
global $ignorerefresh, $changerefresh, $autorefresh; global $ignorerefresh, $changerefresh, $autorefresh;
global $allowcustompages, $customsummarypages; global $allowcustompages, $customsummarypages;
global $miner_font_family, $miner_font_size; global $miner_font_family, $miner_font_size;
global $colouroverride, $placebuttons; global $colouroverride, $placebuttons, $userlist;
# #
# See API-README for more details of these variables and how # See API-README for more details of these variables and how
# to configure miner.php # to configure miner.php
@ -20,6 +20,9 @@ $title = 'Mine';
# Set $readonly to false then it will check cgminer 'privileged' # Set $readonly to false then it will check cgminer 'privileged'
$readonly = false; $readonly = false;
# #
# Set $userlist to null to allow anyone access or read API-README
$userlist = null;
#
# Set $notify to false to NOT attempt to display the notify command # Set $notify to false to NOT attempt to display the notify command
# Set $notify to true to attempt to display the notify command # Set $notify to true to attempt to display the notify command
$notify = true; $notify = true;
@ -113,16 +116,17 @@ $poolspage = array(
'POOL.Difficulty Rejected=Diff Rej', 'POOL.Difficulty Rejected=Diff Rej',
'POOL.Has Stratum=Stratum', 'POOL.Stratum Active=StrAct', 'POOL.Has Stratum=Stratum', 'POOL.Stratum Active=StrAct',
'POOL.Has GBT=GBT', 'STATS.Times Sent=TSent', 'POOL.Has GBT=GBT', 'STATS.Times Sent=TSent',
'STATS.Bytes Sent=BSent', 'STATS.Times Recv=TRecv', 'STATS.Bytes Sent=BSent', 'STATS.Net Bytes Sent=NSent',
'STATS.Bytes Recv=BRecv')); 'STATS.Times Recv=TRecv', 'STATS.Bytes Recv=BRecv',
'STATS.Net Bytes Recv=NRecv'));
# #
$poolssum = array( $poolssum = array(
'SUMMARY' => array('MHS av', 'Found Blocks', 'Accepted', 'SUMMARY' => array('MHS av', 'Found Blocks', 'Accepted',
'Rejected', 'Utility', 'Hardware Errors', 'Rejected', 'Utility', 'Hardware Errors',
'Work Utility'), 'Work Utility'),
'POOL+STATS' => array('POOL.Difficulty Accepted', 'POOL.Difficulty Rejected', 'POOL+STATS' => array('POOL.Difficulty Accepted', 'POOL.Difficulty Rejected',
'STATS.Times Sent', 'STATS.Bytes Sent', 'STATS.Times Sent', 'STATS.Bytes Sent', 'STATS.Net Bytes Sent',
'STATS.Times Recv', 'STATS.Bytes Recv')); 'STATS.Times Recv', 'STATS.Bytes Recv', 'STATS.Net Bytes Recv'));
# #
$poolsext = array( $poolsext = array(
'POOL+STATS' => array( 'POOL+STATS' => array(
@ -130,7 +134,8 @@ $poolsext = array(
'group' => array('POOL.URL', 'POOL.Has Stratum', 'POOL.Stratum Active', 'POOL.Has GBT'), 'group' => array('POOL.URL', 'POOL.Has Stratum', 'POOL.Stratum Active', 'POOL.Has GBT'),
'calc' => array('POOL.Difficulty Accepted' => 'sum', 'POOL.Difficulty Rejected' => 'sum', 'calc' => array('POOL.Difficulty Accepted' => 'sum', 'POOL.Difficulty Rejected' => 'sum',
'STATS.Times Sent' => 'sum', 'STATS.Bytes Sent' => 'sum', 'STATS.Times Sent' => 'sum', 'STATS.Bytes Sent' => 'sum',
'STATS.Times Recv' => 'sum', 'STATS.Bytes Recv' => 'sum'), 'STATS.Net Bytes Sent' => 'sum', 'STATS.Times Recv' => 'sum',
'STATS.Bytes Recv' => 'sum', 'STATS.Net Bytes Recv' => 'sum'),
'having' => array(array('STATS.Bytes Recv', '>', 0))) 'having' => array(array('STATS.Bytes Recv', '>', 0)))
); );
@ -212,6 +217,10 @@ $rigerror = array();
global $rownum; global $rownum;
$rownum = 0; $rownum = 0;
# #
// Login
global $ses;
$ses = 'rutroh';
#
function getcss($cssname, $dom = false) function getcss($cssname, $dom = false)
{ {
global $colourtable, $colouroverride; global $colourtable, $colouroverride;
@ -239,7 +248,7 @@ function getdom($domname)
return getcss($domname, true); return getcss($domname, true);
} }
# #
function htmlhead($checkapi, $rig, $pg = null) function htmlhead($checkapi, $rig, $pg = null, $noscript = false)
{ {
global $title, $miner_font_family, $miner_font_size; global $title, $miner_font_family, $miner_font_size;
global $error, $readonly, $poolinputs, $here; global $error, $readonly, $poolinputs, $here;
@ -285,8 +294,10 @@ td.lst { $miner_font ".getcss('td.lst')."}
td.hi { $miner_font ".getcss('td.hi')."} td.hi { $miner_font ".getcss('td.hi')."}
td.lo { $miner_font ".getcss('td.lo')."} td.lo { $miner_font ".getcss('td.lo')."}
</style> </style>
</head><body".getdom('body')."> </head><body".getdom('body').">\n";
<script type='text/javascript'> if ($noscript === false)
{
echo "<script type='text/javascript'>
function pr(a,m){if(m!=null){if(!confirm(m+'?'))return}window.location='$here?ref=$autorefresh'+a}\n"; function pr(a,m){if(m!=null){if(!confirm(m+'?'))return}window.location='$here?ref=$autorefresh'+a}\n";
if ($ignorerefresh == false) if ($ignorerefresh == false)
@ -300,8 +311,9 @@ function prs2(a,n,r){var v=document.getElementById('gi'+n).value;var c=a.substr(
if ($poolinputs === true) if ($poolinputs === true)
echo "function cbs(s){var t=s.replace(/\\\\/g,'\\\\\\\\'); return t.replace(/,/g, '\\\\,')}\nfunction pla(r){var u=document.getElementById('purl').value;var w=document.getElementById('pwork').value;var p=document.getElementById('ppass').value;pr('&rig='+r+'&arg=addpool|'+cbs(u)+','+cbs(w)+','+cbs(p),'Add Pool '+u)}\nfunction psp(r){var p=document.getElementById('prio').value;pr('&rig='+r+'&arg=poolpriority|'+p,'Set Pool Priorities to '+p)}\n"; echo "function cbs(s){var t=s.replace(/\\\\/g,'\\\\\\\\'); return t.replace(/,/g, '\\\\,')}\nfunction pla(r){var u=document.getElementById('purl').value;var w=document.getElementById('pwork').value;var p=document.getElementById('ppass').value;pr('&rig='+r+'&arg=addpool|'+cbs(u)+','+cbs(w)+','+cbs(p),'Add Pool '+u)}\nfunction psp(r){var p=document.getElementById('prio').value;pr('&rig='+r+'&arg=poolpriority|'+p,'Set Pool Priorities to '+p)}\n";
} }
echo "</script>\n";
}
?> ?>
</script>
<table width=100% height=100% border=0 cellpadding=0 cellspacing=0 summary='Mine'> <table width=100% height=100% border=0 cellpadding=0 cellspacing=0 summary='Mine'>
<tr><td align=center valign=top> <tr><td align=center valign=top>
<table border=0 cellpadding=4 cellspacing=0 summary='Mine'> <table border=0 cellpadding=4 cellspacing=0 summary='Mine'>
@ -578,6 +590,14 @@ function classlastshare($when, $alldata, $warnclass, $errorclass)
return ''; return '';
} }
# #
function endzero($num)
{
$rep = preg_replace('/0*$/', '', $num);
if ($rep === '')
$rep = '0';
return $rep;
}
#
function fmt($section, $name, $value, $when, $alldata) function fmt($section, $name, $value, $when, $alldata)
{ {
global $dfmt, $rownum; global $dfmt, $rownum;
@ -840,12 +860,16 @@ function fmt($section, $name, $value, $when, $alldata)
case 'total.Diff1 Work': case 'total.Diff1 Work':
case 'STATS.Times Sent': case 'STATS.Times Sent':
case 'STATS.Bytes Sent': case 'STATS.Bytes Sent':
case 'STATS.Net Bytes Sent':
case 'STATS.Times Recv': case 'STATS.Times Recv':
case 'STATS.Bytes Recv': case 'STATS.Bytes Recv':
case 'STATS.Net Bytes Recv':
case 'total.Times Sent': case 'total.Times Sent':
case 'total.Bytes Sent': case 'total.Bytes Sent':
case 'total.Net Bytes Sent':
case 'total.Times Recv': case 'total.Times Recv':
case 'total.Bytes Recv': case 'total.Bytes Recv':
case 'total.Net Bytes Recv':
$parts = explode('.', $value, 2); $parts = explode('.', $value, 2);
if (count($parts) == 1) if (count($parts) == 1)
$dec = ''; $dec = '';
@ -853,6 +877,23 @@ function fmt($section, $name, $value, $when, $alldata)
$dec = '.'.$parts[1]; $dec = '.'.$parts[1];
$ret = number_format((float)$parts[0]).$dec; $ret = number_format((float)$parts[0]).$dec;
break; break;
case 'STATS.Hs':
case 'STATS.W':
case 'STATS.history_time':
case 'STATS.Pool Wait':
case 'STATS.Pool Max':
case 'STATS.Pool Min':
case 'STATS.Pool Av':
case 'STATS.Min Diff':
case 'STATS.Max Diff':
case 'STATS.Work Diff':
$parts = explode('.', $value, 2);
if (count($parts) == 1)
$dec = '';
else
$dec = '.'.endzero($parts[1]);
$ret = number_format((float)$parts[0]).$dec;
break;
case 'GPU.Status': case 'GPU.Status':
case 'PGA.Status': case 'PGA.Status':
case 'DEVS.Status': case 'DEVS.Status':
@ -1507,7 +1548,6 @@ function doforeach($cmd, $des, $sum, $head, $datetime)
# #
function refreshbuttons() function refreshbuttons()
{ {
global $readonly;
global $ignorerefresh, $changerefresh, $autorefresh; global $ignorerefresh, $changerefresh, $autorefresh;
if ($ignorerefresh == false && $changerefresh == true) if ($ignorerefresh == false && $changerefresh == true)
@ -1521,7 +1561,7 @@ function refreshbuttons()
# #
function pagebuttons($rig, $pg) function pagebuttons($rig, $pg)
{ {
global $readonly, $rigs; global $readonly, $rigs, $userlist, $ses;
global $allowcustompages, $customsummarypages; global $allowcustompages, $customsummarypages;
if ($rig === null) if ($rig === null)
@ -1557,18 +1597,33 @@ function pagebuttons($rig, $pg)
} }
echo '<tr><td><table cellpadding=0 cellspacing=0 border=0><tr><td nowrap>'; echo '<tr><td><table cellpadding=0 cellspacing=0 border=0><tr><td nowrap>';
if ($prev !== null) if ($userlist === null || isset($_SESSION[$ses]))
echo riginput($prev, 'Prev').'&nbsp;'; {
echo "<input type=button value='Refresh' onclick='pr(\"$refresh\",null)'>&nbsp;"; if ($prev !== null)
if ($next !== null) echo riginput($prev, 'Prev').'&nbsp;';
echo riginput($next, 'Next').'&nbsp;'; echo "<input type=button value='Refresh' onclick='pr(\"$refresh\",null)'>&nbsp;";
echo '&nbsp;'; if ($next !== null)
if (count($rigs) > 1) echo riginput($next, 'Next').'&nbsp;';
echo "<input type=button value='Summary' onclick='pr(\"\",null)'>&nbsp;"; echo '&nbsp;';
if (count($rigs) > 1)
echo "<input type=button value='Summary' onclick='pr(\"\",null)'>&nbsp;";
}
if ($allowcustompages === true) if ($allowcustompages === true)
foreach ($customsummarypages as $pagename => $data) {
if ($userlist === null || isset($_SESSION[$ses]))
$list = $customsummarypages;
else
{
if ($userlist !== null && isset($userlist['def']))
$list = array_flip($userlist['def']);
else
$list = array();
}
foreach ($list as $pagename => $data)
echo "<input type=button value='$pagename' onclick='pr(\"&pg=$pagename\",null)'>&nbsp;"; echo "<input type=button value='$pagename' onclick='pr(\"&pg=$pagename\",null)'>&nbsp;";
}
echo '</td><td width=100%>&nbsp;</td><td nowrap>'; echo '</td><td width=100%>&nbsp;</td><td nowrap>';
if ($rig !== null && $readonly === false) if ($rig !== null && $readonly === false)
@ -1580,6 +1635,12 @@ function pagebuttons($rig, $pg)
echo "&nbsp;<input type=button value='Quit' onclick='prc(\"quit&rig=$rig\",\"Quit CGMiner$rg\")'>"; echo "&nbsp;<input type=button value='Quit' onclick='prc(\"quit&rig=$rig\",\"Quit CGMiner$rg\")'>";
} }
refreshbuttons(); refreshbuttons();
if (isset($_SESSION[$ses]))
echo "&nbsp;<input type=button value='Logout' onclick='pr(\"&logout=1\",null)'>";
else
if ($userlist !== null)
echo "&nbsp;<input type=button value='Login' onclick='pr(\"&login=1\",null)'>";
echo "</td></tr></table></td></tr>"; echo "</td></tr></table></td></tr>";
} }
# #
@ -2015,6 +2076,8 @@ function docalc($func, $data)
if (strcasecmp($val, $ans) > 0) if (strcasecmp($val, $ans) > 0)
$ans = $val; $ans = $val;
return $ans; return $ans;
case 'count':
return count($data);
case 'any': case 'any':
default: default:
return $data[0]; return $data[0];
@ -2410,13 +2473,126 @@ function showcustompage($pagename)
pagebuttons(null, $pagename); pagebuttons(null, $pagename);
} }
# #
function onlylogin()
{
global $here;
htmlhead(false, null, null, true);
?>
<tr height=15%><td>&nbsp;</td></tr>
<tr><td>
<center>
<table width=384 height=368 cellpadding=0 cellspacing=0 border=0>
<tr><td>
<table width=100% height=100% border=0 align=center cellpadding=5 cellspacing=0>
<tr><td><form action='<?php echo $here; ?>' method=post>
<table width=200 border=0 align=center cellpadding=5 cellspacing=0>
<tr><td height=120 colspan=2>&nbsp;</td></tr>
<tr><td colspan=2 align=center valign=middle>
<h2>LOGIN</h2></td></tr>
<tr><td align=center valign=middle><div align=right>Username:</div></td>
<td height=33 align=center valign=middle>
<input type=text name=rut size=18></td></tr>
<tr><td align=center valign=middle><div align=right>Password:</div></td>
<td height=33 align=center valign=middle>
<input type=password name=roh size=18></td></tr>
<tr valign=top><td></td><td><input type=submit value=Login>
</td></tr>
</table></form></td></tr>
</table></td></tr>
</table></center>
</td></tr>
<?php
}
#
function checklogin()
{
global $allowcustompages, $customsummarypages;
global $readonly, $userlist, $ses;
$out = trim(getparam('logout', true));
if ($out !== null && $out !== '' && isset($_SESSION[$ses]))
unset($_SESSION[$ses]);
$login = trim(getparam('login', true));
if ($login !== null && $login !== '')
{
if (isset($_SESSION[$ses]))
unset($_SESSION[$ses]);
onlylogin();
return 'login';
}
if ($userlist === null)
return false;
$rut = trim(getparam('rut', true));
$roh = trim(getparam('roh', true));
if (($rut !== null && $rut !== '') || ($roh !== null && $roh !== ''))
{
if (isset($_SESSION[$ses]))
unset($_SESSION[$ses]);
if ($rut !== null && $rut !== '' && $roh !== null && $roh !== '')
{
if (isset($userlist['sys']) && isset($userlist['sys'][$rut])
&& ($userlist['sys'][$rut] === $roh))
{
$_SESSION[$ses] = true;
return false;
}
if (isset($userlist['usr']) && isset($userlist['usr'][$rut])
&& ($userlist['usr'][$rut] === $roh))
{
$_SESSION[$ses] = false;
$readonly = true;
return false;
}
}
}
if (isset($_SESSION[$ses]))
{
if ($_SESSION[$ses] == false)
$readonly = true;
return false;
}
if (isset($userlist['def']) && $allowcustompages === true)
{
// Ensure at least one exists
foreach ($userlist['def'] as $pg)
if (isset($customsummarypages[$pg]))
return true;
}
onlylogin();
return 'login';
}
#
function display() function display()
{ {
global $miner, $port; global $miner, $port;
global $readonly, $notify, $rigs; global $readonly, $notify, $rigs;
global $ignorerefresh, $autorefresh; global $ignorerefresh, $autorefresh;
global $allowcustompages; global $allowcustompages, $customsummarypages;
global $placebuttons; global $placebuttons;
global $userlist, $ses;
$pagesonly = checklogin();
if ($pagesonly === 'login')
return;
if ($rigs == null or count($rigs) == 0)
{
otherrow("<td>No rigs defined</td>");
return;
}
if ($ignorerefresh == false) if ($ignorerefresh == false)
{ {
@ -2425,52 +2601,65 @@ function display()
$autorefresh = intval($ref); $autorefresh = intval($ref);
} }
$rig = trim(getparam('rig', true)); if ($pagesonly !== true)
$arg = trim(getparam('arg', true));
$preprocess = null;
if ($arg != null and $arg != '')
{ {
$num = null; $rig = trim(getparam('rig', true));
if ($rig != null and $rig != '')
{
if ($rig >= 0 and $rig < count($rigs))
$num = $rig;
}
else
if (count($rigs) == 0)
$num = 0;
if ($num != null) $arg = trim(getparam('arg', true));
$preprocess = null;
if ($arg != null and $arg != '')
{ {
$parts = explode(':', $rigs[$num], 3); if ($rig != null and $rig != '' and $rig >= 0 and $rig < count($rigs))
if (count($parts) >= 2)
{ {
$miner = $parts[0]; $parts = explode(':', $rigs[$rig], 3);
$port = $parts[1]; if (count($parts) >= 2)
{
$miner = $parts[0];
$port = $parts[1];
if ($readonly !== true) if ($readonly !== true)
$preprocess = $arg; $preprocess = $arg;
}
} }
} }
} }
if ($rigs == null or count($rigs) == 0)
{
otherrow("<td>No rigs defined</td>");
return;
}
if ($allowcustompages === true) if ($allowcustompages === true)
{ {
$pg = trim(getparam('pg', true)); $pg = trim(getparam('pg', true));
if ($pg != null && $pg != '') if ($pagesonly === true)
{
if ($pg !== null && $pg !== '')
{
if ($userlist !== null && isset($userlist['def'])
&& !in_array($pg, $userlist['def']))
$pg = null;
}
else
{
if ($userlist !== null && isset($userlist['def']))
foreach ($userlist['def'] as $pglook)
if (isset($customsummarypages[$pglook]))
{
$pg = $pglook;
break;
}
}
}
if ($pg !== null && $pg !== '')
{ {
showcustompage($pg); showcustompage($pg);
return; return;
} }
} }
if ($pagesonly === true)
{
onlylogin();
return;
}
if (count($rigs) == 1) if (count($rigs) == 1)
{ {
$parts = explode(':', $rigs[0], 3); $parts = explode(':', $rigs[0], 3);

728
usbutils.c

File diff suppressed because it is too large Load Diff

76
usbutils.h

@ -1,5 +1,5 @@
/* /*
* Copyright 2012 Andrew Smith * Copyright 2012-2013 Andrew Smith
* *
* This program is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License as published by the Free
@ -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
@ -32,6 +55,7 @@ struct usb_find_devices {
const char *name; const char *name;
uint16_t idVendor; uint16_t idVendor;
uint16_t idProduct; uint16_t idProduct;
int kernel;
int config; int config;
int interface; int interface;
unsigned int timeout; unsigned int timeout;
@ -44,8 +68,6 @@ struct cg_usb_device {
libusb_device_handle *handle; libusb_device_handle *handle;
pthread_mutex_t *mutex; pthread_mutex_t *mutex;
struct libusb_device_descriptor *descriptor; struct libusb_device_descriptor *descriptor;
uint8_t bus_number;
uint8_t device_address;
uint16_t usbver; uint16_t usbver;
int speed; int speed;
char *prod_string; char *prod_string;
@ -55,8 +77,18 @@ struct cg_usb_device {
unsigned char interfaceVersion; // ?? unsigned char interfaceVersion; // ??
}; };
struct cg_usb_info {
uint8_t bus_number;
uint8_t device_address;
int usbstat;
bool nodev;
int nodev_count;
struct timeval last_nodev;
};
enum usb_cmds { enum usb_cmds {
C_PING = 0, C_REJECTED = 0,
C_PING,
C_CLEAR, C_CLEAR,
C_REQUESTVERSION, C_REQUESTVERSION,
C_GETVERSION, C_GETVERSION,
@ -78,32 +110,48 @@ 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
}; };
struct device_api; struct device_drv;
struct cgpu_info; struct cgpu_info;
void usb_uninit(struct cgpu_info *cgpu); void usb_uninit(struct cgpu_info *cgpu);
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_api *api, 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, 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 +165,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

34
util.c

@ -261,6 +261,29 @@ static void set_nettime(void)
wr_unlock(&netacc_lock); wr_unlock(&netacc_lock);
} }
static int curl_debug_cb(__maybe_unused CURL *handle, curl_infotype type,
__maybe_unused char *data, size_t size, void *userdata)
{
struct pool *pool = (struct pool *)userdata;
switch(type) {
case CURLINFO_HEADER_IN:
case CURLINFO_DATA_IN:
case CURLINFO_SSL_DATA_IN:
pool->cgminer_pool_stats.net_bytes_received += size;
break;
case CURLINFO_HEADER_OUT:
case CURLINFO_DATA_OUT:
case CURLINFO_SSL_DATA_OUT:
pool->cgminer_pool_stats.net_bytes_sent += size;
break;
case CURLINFO_TEXT:
default:
break;
}
return 0;
}
json_t *json_rpc_call(CURL *curl, const char *url, json_t *json_rpc_call(CURL *curl, const char *url,
const char *userpass, const char *rpc_req, const char *userpass, const char *rpc_req,
bool probe, bool longpoll, int *rolltime, bool probe, bool longpoll, int *rolltime,
@ -287,10 +310,11 @@ json_t *json_rpc_call(CURL *curl, const char *url,
probing = !pool->probed; probing = !pool->probed;
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
#if 0 /* Disable curl debugging since it spews to stderr */ // CURLOPT_VERBOSE won't write to stderr if we use CURLOPT_DEBUGFUNCTION
if (opt_protocol) curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, curl_debug_cb);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); curl_easy_setopt(curl, CURLOPT_DEBUGDATA, (void *)pool);
#endif curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_ENCODING, ""); curl_easy_setopt(curl, CURLOPT_ENCODING, "");
@ -912,6 +936,7 @@ static bool __stratum_send(struct pool *pool, char *s, ssize_t len)
pool->cgminer_pool_stats.times_sent++; pool->cgminer_pool_stats.times_sent++;
pool->cgminer_pool_stats.bytes_sent += ssent; pool->cgminer_pool_stats.bytes_sent += ssent;
pool->cgminer_pool_stats.net_bytes_sent += ssent;
return true; return true;
} }
@ -1041,6 +1066,7 @@ char *recv_line(struct pool *pool)
pool->cgminer_pool_stats.times_received++; pool->cgminer_pool_stats.times_received++;
pool->cgminer_pool_stats.bytes_received += len; pool->cgminer_pool_stats.bytes_received += len;
pool->cgminer_pool_stats.net_bytes_received += len;
out: out:
if (!sret) if (!sret)
clear_sock(pool); clear_sock(pool);

Loading…
Cancel
Save