Browse Source

Merge branch 'master' into hashfast

Conflicts:
	usbutils.h
nfactor-troky
Con Kolivas 11 years ago
parent
commit
f5baf9f57a
  1. 16
      API-README
  2. 2
      Makefile.am
  3. 100
      NEWS
  4. 403
      api.c
  5. 17
      autogen.sh
  6. 171
      cgminer.c
  7. 2
      compat/Makefile.am
  8. 554
      compat/jansson-2.5/CHANGES
  9. 2
      compat/jansson-2.5/LICENSE
  10. 17
      compat/jansson-2.5/Makefile.am
  11. 63
      compat/jansson-2.5/README.rst
  12. 54
      compat/jansson-2.5/configure.ac
  13. 10
      compat/jansson-2.5/jansson.pc.in
  14. 0
      compat/jansson-2.5/m4/.gitignore
  15. 24
      compat/jansson-2.5/src/Makefile.am
  16. 10
      compat/jansson-2.5/src/dump.c
  17. 0
      compat/jansson-2.5/src/error.c
  18. 4
      compat/jansson-2.5/src/hashtable.c
  19. 2
      compat/jansson-2.5/src/hashtable.h
  20. 2
      compat/jansson-2.5/src/jansson.def
  21. 32
      compat/jansson-2.5/src/jansson.h
  22. 2
      compat/jansson-2.5/src/jansson_config.h.in
  23. 3
      compat/jansson-2.5/src/jansson_private.h
  24. 33
      compat/jansson-2.5/src/load.c
  25. 11
      compat/jansson-2.5/src/memory.c
  26. 229
      compat/jansson-2.5/src/pack_unpack.c
  27. 11
      compat/jansson-2.5/src/strbuffer.c
  28. 4
      compat/jansson-2.5/src/strbuffer.h
  29. 5
      compat/jansson-2.5/src/strconv.c
  30. 2
      compat/jansson-2.5/src/utf.c
  31. 2
      compat/jansson-2.5/src/utf.h
  32. 39
      compat/jansson-2.5/src/value.c
  33. 3
      compat/jansson/.gitignore
  34. 21
      compat/jansson/Makefile.am
  35. 39
      compat/jansson/jansson_config.h
  36. 13
      compat/jansson/util.h
  37. 10
      compat/libusb-1.0/doc/Makefile.am
  38. 1294
      compat/libusb-1.0/doc/doxygen.cfg.in
  39. 15
      compat/libusb-1.0/examples/Makefile.am
  40. 507
      compat/libusb-1.0/examples/dpfp.c
  41. 545
      compat/libusb-1.0/examples/dpfp_threaded.c
  42. 95
      compat/libusb-1.0/examples/hotplugtest.c
  43. 64
      compat/libusb-1.0/examples/listdevs.c
  44. 193
      compat/libusb-1.0/examples/sam3u_benchmark.c
  45. 256
      compat/libusb-1.0/examples/testlibusb1.c
  46. 8
      configure.ac
  47. 91
      driver-avalon.c
  48. 11
      driver-avalon.h
  49. 26
      driver-bflsc.c
  50. 1
      driver-bflsc.h
  51. 20
      driver-icarus.c
  52. 282
      driver-klondike.c
  53. 181
      miner.h
  54. 85
      usbutils.c
  55. 1
      usbutils.h
  56. 41
      util.c
  57. 1
      util.h

16
API-README

@ -437,6 +437,12 @@ The list of requests - a (*) means it requires privileged access - and replies: @@ -437,6 +437,12 @@ The list of requests - a (*) means it requires privileged access - and replies:
AVA+BTB opt=freq val=256 to 1024 - chip frequency
BTB opt=millivolts val=1000 to 1400 - corevoltage
lockstats none There is no reply section just the STATUS section
stating the results of the request
A warning reply means lock stats are not compiled
into cgminer
The API writes all the lock stats to stderr
When you enable, disable or restart a GPU, PGA or ASC, you will also get
Thread messages in the cgminer status window
@ -491,6 +497,16 @@ miner.php - an example web page to access the API @@ -491,6 +497,16 @@ miner.php - an example web page to access the API
Feature Changelog for external applications using the API:
API V1.31 (cgminer v3.6.3)
Added API command:
'lockstats' - display cgminer dev lock stats if compiled in
Modified API command:
'summary' - add 'MHS %ds' (where %d is the log interval)
---------
API V1.30 (cgminer v3.4.3)
Added API command:

2
Makefile.am

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
ACLOCAL_AMFLAGS = -I m4
JANSSON_INCLUDES= -I$(top_srcdir)/compat/jansson
JANSSON_INCLUDES= -I$(top_srcdir)/compat/jansson-2.5/src
if WANT_USBUTILS
USBUTILS_INCLUDES = -I$(top_srcdir)/compat/libusb-1.0/libusb

100
NEWS

@ -1,4 +1,102 @@ @@ -1,4 +1,102 @@
Version 3.6.3 - 17th October 2013
- API add 'MHS %ds' to 'summary'
- Optional lock tracking and stats via the API
- Speed up polling repeat again in usb poll thread and handle async after the
message to disable polling is complete.
- Revert to using timeouts on !linux since libusb leaks memory without them.
- Revert to libusb instead of libusbx
Version 3.6.2 - 17th October 2013
- Remove unused components of jansson
- Remove unused parts of libusb
- Work around older libtoolize that fails without top ltmain.sh not being
present during autogen
- Fix open coded use of autoreconf in autogen
- Update jansson to only build parts we require and suited to our build
environment.
- Initial import of jansson-2.5
- Prevent further USB transfers from occurring once the shutdown signal has been
sent to prevent transfers getting stuck and libusb failing to shut down.
- Make the USB polling thread poll every second to potentially aid longer
timeout transfers.
- Set device_diff on work in get_work to not be missed with drivers that use
get_work directly.
- Convert icarus driver to hash_driver_work model.
- bflsc - also allow ' 0' in DEVICES IN CHAIN
- bflsc - allow a 0 in DEVICES IN CHAIN
- Add needed EXTRA_DIST for libusbx.
- Update libusbx configure.ac changes.
- Revert libusb Makefile changes from going to libusbx.
- Fix trivial libusbx warnings.
- Convert libusb-1.0.16-rc10 to libusbx-1.0.17
Version 3.6.1 - 14th October 2013
- Emulate the libusb_control_transfer sync setup in our async variant.
- usbutils - make all libusb_error_name messages the same
Version 3.6.0 - 14th October 2013
- increasing max miners for avalon driver
- using separate identifier for bitburner fury boards
- changes to bitburner driver for bitburner fury boards
- hexstr is too small in test_work_current
- Windows uses errno for WSAETIMEDOUT
- Convert the usb callback function to using cgsem_t timed waits to avoid race
conditions with conditionals/mutexes.
- Give correct return code in cgsem_mswait
- Check for correct timeout error in cgsem_mswait
- Fix util.h exports for cgsem_mswait
- Implement a generic cgsem_mswait similar to sem_timedwait
- Use the one LIBUSB_ERROR_TIMEOUT for cancelled transactions since this error
is explicitly tested for in various drivers.
- Do not use locking on usb callback function pthread signalling to prevent
deadlock with libusb's own event lock.
- Use a write lock when performing any USB control transfers to prevent
concurrent transfers.
- Free a libusb transfer after we have finished using it to avoid a dereference
in usb_control_transfer
- Do not perform bfi int patching for opencl1.2 or later.
- Although async transfers are meant to use heap memory, we never return before
the transfer function has completed so stack memory will suffice for control
transfers, fixing a memory leak in the process.
- klondike - correct/reverse min/max stats
- api incorrect message name
- klondike - use a link list queue rather than a circular buffer - and add
timing stats
- Use a timeout with usb handle events set to a nominal 200ms and wait for the
polling thread to shut down before deinitialising libusb.
- Use stack memory for hex used in stratum share submissions.
- Use stack memory in test_work_current, avoiding a malloc/free cycle each time.
- Provide a lower level __bin2hex function that does not allocate memory itself.
- Convert the bitfury driver to use the hash_driver_work version of hash_work.
- Add a hash_driver_work function to allow for drivers that wish to do their own
work queueing and management.
- Convert all usb control transfers to asynchronous communication with our own
timeout management as well.
- Klondike - increase circular read buffer size
- Klondike - extra zero value and range checking in temp conversion
- klondike - display MHz also
- Make pthread conditional timeouts handle all bulk usb transfer timeouts
performing libusb_cancel_transfer, disabling timeouts within libusb itself.
- Avoid calling get_statline_before on exit to avoid trying to use it on drivers
in an indeterminate state.
- Avoid calling get_statline on exit.
- Add a small amount to the usb timeout before cancelling to allow for a regular
usb polling interval to pass.
- Do not attempt to clear a usb halt before sending the cancel message since all
transfers should normally be cancelled before attempting to clear a halt
condition, and only change the return message to a timeout if it's consistent
with a cancellation.
- Retry up to USB_RETRY_MAX times to clear a halt condition before failing.
- Show the error number as well as the description in erroring bulk transfers.
- Drop logging level for failed to connect to stratum to verbose mode only since
we hit it regularly.
- We are always dependent on libusb handling events so use the blocking
libusb_handle_events in the polling thread and use a bool to know if we should
continue polling.

403
api.c

@ -136,7 +136,7 @@ static const char SEPARATOR = '|'; @@ -136,7 +136,7 @@ static const char SEPARATOR = '|';
#define SEPSTR "|"
static const char GPUSEP = ',';
static const char *APIVERSION = "1.30";
static const char *APIVERSION = "1.31";
static const char *DEAD = "Dead";
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA) || defined(HAVE_AN_ASIC)
static const char *SICK = "Sick";
@ -431,6 +431,8 @@ static const char *JSON_PARAMETER = "parameter"; @@ -431,6 +431,8 @@ static const char *JSON_PARAMETER = "parameter";
#define MSG_INVNEG 121
#define MSG_SETQUOTA 122
#define MSG_LOCKOK 123
#define MSG_LOCKDIS 124
enum code_severity {
SEVERITY_ERR,
@ -635,6 +637,8 @@ struct CODES { @@ -635,6 +637,8 @@ struct CODES {
{ SEVERITY_SUCC, MSG_ASCSETOK, PARAM_BOTH, "ASC %d set OK" },
{ SEVERITY_ERR, MSG_ASCSETERR, PARAM_BOTH, "ASC %d set failed: %s" },
#endif
{ SEVERITY_SUCC, MSG_LOCKOK, PARAM_NONE, "Lock stats created" },
{ SEVERITY_WARN, MSG_LOCKDIS, PARAM_NONE, "Lock stats not enabled" },
{ SEVERITY_FAIL, 0, 0, NULL }
};
@ -1432,6 +1436,399 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p @@ -1432,6 +1436,399 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p
io_add(io_data, JSON_CLOSE);
}
#if LOCK_TRACKING
#define LOCK_FMT_FFL " - called from %s %s():%d"
#define LOCKMSG(fmt, ...) fprintf(stderr, "APILOCK: " fmt "\n", ##__VA_ARGS__)
#define LOCKMSGMORE(fmt, ...) fprintf(stderr, " " fmt "\n", ##__VA_ARGS__)
#define LOCKMSGFFL(fmt, ...) fprintf(stderr, "APILOCK: " fmt LOCK_FMT_FFL "\n", ##__VA_ARGS__, file, func, linenum)
#define LOCKMSGFLUSH() fflush(stderr)
typedef struct lockstat {
uint64_t lock_id;
const char *file;
const char *func;
int linenum;
struct timeval tv;
} LOCKSTAT;
typedef struct lockline {
struct lockline *prev;
struct lockstat *stat;
struct lockline *next;
} LOCKLINE;
typedef struct lockinfo {
void *lock;
enum cglock_typ typ;
const char *file;
const char *func;
int linenum;
uint64_t gets;
uint64_t gots;
uint64_t tries;
uint64_t dids;
uint64_t didnts; // should be tries - dids
uint64_t unlocks;
LOCKSTAT lastgot;
LOCKLINE *lockgets;
LOCKLINE *locktries;
} LOCKINFO;
typedef struct locklist {
LOCKINFO *info;
struct locklist *next;
} LOCKLIST;
static uint64_t lock_id = 1;
static LOCKLIST *lockhead;
static void lockmsgnow()
{
struct timeval now;
struct tm *tm;
time_t dt;
cgtime(&now);
dt = now.tv_sec;
tm = localtime(&dt);
LOCKMSG("%d-%02d-%02d %02d:%02d:%02d",
tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
}
static LOCKLIST *newlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum)
{
LOCKLIST *list;
list = calloc(1, sizeof(*list));
if (!list)
quithere(1, "OOM list");
list->info = calloc(1, sizeof(*(list->info)));
if (!list->info)
quithere(1, "OOM info");
list->next = lockhead;
lockhead = list;
list->info->lock = lock;
list->info->typ = typ;
list->info->file = file;
list->info->func = func;
list->info->linenum = linenum;
return list;
}
static LOCKINFO *findlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum)
{
LOCKLIST *look;
look = lockhead;
while (look) {
if (look->info->lock == lock)
break;
look = look->next;
}
if (!look)
look = newlock(lock, typ, file, func, linenum);
return look->info;
}
static void addgettry(LOCKINFO *info, uint64_t id, const char *file, const char *func, const int linenum, bool get)
{
LOCKSTAT *stat;
LOCKLINE *line;
stat = calloc(1, sizeof(*stat));
if (!stat)
quithere(1, "OOM stat");
line = calloc(1, sizeof(*line));
if (!line)
quithere(1, "OOM line");
if (get)
info->gets++;
else
info->tries++;
stat->lock_id = id;
stat->file = file;
stat->func = func;
stat->linenum = linenum;
cgtime(&stat->tv);
line->stat = stat;
if (get) {
line->next = info->lockgets;
if (info->lockgets)
info->lockgets->prev = line;
info->lockgets = line;
} else {
line->next = info->locktries;
if (info->locktries)
info->locktries->prev = line;
info->locktries = line;
}
}
static void markgotdid(LOCKINFO *info, uint64_t id, const char *file, const char *func, const int linenum, bool got, int ret)
{
LOCKLINE *line;
if (got)
info->gots++;
else {
if (ret == 0)
info->dids++;
else
info->didnts++;
}
if (got || ret == 0) {
info->lastgot.lock_id = id;
info->lastgot.file = file;
info->lastgot.func = func;
info->lastgot.linenum = linenum;
cgtime(&info->lastgot.tv);
}
if (got)
line = info->lockgets;
else
line = info->locktries;
while (line) {
if (line->stat->lock_id == id)
break;
line = line->next;
}
if (!line) {
lockmsgnow();
LOCKMSGFFL("ERROR attempt to mark a lock as '%s' that wasn't '%s' id=%"PRIu64,
got ? "got" : "did/didnt", got ? "get" : "try", id);
}
// Unlink it
if (line->prev)
line->prev->next = line->next;
if (line->next)
line->next->prev = line->prev;
if (got) {
if (info->lockgets == line)
info->lockgets = line->next;
} else {
if (info->locktries == line)
info->locktries = line->next;
}
free(line->stat);
free(line);
}
// Yes this uses locks also ... ;/
static void locklock()
{
if (unlikely(pthread_mutex_lock(&lockstat_lock)))
quithere(1, "WTF MUTEX ERROR ON LOCK! errno=%d", errno);
}
static void lockunlock()
{
if (unlikely(pthread_mutex_unlock(&lockstat_lock)))
quithere(1, "WTF MUTEX ERROR ON UNLOCK! errno=%d", errno);
}
uint64_t api_getlock(void *lock, const char *file, const char *func, const int linenum)
{
LOCKINFO *info;
uint64_t id;
locklock();
info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum);
id = lock_id++;
addgettry(info, id, file, func, linenum, true);
lockunlock();
return id;
}
void api_gotlock(uint64_t id, void *lock, const char *file, const char *func, const int linenum)
{
LOCKINFO *info;
locklock();
info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum);
markgotdid(info, id, file, func, linenum, true, 0);
lockunlock();
}
uint64_t api_trylock(void *lock, const char *file, const char *func, const int linenum)
{
LOCKINFO *info;
uint64_t id;
info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum);
id = lock_id++;
addgettry(info, id, file, func, linenum, false);
return id;
}
void api_didlock(uint64_t id, int ret, void *lock, const char *file, const char *func, const int linenum)
{
LOCKINFO *info;
locklock();
info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum);
markgotdid(info, id, file, func, linenum, false, ret);
lockunlock();
}
void api_gunlock(void *lock, const char *file, const char *func, const int linenum)
{
LOCKINFO *info;
locklock();
info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum);
info->unlocks++;
lockunlock();
}
void api_initlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum)
{
locklock();
findlock(lock, typ, file, func, linenum);
lockunlock();
}
void dsp_det(char *msg, LOCKSTAT *stat)
{
struct tm *tm;
time_t dt;
dt = stat->tv.tv_sec;
tm = localtime(&dt);
LOCKMSGMORE("%s id=%"PRIu64" by %s %s():%d at %d-%02d-%02d %02d:%02d:%02d",
msg,
stat->lock_id,
stat->file,
stat->func,
stat->linenum,
tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
}
void dsp_lock(LOCKINFO *info)
{
LOCKLINE *line;
char *status;
LOCKMSG("Lock %p created by %s %s():%d",
info->lock,
info->file,
info->func,
info->linenum);
LOCKMSGMORE("gets:%"PRIu64" gots:%"PRIu64" tries:%"PRIu64
" dids:%"PRIu64" didnts:%"PRIu64" unlocks:%"PRIu64,
info->gets,
info->gots,
info->tries,
info->dids,
info->didnts,
info->unlocks);
if (info->gots > 0 || info->dids > 0) {
if (info->unlocks < info->gots + info->dids)
status = "Last got/did still HELD";
else
status = "Last got/did (idle)";
dsp_det(status, &(info->lastgot));
} else
LOCKMSGMORE("... unused ...");
if (info->lockgets) {
LOCKMSGMORE("BLOCKED gets (%"PRIu64")", info->gets - info->gots);
line = info->lockgets;
while (line) {
dsp_det("", line->stat);
line = line->next;
}
} else
LOCKMSGMORE("no blocked gets");
if (info->locktries) {
LOCKMSGMORE("BLOCKED tries (%"PRIu64")", info->tries - info->dids - info->didnts);
line = info->lockgets;
while (line) {
dsp_det("", line->stat);
line = line->next;
}
} else
LOCKMSGMORE("no blocked tries");
}
void show_locks()
{
LOCKLIST *list;
locklock();
lockmsgnow();
list = lockhead;
if (!list)
LOCKMSG("no locks?!?\n");
else {
while (list) {
dsp_lock(list->info);
list = list->next;
}
}
LOCKMSGFLUSH();
lockunlock();
}
#endif
static void lockstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
{
#if LOCK_TRACKING
show_locks();
message(io_data, MSG_LOCKOK, 0, NULL, isjson);
#else
message(io_data, MSG_LOCKDIS, 0, NULL, isjson);
#endif
}
static void apiversion(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
{
struct api_data *root = NULL;
@ -2177,6 +2574,9 @@ static void summary(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __mayb @@ -2177,6 +2574,9 @@ static void summary(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __mayb
root = api_add_elapsed(root, "Elapsed", &(total_secs), true);
root = api_add_mhs(root, "MHS av", &(mhs), false);
char mhsname[27];
sprintf(mhsname, "MHS %ds", opt_log_interval);
root = api_add_mhs(root, mhsname, &(total_rolling), false);
root = api_add_uint(root, "Found Blocks", &(found_blocks), true);
root = api_add_int(root, "Getworks", &(total_getworks), true);
root = api_add_int(root, "Accepted", &(total_accepted), true);
@ -3878,6 +4278,7 @@ struct CMDS { @@ -3878,6 +4278,7 @@ struct CMDS {
{ "ascset", ascset, true },
#endif
{ "asccount", asccount, false },
{ "lockstats", lockstats, true },
{ NULL, NULL, false }
};

17
autogen.sh

@ -1,20 +1,9 @@ @@ -1,20 +1,9 @@
#!/bin/sh
bs_dir="$(dirname $(readlink -f $0))"
rm -rf "${bs_dir}"/autom4te.cache
rm -f "${bs_dir}"/aclocal.m4 "${bs_dir}"/ltmain.sh
libusb_dir="${bs_dir}"/compat/libusb-1.0/
rm -rf "${libusb_dir}"/autom4te.cache
rm -rf "${libusb_dir}"/aclocal.m4 "${libusb_dir}"/ltmain.sh
echo 'Running autoreconf -if...'
aclocal --force -I m4
libtoolize --install --copy --force
autoheader --force
automake --add-missing --copy --force-missing
autoconf --force
autoreconf -fi "${libusb_dir}"
#Some versions of libtoolize don't like there being no ltmain.sh file already
touch "${bs_dir}"/ltmain.sh
autoreconf -fi "${bs_dir}"
if test -z "$NOCONFIGURE" ; then
echo 'Configuring...'

171
cgminer.c

@ -212,6 +212,10 @@ static int new_devices; @@ -212,6 +212,10 @@ static int new_devices;
static int new_threads;
int hotplug_time = 5;
#if LOCK_TRACKING
pthread_mutex_t lockstat_lock;
#endif
#ifdef USE_USBUTILS
pthread_mutex_t cgusb_lock;
pthread_mutex_t cgusbres_lock;
@ -237,6 +241,7 @@ pthread_cond_t restart_cond; @@ -237,6 +241,7 @@ pthread_cond_t restart_cond;
pthread_cond_t gws_cond;
double total_rolling;
double total_mhashes_done;
static struct timeval total_tv_start, total_tv_end;
@ -1249,7 +1254,10 @@ static struct opt_table opt_config_table[] = { @@ -1249,7 +1254,10 @@ static struct opt_table opt_config_table[] = {
"Set avalon target temperature"),
OPT_WITH_ARG("--bitburner-voltage",
opt_set_intval, NULL, &opt_bitburner_core_voltage,
"Set BitBurner core voltage, in millivolts"),
"Set BitBurner (Avalon) core voltage, in millivolts"),
OPT_WITH_ARG("--bitburner-fury-voltage",
opt_set_intval, NULL, &opt_bitburner_fury_core_voltage,
"Set BitBurner Fury core voltage, in millivolts"),
#endif
#ifdef USE_KLONDIKE
OPT_WITH_ARG("--klondike-options",
@ -3148,6 +3156,35 @@ static void disable_curses(void) @@ -3148,6 +3156,35 @@ static void disable_curses(void)
}
#endif
static void kill_timeout(struct thr_info *thr)
{
cg_completion_timeout(&thr_info_cancel, thr, 1000);
}
static void kill_mining(void)
{
struct thr_info *thr;
int i;
applog(LOG_DEBUG, "Killing off mining threads");
/* Kill the mining threads*/
for (i = 0; i < mining_threads; i++) {
pthread_t *pth = NULL;
thr = get_thread(i);
if (thr && PTH(thr) != 0L)
pth = &thr->pth;
thr_info_cancel(thr);
#ifndef WIN32
if (pth && *pth)
pthread_join(*pth, NULL);
#else
if (pth && pth->p)
pthread_join(*pth, NULL);
#endif
}
}
static void __kill_work(void)
{
struct thr_info *thr;
@ -3164,19 +3201,19 @@ static void __kill_work(void) @@ -3164,19 +3201,19 @@ static void __kill_work(void)
if (!opt_scrypt) {
applog(LOG_DEBUG, "Killing off HotPlug thread");
thr = &control_thr[hotplug_thr_id];
thr_info_cancel(thr);
kill_timeout(thr);
}
#endif
applog(LOG_DEBUG, "Killing off watchpool thread");
/* Kill the watchpool thread */
thr = &control_thr[watchpool_thr_id];
thr_info_cancel(thr);
kill_timeout(thr);
applog(LOG_DEBUG, "Killing off watchdog thread");
/* Kill the watchdog thread */
thr = &control_thr[watchdog_thr_id];
thr_info_cancel(thr);
kill_timeout(thr);
applog(LOG_DEBUG, "Shutting down mining threads");
for (i = 0; i < mining_threads; i++) {
@ -3194,43 +3231,27 @@ static void __kill_work(void) @@ -3194,43 +3231,27 @@ static void __kill_work(void)
sleep(1);
applog(LOG_DEBUG, "Killing off mining threads");
/* Kill the mining threads*/
for (i = 0; i < mining_threads; i++) {
pthread_t *pth = NULL;
thr = get_thread(i);
if (thr && PTH(thr) != 0L)
pth = &thr->pth;
thr_info_cancel(thr);
#ifndef WIN32
if (pth && *pth)
pthread_join(*pth, NULL);
#else
if (pth && pth->p)
pthread_join(*pth, NULL);
#endif
}
cg_completion_timeout(&kill_mining, NULL, 3000);
applog(LOG_DEBUG, "Killing off stage thread");
/* Stop the others */
thr = &control_thr[stage_thr_id];
thr_info_cancel(thr);
kill_timeout(thr);
applog(LOG_DEBUG, "Killing off API thread");
thr = &control_thr[api_thr_id];
thr_info_cancel(thr);
kill_timeout(thr);
#ifdef USE_USBUTILS
/* Release USB resources in case it's a restart
* and not a QUIT */
if (!opt_scrypt) {
applog(LOG_DEBUG, "Releasing all USB devices");
usb_cleanup();
cg_completion_timeout(&usb_cleanup, NULL, 1000);
applog(LOG_DEBUG, "Killing off usbres thread");
thr = &control_thr[usbres_thr_id];
thr_info_cancel(thr);
kill_timeout(thr);
}
#endif
@ -4505,6 +4526,7 @@ void zero_stats(void) @@ -4505,6 +4526,7 @@ void zero_stats(void)
int i;
cgtime(&total_tv_start);
total_rolling = 0;
total_mhashes_done = 0;
total_getworks = 0;
total_accepted = 0;
@ -5003,7 +5025,6 @@ static void hashmeter(int thr_id, struct timeval *diff, @@ -5003,7 +5025,6 @@ static void hashmeter(int thr_id, struct timeval *diff,
double secs;
double local_secs;
static double local_mhashes_done = 0;
static double rolling = 0;
double local_mhashes;
bool showlog = false;
char displayed_hashes[16], displayed_rolling[16];
@ -5076,15 +5097,15 @@ static void hashmeter(int thr_id, struct timeval *diff, @@ -5076,15 +5097,15 @@ static void hashmeter(int thr_id, struct timeval *diff,
cgtime(&total_tv_end);
local_secs = (double)total_diff.tv_sec + ((double)total_diff.tv_usec / 1000000.0);
decay_time(&rolling, local_mhashes_done / local_secs, local_secs);
global_hashrate = roundl(rolling) * 1000000;
decay_time(&total_rolling, local_mhashes_done / local_secs, local_secs);
global_hashrate = roundl(total_rolling) * 1000000;
timersub(&total_tv_end, &total_tv_start, &total_diff);
total_secs = (double)total_diff.tv_sec +
((double)total_diff.tv_usec / 1000000.0);
dh64 = (double)total_mhashes_done / total_secs * 1000000ull;
dr64 = (double)rolling * 1000000ull;
dr64 = (double)total_rolling * 1000000ull;
suffix_string(dh64, displayed_hashes, sizeof(displayed_hashes), 4);
suffix_string(dr64, displayed_rolling, sizeof(displayed_rolling), 4);
@ -5992,6 +6013,7 @@ struct work *get_work(struct thr_info *thr, const int thr_id) @@ -5992,6 +6013,7 @@ struct work *get_work(struct thr_info *thr, const int thr_id)
work->thr_id = thr_id;
thread_reportin(thr);
work->mined = true;
work->device_diff = MIN(thr->cgpu->drv->max_diff, work->work_difficulty);
return work;
}
@ -6326,56 +6348,39 @@ static void hash_sole_work(struct thr_info *mythr) @@ -6326,56 +6348,39 @@ static void hash_sole_work(struct thr_info *mythr)
cgpu->deven = DEV_DISABLED;
}
/* Create a hashtable of work items for devices with a queue. The device
* driver must have a custom queue_full function or it will default to true
* and put only one work item in the queue. Work items should not be removed
* from this hashtable until they are no longer in use anywhere. Once a work
* item is physically queued on the device itself, the work->queued flag
* should be set under cgpu->qlock write lock to prevent it being dereferenced
* while still in use. */
/* Put a new unqueued work item in cgpu->unqueued_work under cgpu->qlock till
* the driver tells us it's full so that it may extract the work item using
* the get_queued() function which adds it to the hashtable on
* cgpu->queued_work. */
static void fill_queue(struct thr_info *mythr, struct cgpu_info *cgpu, struct device_drv *drv, const int thr_id)
{
do {
bool need_work;
rd_lock(&cgpu->qlock);
need_work = (HASH_COUNT(cgpu->queued_work) == cgpu->queued_count);
rd_unlock(&cgpu->qlock);
if (need_work) {
struct work *work = get_work(mythr, thr_id);
work->device_diff = MIN(drv->max_diff, work->work_difficulty);
wr_lock(&cgpu->qlock);
HASH_ADD_INT(cgpu->queued_work, id, work);
wr_unlock(&cgpu->qlock);
}
wr_lock(&cgpu->qlock);
if (!cgpu->unqueued_work)
cgpu->unqueued_work = get_work(mythr, thr_id);
wr_unlock(&cgpu->qlock);
/* The queue_full function should be used by the driver to
* actually place work items on the physical device if it
* does have a queue. */
} while (!drv->queue_full(cgpu));
}
/* This function is for retrieving one work item from the queued hashtable of
* available work items that are not yet physically on a device (which is
* flagged with the work->queued bool). Code using this function must be able
* to handle NULL as a return which implies there is no work available. */
/* This function is for retrieving one work item from the unqueued pointer and
* adding it to the hashtable of queued work. Code using this function must be
* able to handle NULL as a return which implies there is no work available. */
struct work *get_queued(struct cgpu_info *cgpu)
{
struct work *work, *tmp, *ret = NULL;
struct work *work = NULL;
wr_lock(&cgpu->qlock);
HASH_ITER(hh, cgpu->queued_work, work, tmp) {
if (!work->queued) {
work->queued = true;
cgpu->queued_count++;
ret = work;
break;
}
if (cgpu->unqueued_work) {
work = cgpu->unqueued_work;
HASH_ADD_INT(cgpu->queued_work, id, work);
cgpu->unqueued_work = NULL;
}
wr_unlock(&cgpu->qlock);
return ret;
return work;
}
/* This function is for finding an already queued work item in the
@ -6388,8 +6393,7 @@ struct work *__find_work_bymidstate(struct work *que, char *midstate, size_t mid @@ -6388,8 +6393,7 @@ struct work *__find_work_bymidstate(struct work *que, char *midstate, size_t mid
struct work *work, *tmp, *ret = NULL;
HASH_ITER(hh, que, work, tmp) {
if (work->queued &&
memcmp(work->midstate, midstate, midstatelen) == 0 &&
if (memcmp(work->midstate, midstate, midstatelen) == 0 &&
memcmp(work->data + offset, data, datalen) == 0) {
ret = work;
break;
@ -6427,10 +6431,9 @@ struct work *clone_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate @@ -6427,10 +6431,9 @@ struct work *clone_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate
return ret;
}
static void __work_completed(struct cgpu_info *cgpu, struct work *work)
void __work_completed(struct cgpu_info *cgpu, struct work *work)
{
if (work->queued)
cgpu->queued_count--;
cgpu->queued_count--;
HASH_DEL(cgpu->queued_work, work);
}
/* This function should be used by queued device drivers when they're sure
@ -6461,23 +6464,17 @@ struct work *take_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, @@ -6461,23 +6464,17 @@ struct work *take_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate,
static void flush_queue(struct cgpu_info *cgpu)
{
struct work *work, *tmp;
int discarded = 0;
struct work *work = NULL;
wr_lock(&cgpu->qlock);
HASH_ITER(hh, cgpu->queued_work, work, tmp) {
/* Can only discard the work items if they're not physically
* queued on the device. */
if (!work->queued) {
HASH_DEL(cgpu->queued_work, work);
discard_work(work);
discarded++;
}
}
work = cgpu->unqueued_work;
cgpu->unqueued_work = NULL;
wr_unlock(&cgpu->qlock);
if (discarded)
applog(LOG_DEBUG, "Discarded %d queued work items", discarded);
if (work) {
free_work(work);
applog(LOG_DEBUG, "Discarded queued work item");
}
}
/* This version of hash work is for devices that are fast enough to always
@ -7799,12 +7796,16 @@ static void probe_pools(void) @@ -7799,12 +7796,16 @@ static void probe_pools(void)
#ifdef USE_USBUTILS
static void *libusb_poll_thread(void __maybe_unused *arg)
{
struct timeval tv_end = {0, 200000};
struct timeval tv_end = {0, 100000};
RenameThread("usbpoll");
while (usb_polling)
libusb_handle_events_timeout_completed(NULL, &tv_end, NULL);
/* One longer poll on shut down to enable drivers to hopefully cleanly
* shut down. */
tv_end.tv_sec = 1;
libusb_handle_events_timeout_completed(NULL, &tv_end, NULL);
return NULL;
}
@ -7840,6 +7841,12 @@ int main(int argc, char *argv[]) @@ -7840,6 +7841,12 @@ int main(int argc, char *argv[])
if (unlikely(curl_global_init(CURL_GLOBAL_ALL)))
quit(1, "Failed to curl_global_init");
#if LOCK_TRACKING
// Must be first
if (unlikely(pthread_mutex_init(&lockstat_lock, NULL)))
quithere(1, "Failed to pthread_mutex_init lockstat_lock errno=%d", errno);
#endif
initial_args = malloc(sizeof(char *) * (argc + 1));
for (i = 0; i < argc; i++)
initial_args[i] = strdup(argv[i]);

2
compat/Makefile.am

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
SUBDIRS = jansson
SUBDIRS = jansson-2.5
if WANT_USBUTILS
SUBDIRS += libusb-1.0

554
compat/jansson-2.5/CHANGES

@ -0,0 +1,554 @@ @@ -0,0 +1,554 @@
Version 2.5
===========
Released 2013-09-19
* New features:
- `json_pack()` and friends: Add format specifiers ``s#``, ``+`` and
``+#``.
- Add ``JSON_DECODE_INT_AS_REAL`` decoding flag to treat all numbers
as real in the decoder (#123).
- Add `json_array_foreach()`, paralleling `json_object_foreach()`
(#118).
* Bug fixes:
- `json_dumps()` and friends: Don't crash if json is *NULL* and
``JSON_ENCODE_ANY`` is set.
- Fix a theoretical integer overflow in `jsonp_strdup()`.
- Fix `l_isxdigit()` macro (#97).
- Fix an off-by-one error in `json_array_remove()`.
* Build:
- Support CMake in addition to GNU Autotools (#106, #107, #112,
#115, #120, #127).
- Support building for Android (#109).
- Don't use ``-Werror`` by default.
- Support building and testing with VPATH (#93).
- Fix compilation when ``NDEBUG`` is defined (#128)
* Tests:
- Fix a refleak in ``test/bin/json_process.c``.
* Documentation:
- Clarify the return value of `json_load_callback_t`.
- Document how to circumvent problems with separate heaps on Windows.
- Fix memory leaks and warnings in ``github_commits.c``.
- Use `json_decref()` properly in tutorial.
* Other:
- Make it possible to forward declare ``struct json_t``.
Version 2.4
===========
Released 2012-09-23
* New features:
- Add `json_boolean()` macro that returns the JSON true or false
value based on its argument (#86).
- Add `json_load_callback()` that calls a callback function
repeatedly to read the JSON input (#57).
- Add JSON_ESCAPE_SLASH encoding flag to escape all occurences of
``/`` with ``\/``.
* Bug fixes:
- Check for and reject NaN and Inf values for reals. Encoding these
values resulted in invalid JSON.
- Fix `json_real_set()` to return -1 on error.
* Build:
- Jansson now builds on Windows with Visual Studio 2010, and
includes solution and project files in ``win32/vs2010/``
directory.
- Fix build warnings (#77, #78).
- Add ``-no-undefined`` to LDFLAGS (#90).
* Tests:
- Fix the symbol exports test on Linux/PPC64 (#88).
* Documentation:
- Fix typos (#73, #84).
Version 2.3.1
=============
Released 2012-04-20
* Build issues:
- Only use ``long long`` if ``strtoll()`` is also available.
* Documentation:
- Fix the names of library version constants in documentation. (#52)
- Change the tutorial to use GitHub API v3. (#65)
* Tests:
- Make some tests locale independent. (#51)
- Distribute the library exports test in the tarball.
- Make test run on shells that don't support the ``export FOO=bar``
syntax.
Version 2.3
===========
Released 2012-01-27
* New features:
- `json_unpack()` and friends: Add support for optional object keys
with the ``{s?o}`` syntax.
- Add `json_object_update_existing()` and
`json_object_update_missing()`, for updating only existing keys or
only adding missing keys to an object. (#37)
- Add `json_object_foreach()` for more convenient iteration over
objects. (#45, #46)
- When decoding JSON, write the number of bytes that were read from
input to ``error.position`` also on success. This is handy with
``JSON_DISABLE_EOF_CHECK``.
- Add support for decoding any JSON value, not just arrays or
objects. The support is enabled with the new ``JSON_DECODE_ANY``
flag. Patch by Andrea Marchesini. (#4)
* Bug fixes
- Avoid problems with object's serial number growing too big. (#40,
#41)
- Decoding functions now return NULL if the first argument is NULL.
Patch by Andrea Marchesini.
- Include ``jansson_config.h.win32`` in the distribution tarball.
- Remove ``+`` and leading zeros from exponents in the encoder.
(#39)
- Make Jansson build and work on MinGW. (#39, #38)
* Documentation
- Note that the same JSON values must not be encoded in parallel by
separate threads. (#42)
- Document MinGW support.
Version 2.2.1
=============
Released 2011-10-06
* Bug fixes:
- Fix real number encoding and decoding under non-C locales. (#32)
- Fix identifier decoding under non-UTF-8 locales. (#35)
- `json_load_file()`: Open the input file in binary mode for maximum
compatiblity.
* Documentation:
- Clarify the lifecycle of the result of the ``s`` fromat of
`json_unpack()`. (#31)
- Add some portability info. (#36)
- Little clarifications here and there.
* Other:
- Some style fixes, issues detected by static analyzers.
Version 2.2
===========
Released 2011-09-03
* New features:
- `json_dump_callback()`: Pass the encoder output to a callback
function in chunks.
* Bug fixes:
- `json_string_set()`: Check that target is a string and value is
not NULL.
* Other:
- Documentation typo fixes and clarifications.
Version 2.1
===========
Released 2011-06-10
* New features:
- `json_loadb()`: Decode a string with a given size, useful if the
string is not null terminated.
- Add ``JSON_ENCODE_ANY`` encoding flag to allow encoding any JSON
value. By default, only arrays and objects can be encoded. (#19)
- Add ``JSON_REJECT_DUPLICATES`` decoding flag to issue a decoding
error if any JSON object in the input contins duplicate keys. (#3)
- Add ``JSON_DISABLE_EOF_CHECK`` decoding flag to stop decoding after a
valid JSON input. This allows other data after the JSON data.
* Bug fixes:
- Fix an additional memory leak when memory allocation fails in
`json_object_set()` and friends.
- Clear errno before calling `strtod()` for better portability. (#27)
* Building:
- Avoid set-but-not-used warning/error in a test. (#20)
* Other:
- Minor clarifications to documentation.
Version 2.0.1
=============
Released 2011-03-31
* Bug fixes:
- Replace a few `malloc()` and `free()` calls with their
counterparts that support custom memory management.
- Fix object key hashing in json_unpack() strict checking mode.
- Fix the parentheses in ``JANSSON_VERSION_HEX`` macro.
- Fix `json_object_size()` return value.
- Fix a few compilation issues.
* Portability:
- Enhance portability of `va_copy()`.
- Test framework portability enhancements.
* Documentation:
- Distribute ``doc/upgrading.rst`` with the source tarball.
- Build documentation in strict mode in ``make distcheck``.
Version 2.0
===========
Released 2011-02-28
This release is backwards incompatible with the 1.x release series.
See the chapter "Upgrading from older versions" in documentation for
details.
* Backwards incompatible changes:
- Unify unsigned integer usage in the API: All occurences of
unsigned int and unsigned long have been replaced with size_t.
- Change JSON integer's underlying type to the widest signed integer
type available, i.e. long long if it's supported, otherwise long.
Add a typedef json_int_t that defines the type.
- Change the maximum indentation depth to 31 spaces in encoder. This
frees up bits from the flags parameter of encoding functions
`json_dumpf()`, `json_dumps()` and `json_dump_file()`.
- For future needs, add a flags parameter to all decoding functions
`json_loadf()`, `json_loads()` and `json_load_file()`.
* New features
- `json_pack()`, `json_pack_ex()`, `json_vpack_ex()`: Create JSON
values based on a format string.
- `json_unpack()`, `json_unpack_ex()`, `json_vunpack_ex()`: Simple
value extraction and validation functionality based on a format
string.
- Add column, position and source fields to the ``json_error_t``
struct.
- Enhance error reporting in the decoder.
- ``JANSSON_VERSION`` et al.: Preprocessor constants that define the
library version.
- `json_set_alloc_funcs()`: Set custom memory allocation functions.
* Fix many portability issues, especially on Windows.
* Configuration
- Add file ``jansson_config.h`` that contains site specific
configuration. It's created automatically by the configure script,
or can be created by hand if the configure script cannot be used.
The file ``jansson_config.h.win32`` can be used without
modifications on Windows systems.
- Add a section to documentation describing how to build Jansson on
Windows.
- Documentation now requires Sphinx 1.0 or newer.
Version 1.3
===========
Released 2010-06-13
* New functions:
- `json_object_iter_set()`, `json_object_iter_set_new()`: Change
object contents while iterating over it.
- `json_object_iter_at()`: Return an iterator that points to a
specific object item.
* New encoding flags:
- ``JSON_PRESERVE_ORDER``: Preserve the insertion order of object
keys.
* Bug fixes:
- Fix an error that occured when an array or object was first
encoded as empty, then populated with some data, and then
re-encoded
- Fix the situation like above, but when the first encoding resulted
in an error
* Documentation:
- Clarify the documentation on reference stealing, providing an
example usage pattern
Version 1.2.1
=============
Released 2010-04-03
* Bug fixes:
- Fix reference counting on ``true``, ``false`` and ``null``
- Estimate real number underflows in decoder with 0.0 instead of
issuing an error
* Portability:
- Make ``int32_t`` available on all systems
- Support compilers that don't have the ``inline`` keyword
- Require Autoconf 2.60 (for ``int32_t``)
* Tests:
- Print test names correctly when ``VERBOSE=1``
- ``test/suites/api``: Fail when a test fails
- Enhance tests for iterators
- Enhance tests for decoding texts that contain null bytes
* Documentation:
- Don't remove ``changes.rst`` in ``make clean``
- Add a chapter on RFC conformance
Version 1.2
===========
Released 2010-01-21
* New functions:
- `json_equal()`: Test whether two JSON values are equal
- `json_copy()` and `json_deep_copy()`: Make shallow and deep copies
of JSON values
- Add a version of all functions taking a string argument that
doesn't check for valid UTF-8: `json_string_nocheck()`,
`json_string_set_nocheck()`, `json_object_set_nocheck()`,
`json_object_set_new_nocheck()`
* New encoding flags:
- ``JSON_SORT_KEYS``: Sort objects by key
- ``JSON_ENSURE_ASCII``: Escape all non-ASCII Unicode characters
- ``JSON_COMPACT``: Use a compact representation with all unneeded
whitespace stripped
* Bug fixes:
- Revise and unify whitespace usage in encoder: Add spaces between
array and object items, never append newline to output.
- Remove const qualifier from the ``json_t`` parameter in
`json_string_set()`, `json_integer_set()` and `json_real_set`.
- Use ``int32_t`` internally for representing Unicode code points
(int is not enough on all platforms)
* Other changes:
- Convert ``CHANGES`` (this file) to reStructured text and add it to
HTML documentation
- The test system has been refactored. Python is no longer required
to run the tests.
- Documentation can now be built by invoking ``make html``
- Support for pkg-config
Version 1.1.3
=============
Released 2009-12-18
* Encode reals correctly, so that first encoding and then decoding a
real always produces the same value
* Don't export private symbols in ``libjansson.so``
Version 1.1.2
=============
Released 2009-11-08
* Fix a bug where an error message was not produced if the input file
could not be opened in `json_load_file()`
* Fix an assertion failure in decoder caused by a minus sign without a
digit after it
* Remove an unneeded include of ``stdint.h`` in ``jansson.h``
Version 1.1.1
=============
Released 2009-10-26
* All documentation files were not distributed with v1.1; build
documentation in make distcheck to prevent this in the future
* Fix v1.1 release date in ``CHANGES``
Version 1.1
===========
Released 2009-10-20
* API additions and improvements:
- Extend array and object APIs
- Add functions to modify integer, real and string values
- Improve argument validation
- Use unsigned int instead of ``uint32_t`` for encoding flags
* Enhance documentation
- Add getting started guide and tutorial
- Fix some typos
- General clarifications and cleanup
* Check for integer and real overflows and underflows in decoder
* Make singleton values thread-safe (``true``, ``false`` and ``null``)
* Enhance circular reference handling
* Don't define ``-std=c99`` in ``AM_CFLAGS``
* Add C++ guards to ``jansson.h``
* Minor performance and portability improvements
* Expand test coverage
Version 1.0.4
=============
Released 2009-10-11
* Relax Autoconf version requirement to 2.59
* Make Jansson compile on platforms where plain ``char`` is unsigned
* Fix API tests for object
Version 1.0.3
=============
Released 2009-09-14
* Check for integer and real overflows and underflows in decoder
* Use the Python json module for tests, or simplejson if the json
module is not found
* Distribute changelog (this file)
Version 1.0.2
=============
Released 2009-09-08
* Handle EOF correctly in decoder
Version 1.0.1
=============
Released 2009-09-04
* Fixed broken `json_is_boolean()`
Version 1.0
===========
Released 2009-08-25
* Initial release

2
compat/jansson/LICENSE → compat/jansson-2.5/LICENSE

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

17
compat/jansson-2.5/Makefile.am

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = CHANGES LICENSE README.rst
SUBDIRS = src
# "make distcheck" builds the dvi target, so use it to check that the
# documentation is built correctly.
dvi:
$(MAKE) SPHINXOPTS_EXTRA=-W html
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = jansson.pc
if GCC
# These flags are gcc specific
export AM_CFLAGS = -Wall -Wextra -Wdeclaration-after-statement
endif

63
compat/jansson-2.5/README.rst

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
Jansson README
==============
.. image:: https://travis-ci.org/akheron/jansson.png
:alt: Build status
:target: https://travis-ci.org/akheron/jansson
Jansson_ is a C library for encoding, decoding and manipulating JSON
data. Its main features and design principles are:
- Simple and intuitive API and data model
- Comprehensive documentation
- No dependencies on other libraries
- Full Unicode support (UTF-8)
- Extensive test suite
Jansson is licensed under the `MIT license`_; see LICENSE in the
source distribution for details.
Compilation and Installation
----------------------------
If you obtained a source tarball, just use the standard autotools
commands::
$ ./configure
$ make
$ make install
To run the test suite, invoke::
$ make check
If the source has been checked out from a Git repository, the
./configure script has to be generated first. The easiest way is to
use autoreconf::
$ autoreconf -i
Documentation
-------------
Prebuilt HTML documentation is available at
http://www.digip.org/jansson/doc/.
The documentation source is in the ``doc/`` subdirectory. To generate
HTML documentation, invoke::
$ make html
Then, point your browser to ``doc/_build/html/index.html``. Sphinx_
1.0 or newer is required to generate the documentation.
.. _Jansson: http://www.digip.org/jansson/
.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php
.. _Sphinx: http://sphinx.pocoo.org/

54
compat/jansson-2.5/configure.ac

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
AC_PREREQ([2.60])
AC_INIT([jansson], [2.5], [petri@digip.org])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([1.10 foreign])
AC_CONFIG_SRCDIR([src/value.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_LIBTOOL
AM_CONDITIONAL([GCC], [test x$GCC = xyes])
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([locale.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_INT32_T
AC_TYPE_LONG_LONG_INT
AC_C_INLINE
case $ac_cv_c_inline in
yes) json_inline=inline;;
no) json_inline=;;
*) json_inline=$ac_cv_c_inline;;
esac
AC_SUBST([json_inline])
# Checks for library functions.
AC_CHECK_FUNCS([strtoll localeconv])
case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in
yesyes) json_have_long_long=1;;
*) json_have_long_long=0;;
esac
AC_SUBST([json_have_long_long])
case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in
yesyes) json_have_localeconv=1;;
*) json_have_localeconv=0;;
esac
AC_SUBST([json_have_localeconv])
AC_CONFIG_FILES([
jansson.pc
Makefile
src/Makefile
src/jansson_config.h
])
AC_OUTPUT

10
compat/jansson-2.5/jansson.pc.in

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=${prefix}/include
Name: Jansson
Description: Library for encoding, decoding and manipulating JSON data
Version: @VERSION@
Libs: -L${libdir} -ljansson
Cflags: -I${includedir}

0
compat/jansson-2.5/m4/.gitignore vendored

24
compat/jansson-2.5/src/Makefile.am

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
EXTRA_DIST = jansson.def
include_HEADERS = jansson.h jansson_config.h
lib_LTLIBRARIES = libjansson.la
libjansson_la_SOURCES = \
dump.c \
error.c \
hashtable.c \
hashtable.h \
jansson_private.h \
load.c \
memory.c \
pack_unpack.c \
strbuffer.c \
strbuffer.h \
strconv.c \
utf.c \
utf.h \
value.c
libjansson_la_LDFLAGS = \
-no-undefined \
-export-symbols-regex '^json_' \
-version-info 9:0:5

10
compat/jansson/dump.c → compat/jansson-2.5/src/dump.c

@ -1,11 +1,14 @@ @@ -1,11 +1,14 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -38,7 +41,7 @@ static int dump_to_file(const char *buffer, size_t size, void *data) @@ -38,7 +41,7 @@ static int dump_to_file(const char *buffer, size_t size, void *data)
}
/* 32 spaces (the maximum indentation size) */
static char whitespace[] = " ";
static const char whitespace[] = " ";
static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data)
{
@ -171,6 +174,9 @@ static int object_key_compare_serials(const void *key1, const void *key2) @@ -171,6 +174,9 @@ static int object_key_compare_serials(const void *key1, const void *key2)
static int do_dump(const json_t *json, size_t flags, int depth,
json_dump_callback_t dump, void *data)
{
if(!json)
return -1;
switch(json_typeof(json)) {
case JSON_NULL:
return dump("null", 4, data);

0
compat/jansson/error.c → compat/jansson-2.5/src/error.c

4
compat/jansson/hashtable.c → compat/jansson-2.5/src/hashtable.c

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@ -74,7 +74,7 @@ static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, @@ -74,7 +74,7 @@ static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket,
}
}
static size_t primes[] = {
static const size_t primes[] = {
5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
12582917, 25165843, 50331653, 100663319, 201326611, 402653189,

2
compat/jansson/hashtable.h → compat/jansson-2.5/src/hashtable.h

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

2
compat/jansson/jansson.def → compat/jansson-2.5/src/jansson.def

@ -1,5 +1,3 @@ @@ -1,5 +1,3 @@
LIBRARY "jansson"
EXPORTS
json_delete
json_true

32
compat/jansson/jansson.h → compat/jansson-2.5/src/jansson.h

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@ -21,11 +21,11 @@ extern "C" { @@ -21,11 +21,11 @@ extern "C" {
/* version */
#define JANSSON_MAJOR_VERSION 2
#define JANSSON_MINOR_VERSION 4
#define JANSSON_MINOR_VERSION 5
#define JANSSON_MICRO_VERSION 0
/* Micro version is omitted if it's 0 */
#define JANSSON_VERSION "2.4"
#define JANSSON_VERSION "2.5"
/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
@ -47,11 +47,12 @@ typedef enum { @@ -47,11 +47,12 @@ typedef enum {
JSON_NULL
} json_type;
typedef struct {
typedef struct json_t {
json_type type;
size_t refcount;
} json_t;
#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
#if JSON_INTEGER_IS_LONG_LONG
#ifdef _WIN32
#define JSON_INTEGER_FORMAT "I64d"
@ -63,6 +64,7 @@ typedef long long json_int_t; @@ -63,6 +64,7 @@ typedef long long json_int_t;
#define JSON_INTEGER_FORMAT "ld"
typedef long json_int_t;
#endif /* JSON_INTEGER_IS_LONG_LONG */
#endif
#define json_typeof(json) ((json)->type)
#define json_is_object(json) (json && json_typeof(json) == JSON_OBJECT)
@ -146,6 +148,11 @@ int json_object_iter_set_new(json_t *object, void *iter, json_t *value); @@ -146,6 +148,11 @@ int json_object_iter_set_new(json_t *object, void *iter, json_t *value);
key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key))))
#define json_array_foreach(array, index, value) \
for(index = 0; \
index < json_array_size(array) && (value = json_array_get(array, index)); \
index++)
static JSON_INLINE
int json_object_set(json_t *object, const char *key, json_t *value)
{
@ -174,9 +181,9 @@ int json_array_clear(json_t *array); @@ -174,9 +181,9 @@ int json_array_clear(json_t *array);
int json_array_extend(json_t *array, json_t *other);
static JSON_INLINE
int json_array_set(json_t *array, size_t index, json_t *value)
int json_array_set(json_t *array, size_t ind, json_t *value)
{
return json_array_set_new(array, index, json_incref(value));
return json_array_set_new(array, ind, json_incref(value));
}
static JSON_INLINE
@ -186,9 +193,9 @@ int json_array_append(json_t *array, json_t *value) @@ -186,9 +193,9 @@ int json_array_append(json_t *array, json_t *value)
}
static JSON_INLINE
int json_array_insert(json_t *array, size_t index, json_t *value)
int json_array_insert(json_t *array, size_t ind, json_t *value)
{
return json_array_insert_new(array, index, json_incref(value));
return json_array_insert_new(array, ind, json_incref(value));
}
const char *json_string_value(const json_t *string);
@ -224,14 +231,15 @@ int json_equal(json_t *value1, json_t *value2); @@ -224,14 +231,15 @@ int json_equal(json_t *value1, json_t *value2);
/* copying */
json_t *json_copy(json_t *value);
json_t *json_deep_copy(json_t *value);
json_t *json_deep_copy(const json_t *value);
/* decoding */
#define JSON_REJECT_DUPLICATES 0x1
#define JSON_DISABLE_EOF_CHECK 0x2
#define JSON_DECODE_ANY 0x4
#define JSON_REJECT_DUPLICATES 0x1
#define JSON_DISABLE_EOF_CHECK 0x2
#define JSON_DECODE_ANY 0x4
#define JSON_DECODE_INT_AS_REAL 0x8
typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);

2
compat/jansson/jansson_config.h.in → compat/jansson-2.5/src/jansson_config.h.in

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (c) 2010-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2010-2013 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

3
compat/jansson/jansson_private.h → compat/jansson-2.5/src/jansson_private.h

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@ -81,6 +81,7 @@ int jsonp_dtostr(char *buffer, size_t size, double value); @@ -81,6 +81,7 @@ int jsonp_dtostr(char *buffer, size_t size, double value);
/* Wrappers for custom memory functions */
void* jsonp_malloc(size_t size);
void jsonp_free(void *ptr);
char *jsonp_strndup(const char *str, size_t length);
char *jsonp_strdup(const char *str);
/* Windows compatibility */

33
compat/jansson/load.c → compat/jansson-2.5/src/load.c

@ -1,11 +1,14 @@ @@ -1,11 +1,14 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <errno.h>
#include <limits.h>
#include <stdio.h>
@ -37,7 +40,7 @@ @@ -37,7 +40,7 @@
#define l_isalpha(c) (l_isupper(c) || l_islower(c))
#define l_isdigit(c) ('0' <= (c) && (c) <= '9')
#define l_isxdigit(c) \
(l_isdigit(c) || 'A' <= (c) || (c) <= 'F' || 'a' <= (c) || (c) <= 'f')
(l_isdigit(c) || ('A' <= (c) && (c) <= 'F') || ('a' <= (c) && (c) <= 'f'))
/* Read one byte from stream, convert to unsigned char, then int, and
return. return EOF on end of file. This corresponds to the
@ -250,9 +253,18 @@ static void lex_unget(lex_t *lex, int c) @@ -250,9 +253,18 @@ static void lex_unget(lex_t *lex, int c)
static void lex_unget_unsave(lex_t *lex, int c)
{
if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) {
/* Since we treat warnings as errors, when assertions are turned
* off the "d" variable would be set but never used. Which is
* treated as an error by GCC.
*/
#ifndef NDEBUG
char d;
#endif
stream_unget(&lex->stream, c);
d = strbuffer_pop(&lex->saved_text);
#ifndef NDEBUG
d =
#endif
strbuffer_pop(&lex->saved_text);
assert(c == d);
}
}
@ -446,8 +458,9 @@ out: @@ -446,8 +458,9 @@ out:
jsonp_free(lex->value.string);
}
#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
#if JSON_INTEGER_IS_LONG_LONG
#ifdef _MSC_VER // Microsoft Visual Studio
#ifdef _MSC_VER /* Microsoft Visual Studio */
#define json_strtoint _strtoi64
#else
#define json_strtoint strtoll
@ -455,6 +468,7 @@ out: @@ -455,6 +468,7 @@ out:
#else
#define json_strtoint strtol
#endif
#endif
static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
{
@ -770,6 +784,7 @@ error: @@ -770,6 +784,7 @@ error:
static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
{
json_t *json;
double value;
switch(lex->token) {
case TOKEN_STRING: {
@ -778,7 +793,15 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) @@ -778,7 +793,15 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
}
case TOKEN_INTEGER: {
json = json_integer(lex->value.integer);
if (flags & JSON_DECODE_INT_AS_REAL) {
if(jsonp_strtod(&lex->saved_text, &value)) {
error_set(error, lex, "real number overflow");
return NULL;
}
json = json_real(value);
} else {
json = json_integer(lex->value.integer);
}
break;
}

11
compat/jansson/memory.c → compat/jansson-2.5/src/memory.c

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Basile Starynkevitch <basile@starynkevitch.net>
*
* Jansson is free software; you can redistribute it and/or modify it
@ -35,12 +35,17 @@ void jsonp_free(void *ptr) @@ -35,12 +35,17 @@ void jsonp_free(void *ptr)
char *jsonp_strdup(const char *str)
{
char *new_str;
size_t len;
new_str = jsonp_malloc(strlen(str) + 1);
len = strlen(str);
if(len == (size_t)-1)
return NULL;
new_str = jsonp_malloc(len + 1);
if(!new_str)
return NULL;
strcpy(new_str, str);
memcpy(new_str, str, len + 1);
return new_str;
}

229
compat/jansson/pack_unpack.c → compat/jansson-2.5/src/pack_unpack.c

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
*
* Jansson is free software; you can redistribute it and/or modify
@ -11,17 +11,29 @@ @@ -11,17 +11,29 @@
#include "jansson_private.h"
#include "utf.h"
typedef struct {
int line;
int column;
size_t pos;
char token;
} token_t;
typedef struct {
const char *start;
const char *fmt;
char token;
token_t prev_token;
token_t token;
token_t next_token;
json_error_t *error;
size_t flags;
int line;
int column;
size_t pos;
} scanner_t;
static const char *type_names[] = {
#define token(scanner) ((scanner)->token.token)
static const char * const type_names[] = {
"object",
"array",
"string",
@ -34,7 +46,7 @@ static const char *type_names[] = { @@ -34,7 +46,7 @@ static const char *type_names[] = {
#define type_name(x) type_names[json_typeof(x)]
static const char *unpack_value_starters = "{[siIbfFOon";
static const char unpack_value_starters[] = "{[siIbfFOon";
static void scanner_init(scanner_t *s, json_error_t *error,
@ -43,14 +55,28 @@ static void scanner_init(scanner_t *s, json_error_t *error, @@ -43,14 +55,28 @@ static void scanner_init(scanner_t *s, json_error_t *error,
s->error = error;
s->flags = flags;
s->fmt = s->start = fmt;
memset(&s->prev_token, 0, sizeof(token_t));
memset(&s->token, 0, sizeof(token_t));
memset(&s->next_token, 0, sizeof(token_t));
s->line = 1;
s->column = 0;
s->pos = 0;
}
static void next_token(scanner_t *s)
{
const char *t = s->fmt;
const char *t;
s->prev_token = s->token;
if(s->next_token.line) {
s->token = s->next_token;
s->next_token.line = 0;
return;
}
t = s->fmt;
s->column++;
s->pos++;
/* skip space and ignored chars */
while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') {
@ -61,23 +87,32 @@ static void next_token(scanner_t *s) @@ -61,23 +87,32 @@ static void next_token(scanner_t *s)
else
s->column++;
s->pos++;
t++;
}
s->token = *t;
s->token.token = *t;
s->token.line = s->line;
s->token.column = s->column;
s->token.pos = s->pos;
t++;
s->fmt = t;
}
static void prev_token(scanner_t *s)
{
s->next_token = s->token;
s->token = s->prev_token;
}
static void set_error(scanner_t *s, const char *source, const char *fmt, ...)
{
va_list ap;
size_t pos;
va_start(ap, fmt);
pos = (size_t)(s->fmt - s->start);
jsonp_error_vset(s->error, s->line, s->column, pos, fmt, ap);
jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos,
fmt, ap);
jsonp_error_set_source(s->error, source);
@ -86,35 +121,107 @@ static void set_error(scanner_t *s, const char *source, const char *fmt, ...) @@ -86,35 +121,107 @@ static void set_error(scanner_t *s, const char *source, const char *fmt, ...)
static json_t *pack(scanner_t *s, va_list *ap);
/* ours will be set to 1 if jsonp_free() must be called for the result
afterwards */
static char *read_string(scanner_t *s, va_list *ap,
const char *purpose, int *ours)
{
char t;
strbuffer_t strbuff;
const char *str;
size_t length;
char *result;
next_token(s);
t = token(s);
prev_token(s);
if(t != '#' && t != '+') {
/* Optimize the simple case */
str = va_arg(*ap, const char *);
if(!str) {
set_error(s, "<args>", "NULL string argument");
return NULL;
}
if(!utf8_check_string(str, -1)) {
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
return NULL;
}
*ours = 0;
return (char *)str;
}
strbuffer_init(&strbuff);
while(1) {
str = va_arg(*ap, const char *);
if(!str) {
set_error(s, "<args>", "NULL string argument");
strbuffer_close(&strbuff);
return NULL;
}
next_token(s);
if(token(s) == '#') {
length = va_arg(*ap, int);
}
else {
prev_token(s);
length = strlen(str);
}
if(strbuffer_append_bytes(&strbuff, str, length) == -1) {
set_error(s, "<internal>", "Out of memory");
strbuffer_close(&strbuff);
return NULL;
}
next_token(s);
if(token(s) != '+') {
prev_token(s);
break;
}
}
result = strbuffer_steal_value(&strbuff);
if(!utf8_check_string(result, -1)) {
set_error(s, "<args>", "Invalid UTF-8 %s", purpose);
return NULL;
}
*ours = 1;
return result;
}
static json_t *pack_object(scanner_t *s, va_list *ap)
{
json_t *object = json_object();
next_token(s);
while(s->token != '}') {
const char *key;
while(token(s) != '}') {
char *key;
int ours;
json_t *value;
if(!s->token) {
if(!token(s)) {
set_error(s, "<format>", "Unexpected end of format string");
goto error;
}
if(s->token != 's') {
set_error(s, "<format>", "Expected format 's', got '%c'", s->token);
if(token(s) != 's') {
set_error(s, "<format>", "Expected format 's', got '%c'", token(s));
goto error;
}
key = va_arg(*ap, const char *);
if(!key) {
set_error(s, "<args>", "NULL object key");
key = read_string(s, ap, "object key", &ours);
if(!key)
goto error;
}
if(!utf8_check_string(key, -1)) {
set_error(s, "<args>", "Invalid UTF-8 in object key");
goto error;
}
next_token(s);
@ -123,10 +230,16 @@ static json_t *pack_object(scanner_t *s, va_list *ap) @@ -123,10 +230,16 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
goto error;
if(json_object_set_new_nocheck(object, key, value)) {
if(ours)
jsonp_free(key);
set_error(s, "<internal>", "Unable to add key \"%s\"", key);
goto error;
}
if(ours)
jsonp_free(key);
next_token(s);
}
@ -142,10 +255,10 @@ static json_t *pack_array(scanner_t *s, va_list *ap) @@ -142,10 +255,10 @@ static json_t *pack_array(scanner_t *s, va_list *ap)
json_t *array = json_array();
next_token(s);
while(s->token != ']') {
while(token(s) != ']') {
json_t *value;
if(!s->token) {
if(!token(s)) {
set_error(s, "<format>", "Unexpected end of format string");
goto error;
}
@ -170,25 +283,27 @@ error: @@ -170,25 +283,27 @@ error:
static json_t *pack(scanner_t *s, va_list *ap)
{
switch(s->token) {
switch(token(s)) {
case '{':
return pack_object(s, ap);
case '[':
return pack_array(s, ap);
case 's': /* string */
{
const char *str = va_arg(*ap, const char *);
if(!str) {
set_error(s, "<args>", "NULL string argument");
return NULL;
}
if(!utf8_check_string(str, -1)) {
set_error(s, "<args>", "Invalid UTF-8 string");
case 's': { /* string */
char *str;
int ours;
json_t *result;
str = read_string(s, ap, "string", &ours);
if(!str)
return NULL;
}
return json_string_nocheck(str);
result = json_string_nocheck(str);
if(ours)
jsonp_free(str);
return result;
}
case 'n': /* null */
@ -214,7 +329,7 @@ static json_t *pack(scanner_t *s, va_list *ap) @@ -214,7 +329,7 @@ static json_t *pack(scanner_t *s, va_list *ap)
default:
set_error(s, "<format>", "Unexpected format character '%c'",
s->token);
token(s));
return NULL;
}
}
@ -245,30 +360,30 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) @@ -245,30 +360,30 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
}
next_token(s);
while(s->token != '}') {
while(token(s) != '}') {
const char *key;
json_t *value;
int opt = 0;
if(strict != 0) {
set_error(s, "<format>", "Expected '}' after '%c', got '%c'",
(strict == 1 ? '!' : '*'), s->token);
(strict == 1 ? '!' : '*'), token(s));
goto out;
}
if(!s->token) {
if(!token(s)) {
set_error(s, "<format>", "Unexpected end of format string");
goto out;
}
if(s->token == '!' || s->token == '*') {
strict = (s->token == '!' ? 1 : -1);
if(token(s) == '!' || token(s) == '*') {
strict = (token(s) == '!' ? 1 : -1);
next_token(s);
continue;
}
if(s->token != 's') {
set_error(s, "<format>", "Expected format 's', got '%c'", s->token);
if(token(s) != 's') {
set_error(s, "<format>", "Expected format 's', got '%c'", token(s));
goto out;
}
@ -280,7 +395,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) @@ -280,7 +395,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
next_token(s);
if(s->token == '?') {
if(token(s) == '?') {
opt = 1;
next_token(s);
}
@ -331,30 +446,30 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap) @@ -331,30 +446,30 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
}
next_token(s);
while(s->token != ']') {
while(token(s) != ']') {
json_t *value;
if(strict != 0) {
set_error(s, "<format>", "Expected ']' after '%c', got '%c'",
(strict == 1 ? '!' : '*'),
s->token);
token(s));
return -1;
}
if(!s->token) {
if(!token(s)) {
set_error(s, "<format>", "Unexpected end of format string");
return -1;
}
if(s->token == '!' || s->token == '*') {
strict = (s->token == '!' ? 1 : -1);
if(token(s) == '!' || token(s) == '*') {
strict = (token(s) == '!' ? 1 : -1);
next_token(s);
continue;
}
if(!strchr(unpack_value_starters, s->token)) {
if(!strchr(unpack_value_starters, token(s))) {
set_error(s, "<format>", "Unexpected format character '%c'",
s->token);
token(s));
return -1;
}
@ -392,7 +507,7 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap) @@ -392,7 +507,7 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
static int unpack(scanner_t *s, json_t *root, va_list *ap)
{
switch(s->token)
switch(token(s))
{
case '{':
return unpack_object(s, root, ap);
@ -521,7 +636,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) @@ -521,7 +636,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap)
default:
set_error(s, "<format>", "Unexpected format character '%c'",
s->token);
token(s));
return -1;
}
}
@ -551,7 +666,7 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags, @@ -551,7 +666,7 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags,
return NULL;
next_token(&s);
if(s.token) {
if(token(&s)) {
json_decref(value);
set_error(&s, "<format>", "Garbage after format string");
return NULL;
@ -614,7 +729,7 @@ int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, @@ -614,7 +729,7 @@ int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags,
va_end(ap_copy);
next_token(&s);
if(s.token) {
if(token(&s)) {
set_error(&s, "<format>", "Garbage after format string");
return -1;
}

11
compat/jansson/strbuffer.c → compat/jansson-2.5/src/strbuffer.c

@ -1,11 +1,14 @@ @@ -1,11 +1,14 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdlib.h>
#include <string.h>
#include "jansson_private.h"
@ -31,7 +34,9 @@ int strbuffer_init(strbuffer_t *strbuff) @@ -31,7 +34,9 @@ int strbuffer_init(strbuffer_t *strbuff)
void strbuffer_close(strbuffer_t *strbuff)
{
jsonp_free(strbuff->value);
if(strbuff->value)
jsonp_free(strbuff->value);
strbuff->size = 0;
strbuff->length = 0;
strbuff->value = NULL;
@ -51,7 +56,7 @@ const char *strbuffer_value(const strbuffer_t *strbuff) @@ -51,7 +56,7 @@ const char *strbuffer_value(const strbuffer_t *strbuff)
char *strbuffer_steal_value(strbuffer_t *strbuff)
{
char *result = strbuff->value;
strbuffer_init(strbuff);
strbuff->value = NULL;
return result;
}

4
compat/jansson/strbuffer.h → compat/jansson-2.5/src/strbuffer.h

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@ -20,6 +20,8 @@ void strbuffer_close(strbuffer_t *strbuff); @@ -20,6 +20,8 @@ void strbuffer_close(strbuffer_t *strbuff);
void strbuffer_clear(strbuffer_t *strbuff);
const char *strbuffer_value(const strbuffer_t *strbuff);
/* Steal the value and close the strbuffer */
char *strbuffer_steal_value(strbuffer_t *strbuff);
int strbuffer_append(strbuffer_t *strbuff, const char *string);

5
compat/jansson/strconv.c → compat/jansson-2.5/src/strconv.c

@ -5,6 +5,11 @@ @@ -5,6 +5,11 @@
#include "jansson_private.h"
#include "strbuffer.h"
/* need config.h to get the correct snprintf */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if JSON_HAVE_LOCALECONV
#include <locale.h>

2
compat/jansson/utf.c → compat/jansson-2.5/src/utf.c

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

2
compat/jansson/utf.h → compat/jansson-2.5/src/utf.h

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.

39
compat/jansson/value.c → compat/jansson-2.5/src/value.c

@ -1,11 +1,13 @@ @@ -1,11 +1,13 @@
/*
* Copyright (c) 2009-2012 Petri Lehtinen <petri@digip.org>
* Copyright (c) 2009-2013 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stddef.h>
#include <stdlib.h>
@ -290,19 +292,27 @@ static json_t *json_object_copy(json_t *object) @@ -290,19 +292,27 @@ static json_t *json_object_copy(json_t *object)
return result;
}
static json_t *json_object_deep_copy(json_t *object)
static json_t *json_object_deep_copy(const json_t *object)
{
json_t *result;
const char *key;
json_t *value;
void *iter;
result = json_object();
if(!result)
return NULL;
json_object_foreach(object, key, value)
/* Cannot use json_object_foreach because object has to be cast
non-const */
iter = json_object_iter((json_t *)object);
while(iter) {
const char *key;
const json_t *value;
key = json_object_iter_key(iter);
value = json_object_iter_value(iter);
json_object_set_new_nocheck(result, key, json_deep_copy(value));
iter = json_object_iter_next((json_t *)object, iter);
}
return result;
}
@ -509,7 +519,10 @@ int json_array_remove(json_t *json, size_t index) @@ -509,7 +519,10 @@ int json_array_remove(json_t *json, size_t index)
json_decref(array->table[index]);
array_move(array, index, index + 1, array->entries - index);
/* If we're removing the last element, nothing has to be moved */
if(index < array->entries - 1)
array_move(array, index, index + 1, array->entries - index - 1);
array->entries--;
return 0;
@ -590,7 +603,7 @@ static json_t *json_array_copy(json_t *array) @@ -590,7 +603,7 @@ static json_t *json_array_copy(json_t *array)
return result;
}
static json_t *json_array_deep_copy(json_t *array)
static json_t *json_array_deep_copy(const json_t *array)
{
json_t *result;
size_t i;
@ -682,7 +695,7 @@ static int json_string_equal(json_t *string1, json_t *string2) @@ -682,7 +695,7 @@ static int json_string_equal(json_t *string1, json_t *string2)
return strcmp(json_string_value(string1), json_string_value(string2)) == 0;
}
static json_t *json_string_copy(json_t *string)
static json_t *json_string_copy(const json_t *string)
{
return json_string_nocheck(json_string_value(string));
}
@ -729,7 +742,7 @@ static int json_integer_equal(json_t *integer1, json_t *integer2) @@ -729,7 +742,7 @@ static int json_integer_equal(json_t *integer1, json_t *integer2)
return json_integer_value(integer1) == json_integer_value(integer2);
}
static json_t *json_integer_copy(json_t *integer)
static json_t *json_integer_copy(const json_t *integer)
{
return json_integer(json_integer_value(integer));
}
@ -781,7 +794,7 @@ static int json_real_equal(json_t *real1, json_t *real2) @@ -781,7 +794,7 @@ static int json_real_equal(json_t *real1, json_t *real2)
return json_real_value(real1) == json_real_value(real2);
}
static json_t *json_real_copy(json_t *real)
static json_t *json_real_copy(const json_t *real)
{
return json_real(json_real_value(real));
}
@ -907,7 +920,7 @@ json_t *json_copy(json_t *json) @@ -907,7 +920,7 @@ json_t *json_copy(json_t *json)
return NULL;
}
json_t *json_deep_copy(json_t *json)
json_t *json_deep_copy(const json_t *json)
{
if(!json)
return NULL;
@ -931,7 +944,7 @@ json_t *json_deep_copy(json_t *json) @@ -931,7 +944,7 @@ json_t *json_deep_copy(json_t *json)
return json_real_copy(json);
if(json_is_true(json) || json_is_false(json) || json_is_null(json))
return json;
return (json_t *)json;
return NULL;
}

3
compat/jansson/.gitignore vendored

@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
libjansson.a

21
compat/jansson/Makefile.am

@ -1,21 +0,0 @@ @@ -1,21 +0,0 @@
EXTRA_DIST = jansson.def
include_HEADERS = jansson.h jansson_config.h
noinst_LIBRARIES = libjansson.a
libjansson_a_SOURCES = \
dump.c \
error.c \
hashtable.c \
hashtable.h \
jansson_private.h \
load.c \
memory.c \
pack_unpack.c \
strbuffer.c \
strbuffer.h \
strconv.c \
utf.c \
utf.h \
value.c

39
compat/jansson/jansson_config.h

@ -1,39 +0,0 @@ @@ -1,39 +0,0 @@
/*
* Copyright (c) 2010-2012 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*
*
* This file specifies a part of the site-specific configuration for
* Jansson, namely those things that affect the public API in
* jansson.h.
*
* The configure script copies this file to jansson_config.h and
* replaces @var@ substitutions by values that fit your system. If you
* cannot run the configure script, you can do the value substitution
* by hand.
*/
#ifndef JANSSON_CONFIG_H
#define JANSSON_CONFIG_H
/* If your compiler supports the inline keyword in C, JSON_INLINE is
defined to `inline', otherwise empty. In C++, the inline is always
supported. */
#ifdef __cplusplus
#define JSON_INLINE inline
#else
#define JSON_INLINE inline
#endif
/* If your compiler supports the `long long` type and the strtoll()
library function, JSON_INTEGER_IS_LONG_LONG is defined to 1,
otherwise to 0. */
#define JSON_INTEGER_IS_LONG_LONG 1
/* If locale.h and localeconv() are available, define to 1,
otherwise to 0. */
#define JSON_HAVE_LOCALECONV 1
#endif

13
compat/jansson/util.h

@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
/*
* Copyright (c) 2009, 2010 Petri Lehtinen <petri@digip.org>
*
* Jansson is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef UTIL_H
#define UTIL_H
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif

10
compat/libusb-1.0/doc/Makefile.am

@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
EXTRA_DIST = doxygen.cfg.in
docs: doxygen.cfg
doxygen $^
docs-upload: docs
ln -s html api-1.0
rsync -av api-1.0/ web.sourceforge.net:htdocs/api-1.0/
rm -f api-1.0

1294
compat/libusb-1.0/doc/doxygen.cfg.in

File diff suppressed because it is too large Load Diff

15
compat/libusb-1.0/examples/Makefile.am

@ -1,15 +0,0 @@ @@ -1,15 +0,0 @@
AM_CPPFLAGS = -I$(top_srcdir)/libusb
LDADD = ../libusb/libusb-1.0.la
noinst_PROGRAMS = listdevs hotplugtest testlibusb1
if HAVE_SIGACTION
noinst_PROGRAMS += dpfp
if THREADS_POSIX
dpfp_threaded_CFLAGS = $(AM_CFLAGS)
noinst_PROGRAMS += dpfp_threaded
endif
sam3u_benchmark_SOURCES = sam3u_benchmark.c
noinst_PROGRAMS += sam3u_benchmark
endif

507
compat/libusb-1.0/examples/dpfp.c

@ -1,507 +0,0 @@ @@ -1,507 +0,0 @@
/*
* libusb example program to manipulate U.are.U 4000B fingerprint scanner.
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
*
* Basic image capture program only, does not consider the powerup quirks or
* the fact that image encryption may be enabled. Not expected to work
* flawlessly all of the time.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <libusb.h>
#define EP_INTR (1 | LIBUSB_ENDPOINT_IN)
#define EP_DATA (2 | LIBUSB_ENDPOINT_IN)
#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
#define USB_RQ 0x04
#define INTR_LENGTH 64
enum {
MODE_INIT = 0x00,
MODE_AWAIT_FINGER_ON = 0x10,
MODE_AWAIT_FINGER_OFF = 0x12,
MODE_CAPTURE = 0x20,
MODE_SHUT_UP = 0x30,
MODE_READY = 0x80,
};
static int next_state(void);
enum {
STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1,
STATE_AWAIT_IRQ_FINGER_DETECTED,
STATE_AWAIT_MODE_CHANGE_CAPTURE,
STATE_AWAIT_IMAGE,
STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF,
STATE_AWAIT_IRQ_FINGER_REMOVED,
};
static int state = 0;
static struct libusb_device_handle *devh = NULL;
static unsigned char imgbuf[0x1b340];
static unsigned char irqbuf[INTR_LENGTH];
static struct libusb_transfer *img_transfer = NULL;
static struct libusb_transfer *irq_transfer = NULL;
static int img_idx = 0;
static int do_exit = 0;
static int find_dpfp_device(void)
{
devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
return devh ? 0 : -EIO;
}
static int print_f0_data(void)
{
unsigned char data[0x10];
int r;
unsigned int i;
r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data,
sizeof(data), 0);
if (r < 0) {
fprintf(stderr, "F0 error %d\n", r);
return r;
}
if ((unsigned int) r < sizeof(data)) {
fprintf(stderr, "short read (%d)\n", r);
return -1;
}
printf("F0 data:");
for (i = 0; i < sizeof(data); i++)
printf("%02x ", data[i]);
printf("\n");
return 0;
}
static int get_hwstat(unsigned char *status)
{
int r;
r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0);
if (r < 0) {
fprintf(stderr, "read hwstat error %d\n", r);
return r;
}
if ((unsigned int) r < 1) {
fprintf(stderr, "short read (%d)\n", r);
return -1;
}
printf("hwstat reads %02x\n", *status);
return 0;
}
static int set_hwstat(unsigned char data)
{
int r;
printf("set hwstat to %02x\n", data);
r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0);
if (r < 0) {
fprintf(stderr, "set hwstat error %d\n", r);
return r;
}
if ((unsigned int) r < 1) {
fprintf(stderr, "short write (%d)", r);
return -1;
}
return 0;
}
static int set_mode(unsigned char data)
{
int r;
printf("set mode %02x\n", data);
r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0);
if (r < 0) {
fprintf(stderr, "set mode error %d\n", r);
return r;
}
if ((unsigned int) r < 1) {
fprintf(stderr, "short write (%d)", r);
return -1;
}
return 0;
}
static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer)
{
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fprintf(stderr, "mode change transfer not completed!\n");
do_exit = 2;
}
printf("async cb_mode_changed length=%d actual_length=%d\n",
transfer->length, transfer->actual_length);
if (next_state() < 0)
do_exit = 2;
}
static int set_mode_async(unsigned char data)
{
unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
struct libusb_transfer *transfer;
if (!buf)
return -ENOMEM;
transfer = libusb_alloc_transfer(0);
if (!transfer) {
free(buf);
return -ENOMEM;
}
printf("async set mode %02x\n", data);
libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1);
buf[LIBUSB_CONTROL_SETUP_SIZE] = data;
libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL,
1000);
transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK
| LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
return libusb_submit_transfer(transfer);
}
static int do_sync_intr(unsigned char *data)
{
int r;
int transferred;
r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH,
&transferred, 1000);
if (r < 0) {
fprintf(stderr, "intr error %d\n", r);
return r;
}
if (transferred < INTR_LENGTH) {
fprintf(stderr, "short read (%d)\n", r);
return -1;
}
printf("recv interrupt %04x\n", *((uint16_t *) data));
return 0;
}
static int sync_intr(unsigned char type)
{
int r;
unsigned char data[INTR_LENGTH];
while (1) {
r = do_sync_intr(data);
if (r < 0)
return r;
if (data[0] == type)
return 0;
}
}
static int save_to_file(unsigned char *data)
{
FILE *fd;
char filename[64];
snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++);
fd = fopen(filename, "w");
if (!fd)
return -1;
fputs("P5 384 289 255 ", fd);
(void) fwrite(data + 64, 1, 384*289, fd);
fclose(fd);
printf("saved image to %s\n", filename);
return 0;
}
static int next_state(void)
{
int r = 0;
printf("old state: %d\n", state);
switch (state) {
case STATE_AWAIT_IRQ_FINGER_REMOVED:
state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON;
r = set_mode_async(MODE_AWAIT_FINGER_ON);
break;
case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON:
state = STATE_AWAIT_IRQ_FINGER_DETECTED;
break;
case STATE_AWAIT_IRQ_FINGER_DETECTED:
state = STATE_AWAIT_MODE_CHANGE_CAPTURE;
r = set_mode_async(MODE_CAPTURE);
break;
case STATE_AWAIT_MODE_CHANGE_CAPTURE:
state = STATE_AWAIT_IMAGE;
break;
case STATE_AWAIT_IMAGE:
state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF;
r = set_mode_async(MODE_AWAIT_FINGER_OFF);
break;
case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF:
state = STATE_AWAIT_IRQ_FINGER_REMOVED;
break;
default:
printf("unrecognised state %d\n", state);
}
if (r < 0) {
fprintf(stderr, "error detected changing state\n");
return r;
}
printf("new state: %d\n", state);
return 0;
}
static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer)
{
unsigned char irqtype = transfer->buffer[0];
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fprintf(stderr, "irq transfer status %d?\n", transfer->status);
do_exit = 2;
libusb_free_transfer(transfer);
irq_transfer = NULL;
return;
}
printf("IRQ callback %02x\n", irqtype);
switch (state) {
case STATE_AWAIT_IRQ_FINGER_DETECTED:
if (irqtype == 0x01) {
if (next_state() < 0) {
do_exit = 2;
return;
}
} else {
printf("finger-on-sensor detected in wrong state!\n");
}
break;
case STATE_AWAIT_IRQ_FINGER_REMOVED:
if (irqtype == 0x02) {
if (next_state() < 0) {
do_exit = 2;
return;
}
} else {
printf("finger-on-sensor detected in wrong state!\n");
}
break;
}
if (libusb_submit_transfer(irq_transfer) < 0)
do_exit = 2;
}
static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer)
{
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fprintf(stderr, "img transfer status %d?\n", transfer->status);
do_exit = 2;
libusb_free_transfer(transfer);
img_transfer = NULL;
return;
}
printf("Image callback\n");
save_to_file(imgbuf);
if (next_state() < 0) {
do_exit = 2;
return;
}
if (libusb_submit_transfer(img_transfer) < 0)
do_exit = 2;
}
static int init_capture(void)
{
int r;
r = libusb_submit_transfer(irq_transfer);
if (r < 0)
return r;
r = libusb_submit_transfer(img_transfer);
if (r < 0) {
libusb_cancel_transfer(irq_transfer);
while (irq_transfer)
if (libusb_handle_events(NULL) < 0)
break;
return r;
}
/* start state machine */
state = STATE_AWAIT_IRQ_FINGER_REMOVED;
return next_state();
}
static int do_init(void)
{
unsigned char status;
int r;
r = get_hwstat(&status);
if (r < 0)
return r;
if (!(status & 0x80)) {
r = set_hwstat(status | 0x80);
if (r < 0)
return r;
r = get_hwstat(&status);
if (r < 0)
return r;
}
status &= ~0x80;
r = set_hwstat(status);
if (r < 0)
return r;
r = get_hwstat(&status);
if (r < 0)
return r;
r = sync_intr(0x56);
if (r < 0)
return r;
return 0;
}
static int alloc_transfers(void)
{
img_transfer = libusb_alloc_transfer(0);
if (!img_transfer)
return -ENOMEM;
irq_transfer = libusb_alloc_transfer(0);
if (!irq_transfer)
return -ENOMEM;
libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf,
sizeof(imgbuf), cb_img, NULL, 0);
libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf,
sizeof(irqbuf), cb_irq, NULL, 0);
return 0;
}
static void sighandler(int signum)
{
do_exit = 1;
}
int main(void)
{
struct sigaction sigact;
int r = 1;
r = libusb_init(NULL);
if (r < 0) {
fprintf(stderr, "failed to initialise libusb\n");
exit(1);
}
r = find_dpfp_device();
if (r < 0) {
fprintf(stderr, "Could not find/open device\n");
goto out;
}
r = libusb_claim_interface(devh, 0);
if (r < 0) {
fprintf(stderr, "usb_claim_interface error %d\n", r);
goto out;
}
printf("claimed interface\n");
r = print_f0_data();
if (r < 0)
goto out_release;
r = do_init();
if (r < 0)
goto out_deinit;
/* async from here onwards */
r = alloc_transfers();
if (r < 0)
goto out_deinit;
r = init_capture();
if (r < 0)
goto out_deinit;
sigact.sa_handler = sighandler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGQUIT, &sigact, NULL);
while (!do_exit) {
r = libusb_handle_events(NULL);
if (r < 0)
goto out_deinit;
}
printf("shutting down...\n");
if (irq_transfer) {
r = libusb_cancel_transfer(irq_transfer);
if (r < 0)
goto out_deinit;
}
if (img_transfer) {
r = libusb_cancel_transfer(img_transfer);
if (r < 0)
goto out_deinit;
}
while (irq_transfer || img_transfer)
if (libusb_handle_events(NULL) < 0)
break;
if (do_exit == 1)
r = 0;
else
r = 1;
out_deinit:
libusb_free_transfer(img_transfer);
libusb_free_transfer(irq_transfer);
set_mode(0);
set_hwstat(0x80);
out_release:
libusb_release_interface(devh, 0);
out:
libusb_close(devh);
libusb_exit(NULL);
return r >= 0 ? r : -r;
}

545
compat/libusb-1.0/examples/dpfp_threaded.c

@ -1,545 +0,0 @@ @@ -1,545 +0,0 @@
/*
* libusb example program to manipulate U.are.U 4000B fingerprint scanner.
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
*
* Basic image capture program only, does not consider the powerup quirks or
* the fact that image encryption may be enabled. Not expected to work
* flawlessly all of the time.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <libusb.h>
#define EP_INTR (1 | LIBUSB_ENDPOINT_IN)
#define EP_DATA (2 | LIBUSB_ENDPOINT_IN)
#define CTRL_IN (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN)
#define CTRL_OUT (LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT)
#define USB_RQ 0x04
#define INTR_LENGTH 64
enum {
MODE_INIT = 0x00,
MODE_AWAIT_FINGER_ON = 0x10,
MODE_AWAIT_FINGER_OFF = 0x12,
MODE_CAPTURE = 0x20,
MODE_SHUT_UP = 0x30,
MODE_READY = 0x80,
};
static int next_state(void);
enum {
STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON = 1,
STATE_AWAIT_IRQ_FINGER_DETECTED,
STATE_AWAIT_MODE_CHANGE_CAPTURE,
STATE_AWAIT_IMAGE,
STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF,
STATE_AWAIT_IRQ_FINGER_REMOVED,
};
static int state = 0;
static struct libusb_device_handle *devh = NULL;
static unsigned char imgbuf[0x1b340];
static unsigned char irqbuf[INTR_LENGTH];
static struct libusb_transfer *img_transfer = NULL;
static struct libusb_transfer *irq_transfer = NULL;
static int img_idx = 0;
static int do_exit = 0;
static pthread_t poll_thread;
static pthread_cond_t exit_cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t exit_cond_lock = PTHREAD_MUTEX_INITIALIZER;
static void request_exit(int code)
{
do_exit = code;
pthread_cond_signal(&exit_cond);
}
static void *poll_thread_main(void *arg)
{
int r = 0;
printf("poll thread running\n");
while (!do_exit) {
struct timeval tv = { 1, 0 };
r = libusb_handle_events_timeout(NULL, &tv);
if (r < 0) {
request_exit(2);
break;
}
}
printf("poll thread shutting down\n");
return NULL;
}
static int find_dpfp_device(void)
{
devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
return devh ? 0 : -EIO;
}
static int print_f0_data(void)
{
unsigned char data[0x10];
int r;
unsigned int i;
r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0xf0, 0, data,
sizeof(data), 0);
if (r < 0) {
fprintf(stderr, "F0 error %d\n", r);
return r;
}
if ((unsigned int) r < sizeof(data)) {
fprintf(stderr, "short read (%d)\n", r);
return -1;
}
printf("F0 data:");
for (i = 0; i < sizeof(data); i++)
printf("%02x ", data[i]);
printf("\n");
return 0;
}
static int get_hwstat(unsigned char *status)
{
int r;
r = libusb_control_transfer(devh, CTRL_IN, USB_RQ, 0x07, 0, status, 1, 0);
if (r < 0) {
fprintf(stderr, "read hwstat error %d\n", r);
return r;
}
if ((unsigned int) r < 1) {
fprintf(stderr, "short read (%d)\n", r);
return -1;
}
printf("hwstat reads %02x\n", *status);
return 0;
}
static int set_hwstat(unsigned char data)
{
int r;
printf("set hwstat to %02x\n", data);
r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x07, 0, &data, 1, 0);
if (r < 0) {
fprintf(stderr, "set hwstat error %d\n", r);
return r;
}
if ((unsigned int) r < 1) {
fprintf(stderr, "short write (%d)", r);
return -1;
}
return 0;
}
static int set_mode(unsigned char data)
{
int r;
printf("set mode %02x\n", data);
r = libusb_control_transfer(devh, CTRL_OUT, USB_RQ, 0x4e, 0, &data, 1, 0);
if (r < 0) {
fprintf(stderr, "set mode error %d\n", r);
return r;
}
if ((unsigned int) r < 1) {
fprintf(stderr, "short write (%d)", r);
return -1;
}
return 0;
}
static void LIBUSB_CALL cb_mode_changed(struct libusb_transfer *transfer)
{
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fprintf(stderr, "mode change transfer not completed!\n");
request_exit(2);
}
printf("async cb_mode_changed length=%d actual_length=%d\n",
transfer->length, transfer->actual_length);
if (next_state() < 0)
request_exit(2);
}
static int set_mode_async(unsigned char data)
{
unsigned char *buf = malloc(LIBUSB_CONTROL_SETUP_SIZE + 1);
struct libusb_transfer *transfer;
if (!buf)
return -ENOMEM;
transfer = libusb_alloc_transfer(0);
if (!transfer) {
free(buf);
return -ENOMEM;
}
printf("async set mode %02x\n", data);
libusb_fill_control_setup(buf, CTRL_OUT, USB_RQ, 0x4e, 0, 1);
buf[LIBUSB_CONTROL_SETUP_SIZE] = data;
libusb_fill_control_transfer(transfer, devh, buf, cb_mode_changed, NULL,
1000);
transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK
| LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER;
return libusb_submit_transfer(transfer);
}
static int do_sync_intr(unsigned char *data)
{
int r;
int transferred;
r = libusb_interrupt_transfer(devh, EP_INTR, data, INTR_LENGTH,
&transferred, 1000);
if (r < 0) {
fprintf(stderr, "intr error %d\n", r);
return r;
}
if (transferred < INTR_LENGTH) {
fprintf(stderr, "short read (%d)\n", r);
return -1;
}
printf("recv interrupt %04x\n", *((uint16_t *) data));
return 0;
}
static int sync_intr(unsigned char type)
{
int r;
unsigned char data[INTR_LENGTH];
while (1) {
r = do_sync_intr(data);
if (r < 0)
return r;
if (data[0] == type)
return 0;
}
}
static int save_to_file(unsigned char *data)
{
FILE *fd;
char filename[64];
snprintf(filename, sizeof(filename), "finger%d.pgm", img_idx++);
fd = fopen(filename, "w");
if (!fd)
return -1;
fputs("P5 384 289 255 ", fd);
(void) fwrite(data + 64, 1, 384*289, fd);
fclose(fd);
printf("saved image to %s\n", filename);
return 0;
}
static int next_state(void)
{
int r = 0;
printf("old state: %d\n", state);
switch (state) {
case STATE_AWAIT_IRQ_FINGER_REMOVED:
state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON;
r = set_mode_async(MODE_AWAIT_FINGER_ON);
break;
case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_ON:
state = STATE_AWAIT_IRQ_FINGER_DETECTED;
break;
case STATE_AWAIT_IRQ_FINGER_DETECTED:
state = STATE_AWAIT_MODE_CHANGE_CAPTURE;
r = set_mode_async(MODE_CAPTURE);
break;
case STATE_AWAIT_MODE_CHANGE_CAPTURE:
state = STATE_AWAIT_IMAGE;
break;
case STATE_AWAIT_IMAGE:
state = STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF;
r = set_mode_async(MODE_AWAIT_FINGER_OFF);
break;
case STATE_AWAIT_MODE_CHANGE_AWAIT_FINGER_OFF:
state = STATE_AWAIT_IRQ_FINGER_REMOVED;
break;
default:
printf("unrecognised state %d\n", state);
}
if (r < 0) {
fprintf(stderr, "error detected changing state\n");
return r;
}
printf("new state: %d\n", state);
return 0;
}
static void LIBUSB_CALL cb_irq(struct libusb_transfer *transfer)
{
unsigned char irqtype = transfer->buffer[0];
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fprintf(stderr, "irq transfer status %d?\n", transfer->status);
irq_transfer = NULL;
request_exit(2);
return;
}
printf("IRQ callback %02x\n", irqtype);
switch (state) {
case STATE_AWAIT_IRQ_FINGER_DETECTED:
if (irqtype == 0x01) {
if (next_state() < 0) {
request_exit(2);
return;
}
} else {
printf("finger-on-sensor detected in wrong state!\n");
}
break;
case STATE_AWAIT_IRQ_FINGER_REMOVED:
if (irqtype == 0x02) {
if (next_state() < 0) {
request_exit(2);
return;
}
} else {
printf("finger-on-sensor detected in wrong state!\n");
}
break;
}
if (libusb_submit_transfer(irq_transfer) < 0)
request_exit(2);
}
static void LIBUSB_CALL cb_img(struct libusb_transfer *transfer)
{
if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
fprintf(stderr, "img transfer status %d?\n", transfer->status);
img_transfer = NULL;
request_exit(2);
return;
}
printf("Image callback\n");
save_to_file(imgbuf);
if (next_state() < 0) {
request_exit(2);
return;
}
if (libusb_submit_transfer(img_transfer) < 0)
request_exit(2);
}
static int init_capture(void)
{
int r;
r = libusb_submit_transfer(irq_transfer);
if (r < 0)
return r;
r = libusb_submit_transfer(img_transfer);
if (r < 0) {
libusb_cancel_transfer(irq_transfer);
while (irq_transfer)
if (libusb_handle_events(NULL) < 0)
break;
return r;
}
/* start state machine */
state = STATE_AWAIT_IRQ_FINGER_REMOVED;
return next_state();
}
static int do_init(void)
{
unsigned char status;
int r;
r = get_hwstat(&status);
if (r < 0)
return r;
if (!(status & 0x80)) {
r = set_hwstat(status | 0x80);
if (r < 0)
return r;
r = get_hwstat(&status);
if (r < 0)
return r;
}
status &= ~0x80;
r = set_hwstat(status);
if (r < 0)
return r;
r = get_hwstat(&status);
if (r < 0)
return r;
r = sync_intr(0x56);
if (r < 0)
return r;
return 0;
}
static int alloc_transfers(void)
{
img_transfer = libusb_alloc_transfer(0);
if (!img_transfer)
return -ENOMEM;
irq_transfer = libusb_alloc_transfer(0);
if (!irq_transfer)
return -ENOMEM;
libusb_fill_bulk_transfer(img_transfer, devh, EP_DATA, imgbuf,
sizeof(imgbuf), cb_img, NULL, 0);
libusb_fill_interrupt_transfer(irq_transfer, devh, EP_INTR, irqbuf,
sizeof(irqbuf), cb_irq, NULL, 0);
return 0;
}
static void sighandler(int signum)
{
request_exit(1);
}
int main(void)
{
struct sigaction sigact;
int r = 1;
r = libusb_init(NULL);
if (r < 0) {
fprintf(stderr, "failed to initialise libusb\n");
exit(1);
}
r = find_dpfp_device();
if (r < 0) {
fprintf(stderr, "Could not find/open device\n");
goto out;
}
r = libusb_claim_interface(devh, 0);
if (r < 0) {
fprintf(stderr, "usb_claim_interface error %d %s\n", r, strerror(-r));
goto out;
}
printf("claimed interface\n");
r = print_f0_data();
if (r < 0)
goto out_release;
r = do_init();
if (r < 0)
goto out_deinit;
/* async from here onwards */
sigact.sa_handler = sighandler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, NULL);
sigaction(SIGTERM, &sigact, NULL);
sigaction(SIGQUIT, &sigact, NULL);
r = pthread_create(&poll_thread, NULL, poll_thread_main, NULL);
if (r)
goto out_deinit;
r = alloc_transfers();
if (r < 0) {
request_exit(1);
pthread_join(poll_thread, NULL);
goto out_deinit;
}
r = init_capture();
if (r < 0) {
request_exit(1);
pthread_join(poll_thread, NULL);
goto out_deinit;
}
while (!do_exit) {
pthread_mutex_lock(&exit_cond_lock);
pthread_cond_wait(&exit_cond, &exit_cond_lock);
pthread_mutex_unlock(&exit_cond_lock);
}
printf("shutting down...\n");
pthread_join(poll_thread, NULL);
r = libusb_cancel_transfer(irq_transfer);
if (r < 0) {
request_exit(1);
goto out_deinit;
}
r = libusb_cancel_transfer(img_transfer);
if (r < 0) {
request_exit(1);
goto out_deinit;
}
while (img_transfer || irq_transfer)
if (libusb_handle_events(NULL) < 0)
break;
if (do_exit == 1)
r = 0;
else
r = 1;
out_deinit:
libusb_free_transfer(img_transfer);
libusb_free_transfer(irq_transfer);
set_mode(0);
set_hwstat(0x80);
out_release:
libusb_release_interface(devh, 0);
out:
libusb_close(devh);
libusb_exit(NULL);
return r >= 0 ? r : -r;
}

95
compat/libusb-1.0/examples/hotplugtest.c

@ -1,95 +0,0 @@ @@ -1,95 +0,0 @@
/*
* libusb example program for hotplug API
* Copyright (C) 2012-2013 Nathan Hjelm <hjelmn@mac.ccom>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdlib.h>
#include <stdio.h>
#include <sched.h>
#include <unistd.h>
#include <libusb.h>
int done = 0;
libusb_device_handle *handle;
static int hotplug_callback (libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) {
struct libusb_device_descriptor desc;
int rc;
rc = libusb_get_device_descriptor(dev, &desc);
if (LIBUSB_SUCCESS != rc) {
fprintf (stderr, "Error getting device descriptor\n");
}
printf ("Device attach: %04x:%04x\n", desc.idVendor, desc.idProduct);
libusb_open (dev, &handle);
done++;
return 0;
}
static int hotplug_callback_detach (libusb_context *ctx, libusb_device *dev, libusb_hotplug_event event, void *user_data) {
printf ("Device detached\n");
libusb_close (handle);
done++;
return 0;
}
int main (int argc, char *argv[]) {
libusb_hotplug_callback_handle hp[2];
int product_id, vendor_id, class_id;
int rc;
vendor_id = (argc > 1) ? strtol (argv[1], NULL, 0) : 0x045a;
product_id = (argc > 2) ? strtol (argv[2], NULL, 0) : 0x5005;
class_id = (argc > 3) ? strtol (argv[3], NULL, 0) : LIBUSB_HOTPLUG_MATCH_ANY;
libusb_init (NULL);
if (!libusb_has_capability (LIBUSB_CAP_HAS_HOTPLUG)) {
printf ("Hotplug not supported by this build of libusb\n");
libusb_exit (NULL);
return EXIT_FAILURE;
}
rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, 0, vendor_id,
product_id, class_id, hotplug_callback, NULL, &hp[0]);
if (LIBUSB_SUCCESS != rc) {
fprintf (stderr, "Error registering callback 0\n");
libusb_exit (NULL);
return EXIT_FAILURE;
}
rc = libusb_hotplug_register_callback (NULL, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, 0, vendor_id,
product_id,class_id, hotplug_callback_detach, NULL, &hp[1]);
if (LIBUSB_SUCCESS != rc) {
fprintf (stderr, "Error registering callback 1\n");
libusb_exit (NULL);
return EXIT_FAILURE;
}
while (done < 2) {
libusb_handle_events (NULL);
}
libusb_exit (NULL);
}

64
compat/libusb-1.0/examples/listdevs.c

@ -1,64 +0,0 @@ @@ -1,64 +0,0 @@
/*
* libusb example program to list devices on the bus
* Copyright (C) 2007 Daniel Drake <dsd@gentoo.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <sys/types.h>
#include <libusb.h>
static void print_devs(libusb_device **devs)
{
libusb_device *dev;
int i = 0;
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "failed to get device descriptor");
return;
}
printf("%04x:%04x (bus %d, device %d)\n",
desc.idVendor, desc.idProduct,
libusb_get_bus_number(dev), libusb_get_device_address(dev));
}
}
int main(void)
{
libusb_device **devs;
int r;
ssize_t cnt;
r = libusb_init(NULL);
if (r < 0)
return r;
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0)
return (int) cnt;
print_devs(devs);
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
return 0;
}

193
compat/libusb-1.0/examples/sam3u_benchmark.c

@ -1,193 +0,0 @@ @@ -1,193 +0,0 @@
/*
* libusb example program to measure Atmel SAM3U isochronous performance
* Copyright (C) 2012 Harald Welte <laforge@gnumonks.org>
*
* Copied with the author's permission under LGPL-2.1 from
* http://git.gnumonks.org/cgi-bin/gitweb.cgi?p=sam3u-tests.git;a=blob;f=usb-benchmark-project/host/benchmark.c;h=74959f7ee88f1597286cd435f312a8ff52c56b7e
*
* An Atmel SAM3U test firmware is also available in the above repository.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <libusb.h>
#define EP_DATA_IN 0x82
#define EP_ISO_IN 0x86
static int do_exit = 0;
static struct libusb_device_handle *devh = NULL;
static unsigned long num_bytes = 0, num_xfer = 0;
static struct timeval tv_start;
static void cb_xfr(struct libusb_transfer *xfr)
{
unsigned int i;
if (xfr->status != LIBUSB_TRANSFER_COMPLETED) {
fprintf(stderr, "transfer status %d\n", xfr->status);
libusb_free_transfer(xfr);
exit(3);
}
if (xfr->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
for (i = 0; i < xfr->num_iso_packets; i++) {
struct libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i];
if (pack->status != LIBUSB_TRANSFER_COMPLETED) {
fprintf(stderr, "Error: pack %u status %d\n", i, pack->status);
exit(5);
}
printf("pack%u length:%u, actual_length:%u\n", i, pack->length, pack->actual_length);
}
}
printf("length:%u, actual_length:%u\n", xfr->length, xfr->actual_length);
for (i = 0; i < xfr->actual_length; i++) {
printf("%02x", xfr->buffer[i]);
if (i % 16)
printf("\n");
else if (i % 8)
printf(" ");
else
printf(" ");
}
num_bytes += xfr->actual_length;
num_xfer++;
if (libusb_submit_transfer(xfr) < 0) {
fprintf(stderr, "error re-submitting URB\n");
exit(1);
}
}
static int benchmark_in(uint8_t ep)
{
static uint8_t buf[2048];
static struct libusb_transfer *xfr;
int num_iso_pack = 0;
if (ep == EP_ISO_IN)
num_iso_pack = 16;
xfr = libusb_alloc_transfer(num_iso_pack);
if (!xfr)
return -ENOMEM;
if (ep == EP_ISO_IN) {
libusb_fill_iso_transfer(xfr, devh, ep, buf,
sizeof(buf), num_iso_pack, cb_xfr, NULL, 0);
libusb_set_iso_packet_lengths(xfr, sizeof(buf)/num_iso_pack);
} else
libusb_fill_bulk_transfer(xfr, devh, ep, buf,
sizeof(buf), cb_xfr, NULL, 0);
gettimeofday(&tv_start, NULL);
/* NOTE: To reach maximum possible performance the program must
* submit *multiple* transfers here, not just one.
*
* When only one transfer is submitted there is a gap in the bus
* schedule from when the transfer completes until a new transfer
* is submitted by the callback. This causes some jitter for
* isochronous transfers and loss of throughput for bulk transfers.
*
* This is avoided by queueing multiple transfers in advance, so
* that the host controller is always kept busy, and will schedule
* more transfers on the bus while the callback is running for
* transfers which have completed on the bus.
*/
return libusb_submit_transfer(xfr);
}
static void measure(void)
{
struct timeval tv_stop;
unsigned int diff_msec;
gettimeofday(&tv_stop, NULL);
diff_msec = (tv_stop.tv_sec - tv_start.tv_sec)*1000;
diff_msec += (tv_stop.tv_usec - tv_start.tv_usec)/1000;
printf("%lu transfers (total %lu bytes) in %u miliseconds => %lu bytes/sec\n",
num_xfer, num_bytes, diff_msec, (num_bytes*1000)/diff_msec);
}
static void sig_hdlr(int signum)
{
switch (signum) {
case SIGINT:
measure();
do_exit = 1;
break;
}
}
int main(int argc, char **argv)
{
int rc;
struct sigaction sigact;
sigact.sa_handler = sig_hdlr;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, NULL);
rc = libusb_init(NULL);
if (rc < 0) {
fprintf(stderr, "Error initializing libusb: %s\n", libusb_error_name(rc));
exit(1);
}
devh = libusb_open_device_with_vid_pid(NULL, 0x16c0, 0x0763);
if (!devh) {
fprintf(stderr, "Error finding USB device\n");
goto out;
}
rc = libusb_claim_interface(devh, 2);
if (rc < 0) {
fprintf(stderr, "Error claiming interface: %s\n", libusb_error_name(rc));
goto out;
}
benchmark_in(EP_ISO_IN);
while (!do_exit) {
rc = libusb_handle_events(NULL);
if (rc != LIBUSB_SUCCESS)
break;
}
/* Measurement has already been done by the signal handler. */
libusb_release_interface(devh, 0);
out:
if (devh)
libusb_close(devh);
libusb_exit(NULL);
return rc;
}

256
compat/libusb-1.0/examples/testlibusb1.c

@ -1,256 +0,0 @@ @@ -1,256 +0,0 @@
/*
* Test suite program based of libusb-0.1-compat testlibusb
* Copyright (c) 2013 Nathan Hjelm <hjelmn@mac.ccom>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <string.h>
#include <libusb.h>
int verbose = 0;
static void print_endpoint_comp(const struct libusb_ss_endpoint_companion_descriptor *ep_comp)
{
printf(" USB 3.0 Endpoint Companion:\n");
printf(" bMaxBurst: %d\n", ep_comp->bMaxBurst);
printf(" bmAttributes: 0x%02x\n", ep_comp->bmAttributes);
printf(" wBytesPerInterval: %d\n", ep_comp->wBytesPerInterval);
}
static void print_endpoint(const struct libusb_endpoint_descriptor *endpoint)
{
int i, ret;
printf(" Endpoint:\n");
printf(" bEndpointAddress: %02xh\n", endpoint->bEndpointAddress);
printf(" bmAttributes: %02xh\n", endpoint->bmAttributes);
printf(" wMaxPacketSize: %d\n", endpoint->wMaxPacketSize);
printf(" bInterval: %d\n", endpoint->bInterval);
printf(" bRefresh: %d\n", endpoint->bRefresh);
printf(" bSynchAddress: %d\n", endpoint->bSynchAddress);
for (i = 0 ; i < endpoint->extra_length ; ) {
if (LIBUSB_DT_SS_ENDPOINT_COMPANION == endpoint->extra[i+1]) {
struct libusb_ss_endpoint_companion_descriptor *ep_comp;
ret = libusb_parse_ss_endpoint_comp(endpoint->extra+i, endpoint->extra[0], &ep_comp);
if (LIBUSB_SUCCESS != ret) {
continue;
}
print_endpoint_comp(ep_comp);
libusb_free_ss_endpoint_comp(ep_comp);
}
i += endpoint->extra[i];
}
}
static void print_altsetting(const struct libusb_interface_descriptor *interface)
{
int i;
printf(" Interface:\n");
printf(" bInterfaceNumber: %d\n", interface->bInterfaceNumber);
printf(" bAlternateSetting: %d\n", interface->bAlternateSetting);
printf(" bNumEndpoints: %d\n", interface->bNumEndpoints);
printf(" bInterfaceClass: %d\n", interface->bInterfaceClass);
printf(" bInterfaceSubClass: %d\n", interface->bInterfaceSubClass);
printf(" bInterfaceProtocol: %d\n", interface->bInterfaceProtocol);
printf(" iInterface: %d\n", interface->iInterface);
for (i = 0; i < interface->bNumEndpoints; i++)
print_endpoint(&interface->endpoint[i]);
}
static void print_2_0_ext_cap(struct libusb_usb_2_0_device_capability_descriptor *usb_2_0_ext_cap)
{
printf(" USB 2.0 Extension Capabilities:\n");
printf(" bDevCapabilityType: %d\n", usb_2_0_ext_cap->bDevCapabilityType);
printf(" bmAttributes: 0x%x\n", usb_2_0_ext_cap->bmAttributes);
}
static void print_ss_usb_cap(struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap)
{
printf(" USB 3.0 Capabilities:\n");
printf(" bDevCapabilityType: %d\n", ss_usb_cap->bDevCapabilityType);
printf(" bmAttributes: 0x%x\n", ss_usb_cap->bmAttributes);
printf(" wSpeedSupported: 0x%x\n", ss_usb_cap->wSpeedSupported);
printf(" bFunctionalitySupport: %d\n", ss_usb_cap->bFunctionalitySupport);
printf(" bU1devExitLat: %d\n", ss_usb_cap->bU1DevExitLat);
printf(" bU2devExitLat: %d\n", ss_usb_cap->bU2DevExitLat);
}
static void print_bos(libusb_device_handle *handle)
{
unsigned char buffer[128];
struct libusb_bos_descriptor *bos;
int ret;
ret = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, buffer, 128);
if (0 > ret) {
return;
}
ret = libusb_parse_bos_descriptor(buffer, 128, &bos);
if (0 > ret) {
return;
}
printf(" Binary Object Store (BOS):\n");
printf(" wTotalLength: %d\n", bos->wTotalLength);
printf(" bNumDeviceCaps: %d\n", bos->bNumDeviceCaps);
if (bos->usb_2_0_ext_cap) {
print_2_0_ext_cap(bos->usb_2_0_ext_cap);
}
if (bos->ss_usb_cap) {
print_ss_usb_cap(bos->ss_usb_cap);
}
}
static void print_interface(const struct libusb_interface *interface)
{
int i;
for (i = 0; i < interface->num_altsetting; i++)
print_altsetting(&interface->altsetting[i]);
}
static void print_configuration(struct libusb_config_descriptor *config)
{
int i;
printf(" Configuration:\n");
printf(" wTotalLength: %d\n", config->wTotalLength);
printf(" bNumInterfaces: %d\n", config->bNumInterfaces);
printf(" bConfigurationValue: %d\n", config->bConfigurationValue);
printf(" iConfiguration: %d\n", config->iConfiguration);
printf(" bmAttributes: %02xh\n", config->bmAttributes);
printf(" MaxPower: %d\n", config->MaxPower);
for (i = 0; i < config->bNumInterfaces; i++)
print_interface(&config->interface[i]);
}
static int print_device(libusb_device *dev, int level)
{
struct libusb_device_descriptor desc;
libusb_device_handle *handle = NULL;
char description[256];
char string[256];
int ret, i;
ret = libusb_get_device_descriptor(dev, &desc);
if (ret < 0) {
fprintf(stderr, "failed to get device descriptor");
return -1;
}
ret = libusb_open(dev, &handle);
if (LIBUSB_SUCCESS == ret) {
if (desc.iManufacturer) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, string, sizeof(string));
if (ret > 0)
snprintf(description, sizeof(description), "%s - ", string);
else
snprintf(description, sizeof(description), "%04X - ",
desc.idVendor);
} else
snprintf(description, sizeof(description), "%04X - ",
desc.idVendor);
if (desc.iProduct) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iProduct, string, sizeof(string));
if (ret > 0)
snprintf(description + strlen(description), sizeof(description) -
strlen(description), "%s", string);
else
snprintf(description + strlen(description), sizeof(description) -
strlen(description), "%04X", desc.idProduct);
} else
snprintf(description + strlen(description), sizeof(description) -
strlen(description), "%04X", desc.idProduct);
} else {
snprintf(description, sizeof(description), "%04X - %04X",
desc.idVendor, desc.idProduct);
}
printf("%.*sDev (bus %d, device %d): %s\n", level * 2, " ",
libusb_get_bus_number(dev), libusb_get_device_address(dev), description);
if (handle && verbose) {
if (desc.iSerialNumber) {
ret = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, string, sizeof(string));
if (ret > 0)
printf("%.*s - Serial Number: %s\n", level * 2,
" ", string);
}
}
if (verbose) {
for (i = 0; i < desc.bNumConfigurations; i++) {
struct libusb_config_descriptor *config;
ret = libusb_get_config_descriptor(dev, i, &config);
if (LIBUSB_SUCCESS != ret) {
printf(" Couldn't retrieve descriptors\n");
continue;
}
print_configuration(config);
libusb_free_config_descriptor(config);
}
if (handle && desc.bcdUSB >= 0x0201) {
print_bos(handle);
}
}
if (handle)
libusb_close(handle);
return 0;
}
int main(int argc, char *argv[])
{
libusb_device **devs;
ssize_t cnt;
int r, i;
if (argc > 1 && !strcmp(argv[1], "-v"))
verbose = 1;
r = libusb_init(NULL);
if (r < 0)
return r;
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0)
return (int) cnt;
for (i = 0 ; devs[i] ; ++i) {
print_device(devs[i], 0);
}
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
return 0;
}

8
configure.ac

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
m4_define([v_maj], [3])
m4_define([v_min], [5])
m4_define([v_mic], [0])
m4_define([v_min], [6])
m4_define([v_mic], [3])
##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
m4_define([v_ver], [v_maj.v_min.v_mic])
m4_define([lt_rev], m4_eval(v_maj + v_min))
@ -359,7 +359,8 @@ else @@ -359,7 +359,8 @@ else
LIBUSB_LIBS=""
fi
JANSSON_LIBS="compat/jansson/libjansson.a"
AC_CONFIG_SUBDIRS([compat/jansson-2.5])
JANSSON_LIBS="compat/jansson-2.5/src/.libs/libjansson.a"
PKG_PROG_PKG_CONFIG()
@ -466,7 +467,6 @@ AC_SUBST(ADL_CPPFLAGS) @@ -466,7 +467,6 @@ AC_SUBST(ADL_CPPFLAGS)
AC_CONFIG_FILES([
Makefile
compat/Makefile
compat/jansson/Makefile
ccan/Makefile
lib/Makefile
])

91
driver-avalon.c

@ -49,6 +49,7 @@ int opt_avalon_fan_max = AVALON_DEFAULT_FAN_MAX_PWM; @@ -49,6 +49,7 @@ int opt_avalon_fan_max = AVALON_DEFAULT_FAN_MAX_PWM;
int opt_avalon_freq_min = AVALON_MIN_FREQUENCY;
int opt_avalon_freq_max = AVALON_MAX_FREQUENCY;
int opt_bitburner_core_voltage = BITBURNER_DEFAULT_CORE_VOLTAGE;
int opt_bitburner_fury_core_voltage = BITBURNER_FURY_DEFAULT_CORE_VOLTAGE;
bool opt_avalon_auto;
static int option_offset = -1;
@ -209,6 +210,55 @@ static int avalon_send_task(const struct avalon_task *at, struct cgpu_info *aval @@ -209,6 +210,55 @@ static int avalon_send_task(const struct avalon_task *at, struct cgpu_info *aval
return ret;
}
static int bitburner_send_task(const struct avalon_task *at, struct cgpu_info *avalon)
{
uint8_t buf[AVALON_WRITE_SIZE + 4 * AVALON_DEFAULT_ASIC_NUM];
int ret, ep = C_AVALON_TASK;
cgtimer_t ts_start;
size_t nr_len;
if (at->nonce_elf)
nr_len = AVALON_WRITE_SIZE + 4 * at->asic_num;
else
nr_len = AVALON_WRITE_SIZE;
memset(buf, 0, nr_len);
memcpy(buf, at, AVALON_WRITE_SIZE);
#if defined(__BIG_ENDIAN__) || defined(MIPSEB)
uint8_t tt = 0;
tt = (buf[0] & 0x0f) << 4;
tt |= ((buf[0] & 0x10) ? (1 << 3) : 0);
tt |= ((buf[0] & 0x20) ? (1 << 2) : 0);
tt |= ((buf[0] & 0x40) ? (1 << 1) : 0);
tt |= ((buf[0] & 0x80) ? (1 << 0) : 0);
buf[0] = tt;
tt = (buf[4] & 0x0f) << 4;
tt |= ((buf[4] & 0x10) ? (1 << 3) : 0);
tt |= ((buf[4] & 0x20) ? (1 << 2) : 0);
tt |= ((buf[4] & 0x40) ? (1 << 1) : 0);
tt |= ((buf[4] & 0x80) ? (1 << 0) : 0);
buf[4] = tt;
#endif
if (at->reset) {
ep = C_AVALON_RESET;
nr_len = 1;
}
if (opt_debug) {
applog(LOG_DEBUG, "Avalon: Sent(%u):", (unsigned int)nr_len);
hexdump(buf, nr_len);
}
cgsleep_prepare_r(&ts_start);
ret = avalon_write(avalon, (char *)buf, nr_len, ep);
cgsleep_us_r(&ts_start, 3000); // 3 ms = 333 tasks per second, or 1.4 TH/s
return ret;
}
static bool avalon_decode_nonce(struct thr_info *thr, struct cgpu_info *avalon,
struct avalon_info *info, struct avalon_result *ar,
struct work *work)
@ -414,12 +464,12 @@ static bool get_options(int this_option_offset, int *baud, int *miner_count, @@ -414,12 +464,12 @@ static bool get_options(int this_option_offset, int *baud, int *miner_count,
if (*colon) {
tmp = atoi(colon);
if (tmp > 0 && tmp <= AVALON_DEFAULT_MINER_NUM) {
if (tmp > 0 && tmp <= AVALON_MAX_MINER_NUM) {
*miner_count = tmp;
} else {
quit(1, "Invalid avalon-options for "
"miner_count (%s) must be 1 ~ %d",
colon, AVALON_DEFAULT_MINER_NUM);
colon, AVALON_MAX_MINER_NUM);
}
}
@ -620,12 +670,20 @@ static void avalon_initialise(struct cgpu_info *avalon) @@ -620,12 +670,20 @@ static void avalon_initialise(struct cgpu_info *avalon)
avalon->drv->name, avalon->device_id, err);
}
static bool is_bitburner(struct cgpu_info *avalon)
{
enum sub_ident ident;
ident = usb_ident(avalon);
return ident == IDENT_BTB || ident == IDENT_BBF;
}
static bool bitburner_set_core_voltage(struct cgpu_info *avalon, int core_voltage)
{
uint8_t buf[2];
int err;
if (usb_ident(avalon) == IDENT_BTB) {
if (is_bitburner(avalon)) {
buf[0] = (uint8_t)core_voltage;
buf[1] = (uint8_t)(core_voltage >> 8);
err = usb_transfer_data(avalon, FTDI_TYPE_OUT, BITBURNER_REQUEST,
@ -651,7 +709,7 @@ static int bitburner_get_core_voltage(struct cgpu_info *avalon) @@ -651,7 +709,7 @@ static int bitburner_get_core_voltage(struct cgpu_info *avalon)
int err;
int amount;
if (usb_ident(avalon) == IDENT_BTB) {
if (is_bitburner(avalon)) {
err = usb_transfer_read(avalon, FTDI_TYPE_IN, BITBURNER_REQUEST,
BITBURNER_VALUE, BITBURNER_INDEX_GET_VOLTAGE,
(char *)buf, sizeof(buf), &amount,
@ -780,7 +838,18 @@ static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found @@ -780,7 +838,18 @@ static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found
BITBURNER_MAX_COREMV);
} else
bitburner_set_core_voltage(avalon, opt_bitburner_core_voltage);
} else if (usb_ident(avalon) == IDENT_BBF) {
if (opt_bitburner_fury_core_voltage < BITBURNER_FURY_MIN_COREMV ||
opt_bitburner_fury_core_voltage > BITBURNER_FURY_MAX_COREMV) {
quit(1, "Invalid bitburner-fury-voltage %d must be %dmv - %dmv",
opt_bitburner_fury_core_voltage,
BITBURNER_FURY_MIN_COREMV,
BITBURNER_FURY_MAX_COREMV);
} else
bitburner_set_core_voltage(avalon, opt_bitburner_fury_core_voltage);
}
if (is_bitburner(avalon)) {
bitburner_get_version(avalon);
}
@ -1181,7 +1250,7 @@ static void *bitburner_send_tasks(void *userdata) @@ -1181,7 +1250,7 @@ static void *bitburner_send_tasks(void *userdata)
avalon_reset_auto(info);
}
ret = avalon_send_task(&at, avalon);
ret = bitburner_send_task(&at, avalon);
if (unlikely(ret == AVA_SEND_ERROR)) {
applog(LOG_ERR, "%s%i: Comms error(buffer)",
@ -1211,7 +1280,7 @@ static bool avalon_prepare(struct thr_info *thr) @@ -1211,7 +1280,7 @@ static bool avalon_prepare(struct thr_info *thr)
int array_size = AVALON_ARRAY_SIZE;
void *(*write_thread_fn)(void *) = avalon_send_tasks;
if (usb_ident(avalon) == IDENT_BTB) {
if (is_bitburner(avalon)) {
array_size = BITBURNER_ARRAY_SIZE;
write_thread_fn = bitburner_send_tasks;
}
@ -1356,7 +1425,7 @@ static void avalon_update_temps(struct cgpu_info *avalon, struct avalon_info *in @@ -1356,7 +1425,7 @@ static void avalon_update_temps(struct cgpu_info *avalon, struct avalon_info *in
info->temp_sum += avalon->temp;
applog(LOG_DEBUG, "Avalon: temp_index: %d, temp_count: %d, temp_old: %d",
info->temp_history_index, info->temp_history_count, info->temp_old);
if (usb_ident(avalon) == IDENT_BTB) {
if (is_bitburner(avalon)) {
info->core_voltage = bitburner_get_core_voltage(avalon);
}
if (info->temp_history_index == info->temp_history_count) {
@ -1378,7 +1447,7 @@ static void get_avalon_statline_before(char *buf, size_t bufsiz, struct cgpu_inf @@ -1378,7 +1447,7 @@ static void get_avalon_statline_before(char *buf, size_t bufsiz, struct cgpu_inf
struct avalon_info *info = avalon->device_data;
int lowfan = 10000;
if (usb_ident(avalon) == IDENT_BTB) {
if (is_bitburner(avalon)) {
int temp = info->temp0;
if (info->temp2 > temp)
temp = info->temp2;
@ -1464,7 +1533,7 @@ static int64_t avalon_scanhash(struct thr_info *thr) @@ -1464,7 +1533,7 @@ static int64_t avalon_scanhash(struct thr_info *thr)
/* Check for nothing but consecutive bad results or consistently less
* results than we should be getting and reset the FPGA if necessary */
if (usb_ident(avalon) != IDENT_BTB) {
if (!is_bitburner(avalon)) {
if (avalon->results < -miner_count && !info->reset) {
applog(LOG_ERR, "%s%d: Result return rate low, resetting!",
avalon->drv->name, avalon->device_id);
@ -1525,7 +1594,7 @@ static struct api_data *avalon_api_stats(struct cgpu_info *cgpu) @@ -1525,7 +1594,7 @@ static struct api_data *avalon_api_stats(struct cgpu_info *cgpu)
sprintf(mcw, "match_work_count%d", i + 1);
root = api_add_int(root, mcw, &(info->matching_work[i]), false);
}
if (usb_ident(cgpu) == IDENT_BTB) {
if (is_bitburner(cgpu)) {
root = api_add_int(root, "core_voltage", &(info->core_voltage), false);
snprintf(buf, sizeof(buf), "%"PRIu8".%"PRIu8".%"PRIu8,
info->version1, info->version2, info->version3);
@ -1553,7 +1622,7 @@ static char *avalon_set_device(struct cgpu_info *avalon, char *option, char *set @@ -1553,7 +1622,7 @@ static char *avalon_set_device(struct cgpu_info *avalon, char *option, char *set
}
if (strcasecmp(option, "millivolts") == 0 || strcasecmp(option, "mv") == 0) {
if (usb_ident(avalon) != IDENT_BTB) {
if (!is_bitburner(avalon)) {
sprintf(replybuf, "%s cannot set millivolts", avalon->drv->name);
return replybuf;
}

11
driver-avalon.h

@ -33,11 +33,18 @@ @@ -33,11 +33,18 @@
#define AVALON_TEMP_HYSTERESIS 3
#define AVALON_TEMP_OVERHEAT 60
/* Avalon-based BitBurner. */
#define BITBURNER_DEFAULT_CORE_VOLTAGE 1200 /* in millivolts */
#define BITBURNER_MIN_COREMV 1000
/* change here if you want to risk killing it :) */
#define BITBURNER_MAX_COREMV 1400
/* BitFury-based BitBurner. */
#define BITBURNER_FURY_DEFAULT_CORE_VOLTAGE 900 /* in millivolts */
#define BITBURNER_FURY_MIN_COREMV 700
/* change here if you want to risk killing it :) */
#define BITBURNER_FURY_MAX_COREMV 1100
#define AVALON_DEFAULT_TIMEOUT 0x2D
#define AVALON_MIN_FREQUENCY 256
@ -45,6 +52,7 @@ @@ -45,6 +52,7 @@
#define AVALON_TIMEOUT_FACTOR 12690
#define AVALON_DEFAULT_FREQUENCY 282
#define AVALON_DEFAULT_MINER_NUM 0x20
#define AVALON_MAX_MINER_NUM 0x100
#define AVALON_DEFAULT_ASIC_NUM 0xA
#define AVALON_AUTO_CYCLE 1024
@ -122,7 +130,7 @@ struct avalon_info { @@ -122,7 +130,7 @@ struct avalon_info {
int core_voltage;
int no_matching_work;
int matching_work[AVALON_DEFAULT_MINER_NUM];
int matching_work[AVALON_MAX_MINER_NUM];
int frequency;
uint32_t ctlr_ver;
@ -179,6 +187,7 @@ extern int opt_avalon_freq_min; @@ -179,6 +187,7 @@ extern int opt_avalon_freq_min;
extern int opt_avalon_freq_max;
extern bool opt_avalon_auto;
extern int opt_bitburner_core_voltage;
extern int opt_bitburner_fury_core_voltage;
extern char *set_avalon_fan(char *arg);
extern char *set_avalon_freq(char *arg);

26
driver-bflsc.c

@ -645,18 +645,23 @@ static bool getinfo(struct cgpu_info *bflsc, int dev) @@ -645,18 +645,23 @@ static bool getinfo(struct cgpu_info *bflsc, int dev)
else if (strstr(firstname, BFLSC_DI_XLINKPRESENT))
sc_dev.xlink_present = strdup(fields[0]);
else if (strstr(firstname, BFLSC_DI_DEVICESINCHAIN)) {
sc_info->sc_count = atoi(fields[0]);
if (fields[0][0] == '0' ||
(fields[0][0] == ' ' && fields[0][1] == '0'))
sc_info->sc_count = 1;
else
sc_info->sc_count = atoi(fields[0]);
if (sc_info->sc_count < 1 || sc_info->sc_count > 30) {
tmp = str_text(items[i]);
applogsiz(LOG_WARNING, BFLSC_APPLOGSIZ,
"%s detect (%s) invalid s-link count: '%s'",
"%s detect (%s) invalid x-link count: '%s'",
bflsc->drv->dname, bflsc->device_path, tmp);
free(tmp);
goto mata;
}
}
else if (strstr(firstname, BFLSC_DI_CHIPS))
sc_dev.chips = strdup(fields[0]);
}
freebreakdown(&count, &firstname, &fields);
}
@ -813,6 +818,19 @@ reinit: @@ -813,6 +818,19 @@ reinit:
break;
}
// Set parallelization based on the getinfo() response if it is present
if (sc_info->sc_devs[0].chips && strlen(sc_info->sc_devs[0].chips)) {
if (strstr(sc_info->sc_devs[0].chips, BFLSC_DI_CHIPS_PARALLEL)) {
sc_info->que_noncecount = QUE_NONCECOUNT_V2;
sc_info->que_fld_min = QUE_FLD_MIN_V2;
sc_info->que_fld_max = QUE_FLD_MAX_V2;
} else {
sc_info->que_noncecount = QUE_NONCECOUNT_V1;
sc_info->que_fld_min = QUE_FLD_MIN_V1;
sc_info->que_fld_max = QUE_FLD_MAX_V1;
}
}
sc_info->scan_sleep_time = BAS_SCAN_TIME;
sc_info->results_sleep_time = BFLSC_RES_TIME;
sc_info->default_ms_work = BAS_WORK_TIME;
@ -930,7 +948,7 @@ static void flush_one_dev(struct cgpu_info *bflsc, int dev) @@ -930,7 +948,7 @@ static void flush_one_dev(struct cgpu_info *bflsc, int dev)
rd_lock(&bflsc->qlock);
HASH_ITER(hh, bflsc->queued_work, work, tmp) {
if (work->queued && work->subid == dev) {
if (work->subid == dev) {
// devflag is used to flag stale work
work->devflag = true;
did = true;

1
driver-bflsc.h

@ -59,6 +59,7 @@ enum driver_version { @@ -59,6 +59,7 @@ enum driver_version {
#define BFLSC_DI_DEVICESINCHAIN "DEVICES IN CHAIN"
#define BFLSC_DI_CHAINPRESENCE "CHAIN PRESENCE MASK"
#define BFLSC_DI_CHIPS "CHIP PARALLELIZATION"
#define BFLSC_DI_CHIPS_PARALLEL "YES"
#define FULLNONCE 0x100000000ULL

20
driver-icarus.c

@ -1116,8 +1116,7 @@ static void cmr2_commands(struct cgpu_info *icarus) @@ -1116,8 +1116,7 @@ static void cmr2_commands(struct cgpu_info *icarus)
}
}
static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
__maybe_unused int64_t max_nonce)
static int64_t icarus_scanwork(struct thr_info *thr)
{
struct cgpu_info *icarus = thr->cgpu;
struct ICARUS_INFO *info = (struct ICARUS_INFO *)(icarus->device_data);
@ -1126,12 +1125,13 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, @@ -1126,12 +1125,13 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
struct ICARUS_WORK workdata;
char *ob_hex;
uint32_t nonce;
int64_t hash_count;
int64_t hash_count = 0;
struct timeval tv_start, tv_finish, elapsed;
struct timeval tv_history_start, tv_history_finish;
double Ti, Xi;
int curr_hw_errors, i;
bool was_hw_error;
struct work *work;
struct ICARUS_HISTORY *history0, *history;
int count;
@ -1148,6 +1148,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, @@ -1148,6 +1148,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
elapsed.tv_sec = elapsed.tv_usec = 0;
work = get_work(thr, thr->id);
memset((void *)(&workdata), 0, sizeof(workdata));
memcpy(&(workdata.midstate), work->midstate, ICARUS_MIDSTATE_SIZE);
memcpy(&(workdata.work), work->data + ICARUS_WORK_DATA_OFFSET, ICARUS_WORK_SIZE);
@ -1166,7 +1167,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, @@ -1166,7 +1167,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
icarus->drv->name, icarus->device_id, err, amount);
dev_error(icarus, REASON_DEV_COMMS_ERROR);
icarus_initialise(icarus, info->baud);
return 0;
goto out;
}
if (opt_debug) {
@ -1180,7 +1181,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, @@ -1180,7 +1181,7 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
memset(nonce_bin, 0, sizeof(nonce_bin));
ret = icarus_get_nonce(icarus, nonce_bin, &tv_start, &tv_finish, thr, info->read_time);
if (ret == ICA_NONCE_ERROR)
return 0;
goto out;
work->blk.nonce = 0xffffffff;
@ -1203,7 +1204,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, @@ -1203,7 +1204,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
(long unsigned int)estimate_hashes,
elapsed.tv_sec, elapsed.tv_usec);
return estimate_hashes;
hash_count = estimate_hashes;
goto out;
}
memcpy((char *)&nonce, nonce_bin, sizeof(nonce_bin));
@ -1343,7 +1345,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work, @@ -1343,7 +1345,8 @@ static int64_t icarus_scanhash(struct thr_info *thr, struct work *work,
timersub(&tv_history_finish, &tv_history_start, &tv_history_finish);
timeradd(&tv_history_finish, &(info->history_time), &(info->history_time));
}
out:
free_work(work);
return hash_count;
}
@ -1447,11 +1450,12 @@ struct device_drv icarus_drv = { @@ -1447,11 +1450,12 @@ struct device_drv icarus_drv = {
.dname = "Icarus",
.name = "ICA",
.drv_detect = icarus_detect,
.hash_work = &hash_driver_work,
.get_api_stats = icarus_api_stats,
.get_statline_before = icarus_statline_before,
.set_device = icarus_set,
.identify_device = icarus_identify,
.thread_prepare = icarus_prepare,
.scanhash = icarus_scanhash,
.scanwork = icarus_scanwork,
.thread_shutdown = icarus_shutdown,
};

282
driver-klondike.c

@ -44,6 +44,20 @@ @@ -44,6 +44,20 @@
#define MAX_WORK_COUNT 4 // for now, must be binary multiple and match firmware
#define TACH_FACTOR 87890 // fan rpm divisor
/*
* Work older than 5s will already be completed
* FYI it must not be possible to complete 256 work
* items this quickly on a single device -
* thus limited to 219.9GH/s per device
*/
#define OLD_WORK_MS ((int)(5 * 1000))
/*
* If the queue status hasn't been updated for this long
* then do it now
*/
#define LATE_UPDATE_MS ((int)(4 * 1000))
struct device_drv klondike_drv;
typedef struct klondike_header {
@ -152,6 +166,11 @@ typedef struct klist { @@ -152,6 +166,11 @@ typedef struct klist {
bool working;
} KLIST;
typedef struct jobque {
int workqc;
struct timeval last_update;
} JOBQUE;
struct klondike_info {
bool shutdown;
pthread_rwlock_t stat_lock;
@ -165,6 +184,7 @@ struct klondike_info { @@ -165,6 +184,7 @@ struct klondike_info {
KLIST *status;
DEVINFO *devinfo;
KLIST *cfg;
JOBQUE *jobque;
int noncecount;
uint64_t hashcount;
uint64_t errorcount;
@ -183,6 +203,11 @@ struct klondike_info { @@ -183,6 +203,11 @@ struct klondike_info {
double nonce_total;
double nonce_min;
double nonce_max;
int wque_size;
int wque_cleared;
bool initialised;
};
static KLIST *new_klist_set(struct cgpu_info *klncgpu)
@ -254,7 +279,7 @@ static KLIST *allocate_kitem(struct cgpu_info *klncgpu) @@ -254,7 +279,7 @@ static KLIST *allocate_kitem(struct cgpu_info *klncgpu)
return kitem;
}
static void release_kitem(struct cgpu_info *klncgpu, KLIST *kitem)
static KLIST *release_kitem(struct cgpu_info *klncgpu, KLIST *kitem)
{
struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
@ -279,6 +304,8 @@ static void release_kitem(struct cgpu_info *klncgpu, KLIST *kitem) @@ -279,6 +304,8 @@ static void release_kitem(struct cgpu_info *klncgpu, KLIST *kitem)
klninfo->used_count--;
cg_wunlock(&klninfo->klist_lock);
return NULL;
}
static double cvtKlnToC(uint8_t temp)
@ -455,7 +482,9 @@ static bool klondike_get_stats(struct cgpu_info *klncgpu) @@ -455,7 +482,9 @@ static bool klondike_get_stats(struct cgpu_info *klncgpu)
applog(LOG_DEBUG, "Klondike getting status");
rd_lock(&(klninfo->stat_lock));
slaves = klninfo->status[0].kline.ws.slavecount;
rd_unlock(&(klninfo->stat_lock));
// loop thru devices and get status for each
for (dev = 0; dev <= slaves; dev++) {
@ -464,10 +493,11 @@ static bool klondike_get_stats(struct cgpu_info *klncgpu) @@ -464,10 +493,11 @@ static bool klondike_get_stats(struct cgpu_info *klncgpu)
kitem = SendCmdGetReply(klncgpu, &kline, 0);
if (kitem != NULL) {
wr_lock(&(klninfo->stat_lock));
memcpy((void *)(&(klninfo->status[dev])), (void *)kitem, sizeof(*kitem));
memcpy((void *)(&(klninfo->status[dev])),
(void *)kitem,
sizeof(klninfo->status[dev]));
wr_unlock(&(klninfo->stat_lock));
release_kitem(klncgpu, kitem);
kitem = NULL;
kitem = release_kitem(klncgpu, kitem);
}
}
@ -483,6 +513,8 @@ static bool klondike_init(struct cgpu_info *klncgpu) @@ -483,6 +513,8 @@ static bool klondike_init(struct cgpu_info *klncgpu)
KLINE kline;
int slaves, dev;
klninfo->initialised = false;
kline.hd.cmd = 'S';
kline.hd.dev = 0;
kitem = SendCmdGetReply(klncgpu, &kline, 0);
@ -490,23 +522,27 @@ static bool klondike_init(struct cgpu_info *klncgpu) @@ -490,23 +522,27 @@ static bool klondike_init(struct cgpu_info *klncgpu)
return false;
slaves = kitem->kline.ws.slavecount;
release_kitem(klncgpu, kitem);
kitem = NULL;
if (klninfo->status == NULL) {
applog(LOG_DEBUG, "Klondike initializing data");
// alloc space for status, devinfo and cfg for master and slaves
klninfo->status = calloc(slaves+1, sizeof(KLIST));
// alloc space for status, devinfo, cfg and jobque for master and slaves
klninfo->status = calloc(slaves+1, sizeof(*(klninfo->status)));
if (unlikely(!klninfo->status))
quit(1, "Failed to calloc status array in klondke_get_stats");
klninfo->devinfo = calloc(slaves+1, sizeof(DEVINFO));
klninfo->devinfo = calloc(slaves+1, sizeof(*(klninfo->devinfo)));
if (unlikely(!klninfo->devinfo))
quit(1, "Failed to calloc devinfo array in klondke_get_stats");
klninfo->cfg = calloc(slaves+1, sizeof(KLIST));
klninfo->cfg = calloc(slaves+1, sizeof(*(klninfo->cfg)));
if (unlikely(!klninfo->cfg))
quit(1, "Failed to calloc cfg array in klondke_get_stats");
klninfo->jobque = calloc(slaves+1, sizeof(*(klninfo->jobque)));
if (unlikely(!klninfo->jobque))
quit(1, "Failed to calloc jobque array in klondke_get_stats");
}
memcpy((void *)(&(klninfo->status[0])), (void *)kitem, sizeof(klninfo->status[0]));
kitem = release_kitem(klncgpu, kitem);
// zero init triggers read back only
memset(&(kline.cfg), 0, sizeof(kline.cfg));
kline.cfg.cmd = 'C';
@ -533,17 +569,17 @@ static bool klondike_init(struct cgpu_info *klncgpu) @@ -533,17 +569,17 @@ static bool klondike_init(struct cgpu_info *klncgpu)
kline.cfg.dev = dev;
kitem = SendCmdGetReply(klncgpu, &kline, size);
if (kitem != NULL) {
memcpy((void *)&(klninfo->cfg[dev]), kitem, sizeof(*kitem));
memcpy((void *)&(klninfo->cfg[dev]), kitem, sizeof(klninfo->cfg[dev]));
applog(LOG_WARNING, "Klondike config (%d: Clk: %d, T:%.0lf, C:%.0lf, F:%d)",
dev, K_HASHCLOCK(klninfo->cfg[dev].kline.cfg.hashclock),
cvtKlnToC(klninfo->cfg[dev].kline.cfg.temptarget),
cvtKlnToC(klninfo->cfg[dev].kline.cfg.tempcritical),
(int)100*klninfo->cfg[dev].kline.cfg.fantarget/256);
release_kitem(klncgpu, kitem);
kitem = NULL;
kitem = release_kitem(klncgpu, kitem);
}
}
klondike_get_stats(klncgpu);
klninfo->initialised = true;
for (dev = 0; dev <= slaves; dev++) {
klninfo->devinfo[dev].rangesize = ((uint64_t)1<<32) / klninfo->status[dev].kline.ws.chipcount;
klninfo->devinfo[dev].chipstats = calloc(klninfo->status[dev].kline.ws.chipcount*2 , sizeof(uint32_t));
@ -559,12 +595,13 @@ static bool klondike_init(struct cgpu_info *klncgpu) @@ -559,12 +595,13 @@ static bool klondike_init(struct cgpu_info *klncgpu)
while (tries-- > 0) {
kitem = SendCmdGetReply(klncgpu, &kline, 1);
if (kitem) {
release_kitem(klncgpu, kitem);
kitem = NULL;
kitem = release_kitem(klncgpu, kitem);
ok = true;
break;
}
cgsleep_ms(50);
}
cgsleep_ms(50);
if (!ok)
applog(LOG_ERR, "%s%i: failed to enable", klncgpu->drv->name, klncgpu->device_id);
@ -572,6 +609,21 @@ static bool klondike_init(struct cgpu_info *klncgpu) @@ -572,6 +609,21 @@ static bool klondike_init(struct cgpu_info *klncgpu)
return ok;
}
static void control_init(struct cgpu_info *klncgpu)
{
int err, interface;
if (klncgpu->usbinfo.nodev)
return;
interface = usb_interface(klncgpu);
err = usb_transfer(klncgpu, 0, 9, 1, interface, C_RESET);
applog(LOG_DEBUG, "%s%i: reset got err %d",
klncgpu->drv->name, klncgpu->device_id, err);
}
static bool klondike_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
{
struct cgpu_info *klncgpu = usb_alloc_cgpu(&klondike_drv, 1);
@ -592,6 +644,8 @@ static bool klondike_detect_one(struct libusb_device *dev, struct usb_find_devic @@ -592,6 +644,8 @@ static bool klondike_detect_one(struct libusb_device *dev, struct usb_find_devic
KLIST kitem;
int attempts = 0;
control_init(klncgpu);
while (attempts++ < 3) {
err = usb_write(klncgpu, "I", 2, &sent, C_REQUESTRESULTS);
if (err < 0 || sent != 2) {
@ -613,10 +667,11 @@ static bool klondike_detect_one(struct libusb_device *dev, struct usb_find_devic @@ -613,10 +667,11 @@ static bool klondike_detect_one(struct libusb_device *dev, struct usb_find_devic
klncgpu->device_path,
recd);
} else if (kitem.kline.hd.cmd == 'I' && kitem.kline.hd.dev == 0) {
display_kline(klncgpu, &kitem.kline);
applog(LOG_DEBUG, "%s (%s) detect successful",
display_kline(klncgpu, &kitem.kline);
applog(LOG_DEBUG, "%s (%s) detect successful (%d attempt%s)",
klncgpu->drv->dname,
klncgpu->device_path);
klncgpu->device_path,
attempts, attempts == 1 ? "" : "s");
if (!add_cgpu(klncgpu))
break;
update_usb_stats(klncgpu);
@ -652,7 +707,7 @@ static void klondike_identify(__maybe_unused struct cgpu_info *klncgpu) @@ -652,7 +707,7 @@ static void klondike_identify(__maybe_unused struct cgpu_info *klncgpu)
static void klondike_check_nonce(struct cgpu_info *klncgpu, KLIST *kitem)
{
struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
struct work *work, *tmp;
struct work *work, *look, *tmp;
KLINE *kline = &(kitem->kline);
struct timeval tv_now;
double us_diff;
@ -661,43 +716,54 @@ static void klondike_check_nonce(struct cgpu_info *klncgpu, KLIST *kitem) @@ -661,43 +716,54 @@ static void klondike_check_nonce(struct cgpu_info *klncgpu, KLIST *kitem)
applog(LOG_DEBUG, "Klondike FOUND NONCE (%02x:%08x)",
kline->wr.workid, (unsigned int)nonce);
HASH_ITER(hh, klncgpu->queued_work, work, tmp) {
if (work->queued && (work->subid == (kline->wr.dev*256 + kline->wr.workid))) {
work = NULL;
cgtime(&tv_now);
rd_lock(&(klncgpu->qlock));
HASH_ITER(hh, klncgpu->queued_work, look, tmp) {
if (ms_tdiff(&tv_now, &(look->tv_stamp)) < OLD_WORK_MS &&
(look->subid == (kline->wr.dev*256 + kline->wr.workid))) {
work = look;
break;
}
}
rd_unlock(&(klncgpu->qlock));
wr_lock(&(klninfo->stat_lock));
klninfo->devinfo[kline->wr.dev].noncecount++;
klninfo->noncecount++;
wr_unlock(&(klninfo->stat_lock));
if (work) {
wr_lock(&(klninfo->stat_lock));
klninfo->devinfo[kline->wr.dev].noncecount++;
klninfo->noncecount++;
wr_unlock(&(klninfo->stat_lock));
// kline->wr.nonce = le32toh(kline->wr.nonce - 0xC0);
applog(LOG_DEBUG, "Klondike SUBMIT NONCE (%02x:%08x)",
kline->wr.workid, (unsigned int)nonce);
// kline->wr.nonce = le32toh(kline->wr.nonce - 0xC0);
applog(LOG_DEBUG, "Klondike SUBMIT NONCE (%02x:%08x)",
kline->wr.workid, (unsigned int)nonce);
cgtime(&tv_now);
bool ok = submit_nonce(klncgpu->thr[0], work, nonce);
cgtime(&tv_now);
bool ok = submit_nonce(klncgpu->thr[0], work, nonce);
applog(LOG_DEBUG, "Klondike chip stats %d, %08x, %d, %d",
kline->wr.dev, (unsigned int)nonce,
klninfo->devinfo[kline->wr.dev].rangesize,
klninfo->status[kline->wr.dev].kline.ws.chipcount);
applog(LOG_DEBUG, "Klondike chip stats %d, %08x, %d, %d",
kline->wr.dev, (unsigned int)nonce,
klninfo->devinfo[kline->wr.dev].rangesize,
klninfo->status[kline->wr.dev].kline.ws.chipcount);
klninfo->devinfo[kline->wr.dev].chipstats[(nonce / klninfo->devinfo[kline->wr.dev].rangesize) + (ok ? 0 : klninfo->status[kline->wr.dev].kline.ws.chipcount)]++;
klninfo->devinfo[kline->wr.dev].chipstats[(nonce / klninfo->devinfo[kline->wr.dev].rangesize) + (ok ? 0 : klninfo->status[kline->wr.dev].kline.ws.chipcount)]++;
us_diff = us_tdiff(&tv_now, &(kitem->tv_when));
if (klninfo->delay_count == 0) {
us_diff = us_tdiff(&tv_now, &(kitem->tv_when));
if (klninfo->delay_count == 0) {
klninfo->delay_min = us_diff;
klninfo->delay_max = us_diff;
} else {
if (klninfo->delay_min > us_diff)
klninfo->delay_min = us_diff;
if (klninfo->delay_max < us_diff)
klninfo->delay_max = us_diff;
} else {
if (klninfo->delay_min > us_diff)
klninfo->delay_min = us_diff;
if (klninfo->delay_max < us_diff)
klninfo->delay_max = us_diff;
}
klninfo->delay_count++;
klninfo->delay_total += us_diff;
}
klninfo->delay_count++;
klninfo->delay_total += us_diff;
if (klninfo->nonce_count > 0) {
us_diff = us_tdiff(&(kitem->tv_when), &(klninfo->tv_last_nonce_received));
if (klninfo->nonce_count == 0) {
if (klninfo->nonce_count == 1) {
klninfo->nonce_min = us_diff;
klninfo->nonce_max = us_diff;
} else {
@ -706,14 +772,14 @@ static void klondike_check_nonce(struct cgpu_info *klncgpu, KLIST *kitem) @@ -706,14 +772,14 @@ static void klondike_check_nonce(struct cgpu_info *klncgpu, KLIST *kitem)
if (klninfo->nonce_max < us_diff)
klninfo->nonce_max = us_diff;
}
klninfo->nonce_count++;
klninfo->nonce_total += us_diff;
}
klninfo->nonce_count++;
memcpy(&(klninfo->tv_last_nonce_received), &(kitem->tv_when),
sizeof(klninfo->tv_last_nonce_received));
memcpy(&(klninfo->tv_last_nonce_received), &(kitem->tv_when),
sizeof(klninfo->tv_last_nonce_received));
return;
}
return;
}
applog(LOG_ERR, "%s%i:%d unknown work (%02x:%08x) - ignored",
@ -730,9 +796,9 @@ static void *klondike_get_replies(void *userdata) @@ -730,9 +796,9 @@ static void *klondike_get_replies(void *userdata)
struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
KLIST *kitem = NULL;
char *hexdata;
int err, recd;
int err, recd, slaves;
applog(LOG_ERR, "Klondike listening for replies");
applog(LOG_DEBUG, "Klondike listening for replies");
while (klninfo->shutdown == false) {
if (klncgpu->usbinfo.nodev)
@ -755,6 +821,22 @@ static void *klondike_get_replies(void *userdata) @@ -755,6 +821,22 @@ static void *klondike_get_replies(void *userdata)
free(hexdata);
}
// We can't check this until it's initialised
if (klninfo->initialised) {
rd_lock(&(klninfo->stat_lock));
slaves = klninfo->status[0].kline.ws.slavecount;
rd_unlock(&(klninfo->stat_lock));
if (kitem->kline.hd.dev > slaves) {
applog(LOG_ERR, "%s%i: reply [%c] has invalid dev=%d (max=%d) using 0",
klncgpu->drv->name, klncgpu->device_id,
(char)(kitem->kline.hd.cmd),
(int)(kitem->kline.hd.dev),
slaves);
kitem->kline.hd.dev = 0;
}
}
switch (kitem->kline.hd.cmd) {
case '=':
klondike_check_nonce(klncgpu, kitem);
@ -763,6 +845,25 @@ static void *klondike_get_replies(void *userdata) @@ -763,6 +845,25 @@ static void *klondike_get_replies(void *userdata)
case 'S':
case 'W':
case 'A':
// We can't do/check this until it's initialised
if (klninfo->initialised) {
wr_lock(&(klninfo->stat_lock));
klninfo->jobque[kitem->kline.ws.dev].workqc =
(int)(kitem->kline.ws.workqc);
cgtime(&(klninfo->jobque[kitem->kline.ws.dev].last_update));
slaves = klninfo->status[0].kline.ws.slavecount;
wr_unlock(&(klninfo->stat_lock));
if (kitem->kline.ws.slavecount != slaves) {
applog(LOG_ERR, "%s%i: reply [%c] has a diff # of slaves=%d (curr=%d) dropping device to hotplug",
klncgpu->drv->name, klncgpu->device_id,
(char)(kitem->kline.ws.cmd),
(int)(kitem->kline.ws.slavecount),
slaves);
klninfo->shutdown = true;
break;
}
}
case 'E':
wr_lock(&(klninfo->stat_lock));
klninfo->errorcount += kitem->kline.ws.errorcount;
@ -801,17 +902,20 @@ static void klondike_flush_work(struct cgpu_info *klncgpu) @@ -801,17 +902,20 @@ static void klondike_flush_work(struct cgpu_info *klncgpu)
klninfo->block_seq++;
applog(LOG_DEBUG, "Klondike flushing work");
rd_lock(&(klninfo->stat_lock));
slaves = klninfo->status[0].kline.ws.slavecount;
rd_unlock(&(klninfo->stat_lock));
kline.hd.cmd = 'A';
for (dev = 0; dev <= slaves; dev++) {
kline.hd.dev = dev;
kitem = SendCmdGetReply(klncgpu, &kline, KSENDHD(0));
if (kitem != NULL) {
wr_lock(&(klninfo->stat_lock));
memcpy((void *)&(klninfo->status[dev]), kitem, sizeof(*kitem));
memcpy((void *)&(klninfo->status[dev]),
kitem,
sizeof(klninfo->status[dev]));
wr_unlock(&(klninfo->stat_lock));
release_kitem(klncgpu, kitem);
kitem = NULL;
kitem = release_kitem(klncgpu, kitem);
}
}
}
@ -860,7 +964,7 @@ static void klondike_shutdown(struct thr_info *thr) @@ -860,7 +964,7 @@ static void klondike_shutdown(struct thr_info *thr)
kline.hd.buf[0] = '0';
kitem = SendCmdGetReply(klncgpu, &kline, KSENDHD(1));
if (kitem)
release_kitem(klncgpu, kitem);
kitem = release_kitem(klncgpu, kitem);
}
klncgpu->shutdown = klninfo->shutdown = true;
}
@ -886,8 +990,10 @@ static void klondike_thread_enable(struct thr_info *thr) @@ -886,8 +990,10 @@ static void klondike_thread_enable(struct thr_info *thr)
static bool klondike_send_work(struct cgpu_info *klncgpu, int dev, struct work *work)
{
struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
struct work *tmp;
struct work *look, *tmp;
KLINE kline;
struct timeval tv_old;
int wque_size, wque_cleared;
if (klncgpu->usbinfo.nodev)
return false;
@ -898,6 +1004,7 @@ static bool klondike_send_work(struct cgpu_info *klncgpu, int dev, struct work * @@ -898,6 +1004,7 @@ static bool klondike_send_work(struct cgpu_info *klncgpu, int dev, struct work *
memcpy(kline.wt.merkle, work->data + MERKLE_OFFSET, MERKLE_BYTES);
kline.wt.workid = (uint8_t)(klninfo->devinfo[dev].nextworkid++ & 0xFF);
work->subid = dev*256 + kline.wt.workid;
cgtime(&work->tv_stamp);
if (opt_log_level <= LOG_DEBUG) {
char *hexdata = bin2hex((void *)&kline.wt, sizeof(kline.wt));
@ -909,16 +1016,28 @@ static bool klondike_send_work(struct cgpu_info *klncgpu, int dev, struct work * @@ -909,16 +1016,28 @@ static bool klondike_send_work(struct cgpu_info *klncgpu, int dev, struct work *
KLIST *kitem = SendCmdGetReply(klncgpu, &kline, sizeof(kline.wt));
if (kitem != NULL) {
wr_lock(&(klninfo->stat_lock));
memcpy((void *)&(klninfo->status[dev]), kitem, sizeof(*kitem));
memcpy((void *)&(klninfo->status[dev]), kitem, sizeof(klninfo->status[dev]));
wr_unlock(&(klninfo->stat_lock));
release_kitem(klncgpu, kitem);
kitem = NULL;
kitem = release_kitem(klncgpu, kitem);
// remove old work
HASH_ITER(hh, klncgpu->queued_work, work, tmp) {
if (work->queued && (work->subid == (int)(dev*256 + ((klninfo->devinfo[dev].nextworkid-2*MAX_WORK_COUNT) & 0xFF))))
work_completed(klncgpu, work);
wque_size = 0;
wque_cleared = 0;
cgtime(&tv_old);
wr_lock(&klncgpu->qlock);
HASH_ITER(hh, klncgpu->queued_work, look, tmp) {
if (ms_tdiff(&tv_old, &(look->tv_stamp)) > OLD_WORK_MS) {
__work_completed(klncgpu, look);
free_work(look);
} else
wque_size++;
}
wr_unlock(&klncgpu->qlock);
wr_lock(&(klninfo->stat_lock));
klninfo->wque_size = wque_size;
klninfo->wque_cleared = wque_cleared;
wr_unlock(&(klninfo->stat_lock));
return true;
}
return false;
@ -929,20 +1048,38 @@ static bool klondike_queue_full(struct cgpu_info *klncgpu) @@ -929,20 +1048,38 @@ static bool klondike_queue_full(struct cgpu_info *klncgpu)
struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
struct work *work = NULL;
int dev, queued, slaves;
struct timeval now;
cgtime(&now);
rd_lock(&(klninfo->stat_lock));
slaves = klninfo->status[0].kline.ws.slavecount;
for (dev = 0; dev <= slaves; dev++)
if (ms_tdiff(&now, &(klninfo->jobque[dev].last_update)) > LATE_UPDATE_MS) {
rd_unlock(&(klninfo->stat_lock));
applog(LOG_ERR, "%s%i: late update",
klncgpu->drv->name, klncgpu->device_id);
klondike_get_stats(klncgpu);
goto que;
}
rd_unlock(&(klninfo->stat_lock));
que:
for (queued = 0; queued < MAX_WORK_COUNT-1; queued++)
for (dev = 0; dev <= slaves; dev++)
if (klninfo->status[dev].kline.ws.workqc <= queued) {
for (dev = 0; dev <= slaves; dev++) {
rd_lock(&(klninfo->stat_lock));
if (klninfo->jobque[dev].workqc <= queued) {
rd_unlock(&(klninfo->stat_lock));
if (!work)
work = get_queued(klncgpu);
if (unlikely(!work))
return false;
if (klondike_send_work(klncgpu, dev, work)) {
work = NULL;
break;
}
}
if (klondike_send_work(klncgpu, dev, work))
return false;
} else
rd_unlock(&(klninfo->stat_lock));
}
return true;
}
@ -1100,6 +1237,9 @@ static struct api_data *klondike_api_stats(struct cgpu_info *klncgpu) @@ -1100,6 +1237,9 @@ static struct api_data *klondike_api_stats(struct cgpu_info *klncgpu)
avg = klninfo->nonce_total / klninfo->nonce_count;
root = api_add_diff(root, "KQue Nonce Avg", &avg, true);
root = api_add_int(root, "WQue Size", &(klninfo->wque_size), true);
root = api_add_int(root, "WQue Cleared", &(klninfo->wque_cleared), true);
rd_unlock(&(klninfo->stat_lock));
return root;

181
miner.h

@ -575,6 +575,7 @@ struct cgpu_info { @@ -575,6 +575,7 @@ struct cgpu_info {
pthread_rwlock_t qlock;
struct work *queued_work;
struct work *unqueued_work;
unsigned int queued_count;
bool shutdown;
@ -738,74 +739,143 @@ endian_flip128(void __maybe_unused *dest_p, const void __maybe_unused *src_p) @@ -738,74 +739,143 @@ endian_flip128(void __maybe_unused *dest_p, const void __maybe_unused *src_p)
extern void _quit(int status);
#define mutex_lock(_lock) _mutex_lock(_lock, __FILE__, __func__, __LINE__)
#define mutex_unlock_noyield(_lock) _mutex_unlock_noyield(_lock, __FILE__, __func__, __LINE__)
#define wr_lock(_lock) _wr_lock(_lock, __FILE__, __func__, __LINE__)
#define rd_lock(_lock) _rd_lock(_lock, __FILE__, __func__, __LINE__)
#define rw_unlock(_lock) _rw_unlock(_lock, __FILE__, __func__, __LINE__)
#define mutex_init(_lock) _mutex_init(_lock, __FILE__, __func__, __LINE__)
#define rwlock_init(_lock) _rwlock_init(_lock, __FILE__, __func__, __LINE__)
/*
* Set this to non-zero to enable lock tracking
* Use the API lockstats command to see the locking status on stderr
* i.e. in your log file if you 2> log.log - but not on the screen
* API lockstats is privilidged but will always exist and will return
* success if LOCK_TRACKING is enabled and warning if disabled
* In production code, this should never be enabled since it will slow down all locking
* So, e.g. use it to track down a deadlock - after a reproducable deadlock occurs
* ... Of course if the API code itself deadlocks, it wont help :)
*/
#define LOCK_TRACKING 0
#if LOCK_TRACKING
enum cglock_typ {
CGLOCK_MUTEX,
CGLOCK_RW,
CGLOCK_UNKNOWN
};
extern uint64_t api_getlock(void *lock, const char *file, const char *func, const int line);
extern void api_gotlock(uint64_t id, void *lock, const char *file, const char *func, const int line);
extern uint64_t api_trylock(void *lock, const char *file, const char *func, const int line);
extern void api_didlock(uint64_t id, int ret, void *lock, const char *file, const char *func, const int line);
extern void api_gunlock(void *lock, const char *file, const char *func, const int line);
extern void api_initlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int line);
#define GETLOCK(_lock, _file, _func, _line) uint64_t _id1 = api_getlock((void *)(_lock), _file, _func, _line)
#define GOTLOCK(_lock, _file, _func, _line) api_gotlock(_id1, (void *)(_lock), _file, _func, _line)
#define TRYLOCK(_lock, _file, _func, _line) uint64_t _id2 = api_trylock((void *)(_lock), _file, _func, _line)
#define DIDLOCK(_ret, _lock, _file, _func, _line) api_didlock(_id2, _ret, (void *)(_lock), _file, _func, _line)
#define GUNLOCK(_lock, _file, _func, _line) api_gunlock((void *)(_lock), _file, _func, _line)
#define INITLOCK(_lock, _typ, _file, _func, _line) api_initlock((void *)(_lock), _typ, _file, _func, _line)
#else
#define GETLOCK(_lock, _file, _func, _line)
#define GOTLOCK(_lock, _file, _func, _line)
#define TRYLOCK(_lock, _file, _func, _line)
#define DIDLOCK(_ret, _lock, _file, _func, _line)
#define GUNLOCK(_lock, _file, _func, _line)
#define INITLOCK(_typ, _lock, _file, _func, _line)
#endif
#define mutex_lock(_lock) _mutex_lock(_lock, __FILE__, __func__, __LINE__)
#define mutex_unlock_noyield(_lock) _mutex_unlock_noyield(_lock, __FILE__, __func__, __LINE__)
#define mutex_unlock(_lock) _mutex_unlock(_lock, __FILE__, __func__, __LINE__)
#define mutex_trylock(_lock) _mutex_trylock(_lock, __FILE__, __func__, __LINE__)
#define wr_lock(_lock) _wr_lock(_lock, __FILE__, __func__, __LINE__)
#define rd_lock(_lock) _rd_lock(_lock, __FILE__, __func__, __LINE__)
#define rw_unlock(_lock) _rw_unlock(_lock, __FILE__, __func__, __LINE__)
#define rd_unlock_noyield(_lock) _rd_unlock_noyield(_lock, __FILE__, __func__, __LINE__)
#define wr_unlock_noyield(_lock) _wr_unlock_noyield(_lock, __FILE__, __func__, __LINE__)
#define rd_unlock(_lock) _rd_unlock(_lock, __FILE__, __func__, __LINE__)
#define wr_unlock(_lock) _wr_unlock(_lock, __FILE__, __func__, __LINE__)
#define mutex_init(_lock) _mutex_init(_lock, __FILE__, __func__, __LINE__)
#define rwlock_init(_lock) _rwlock_init(_lock, __FILE__, __func__, __LINE__)
#define cglock_init(_lock) _cglock_init(_lock, __FILE__, __func__, __LINE__)
#define cg_rlock(_lock) _cg_rlock(_lock, __FILE__, __func__, __LINE__)
#define cg_ilock(_lock) _cg_ilock(_lock, __FILE__, __func__, __LINE__)
#define cg_ulock(_lock) _cg_ulock(_lock, __FILE__, __func__, __LINE__)
#define cg_wlock(_lock) _cg_wlock(_lock, __FILE__, __func__, __LINE__)
#define cg_dwlock(_lock) _cg_dwlock(_lock, __FILE__, __func__, __LINE__)
#define cg_dwilock(_lock) _cg_dwilock(_lock, __FILE__, __func__, __LINE__)
#define cg_dlock(_lock) _cg_dlock(_lock, __FILE__, __func__, __LINE__)
#define cg_runlock(_lock) _cg_runlock(_lock, __FILE__, __func__, __LINE__)
#define cg_ruwlock(_lock) _cg_ruwlock(_lock, __FILE__, __func__, __LINE__)
#define cg_wunlock(_lock) _cg_wunlock(_lock, __FILE__, __func__, __LINE__)
static inline void _mutex_lock(pthread_mutex_t *lock, const char *file, const char *func, const int line)
{
GETLOCK(lock, file, func, line);
if (unlikely(pthread_mutex_lock(lock)))
quitfrom(1, file, func, line, "WTF MUTEX ERROR ON LOCK! errno=%d", errno);
GOTLOCK(lock, file, func, line);
}
static inline void _mutex_unlock_noyield(pthread_mutex_t *lock, const char *file, const char *func, const int line)
{
if (unlikely(pthread_mutex_unlock(lock)))
quitfrom(1, file, func, line, "WTF MUTEX ERROR ON UNLOCK! errno=%d", errno);
GUNLOCK(lock, file, func, line);
}
static inline void mutex_unlock(pthread_mutex_t *lock)
static inline void _mutex_unlock(pthread_mutex_t *lock, const char *file, const char *func, const int line)
{
mutex_unlock_noyield(lock);
_mutex_unlock_noyield(lock, file, func, line);
sched_yield();
}
static inline int mutex_trylock(pthread_mutex_t *lock)
static inline int _mutex_trylock(pthread_mutex_t *lock, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line)
{
return pthread_mutex_trylock(lock);
TRYLOCK(lock, file, func, line);
int ret = pthread_mutex_trylock(lock);
DIDLOCK(ret, lock, file, func, line);
return ret;
}
static inline void _wr_lock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
{
GETLOCK(lock, file, func, line);
if (unlikely(pthread_rwlock_wrlock(lock)))
quitfrom(1, file, func, line, "WTF WRLOCK ERROR ON LOCK! errno=%d", errno);
GOTLOCK(lock, file, func, line);
}
static inline void _rd_lock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
{
GETLOCK(lock, file, func, line);
if (unlikely(pthread_rwlock_rdlock(lock)))
quitfrom(1, file, func, line, "WTF RDLOCK ERROR ON LOCK! errno=%d", errno);
GOTLOCK(lock, file, func, line);
}
static inline void _rw_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
{
if (unlikely(pthread_rwlock_unlock(lock)))
quitfrom(1, file, func, line, "WTF RWLOCK ERROR ON UNLOCK! errno=%d", errno);
GUNLOCK(lock, file, func, line);
}
static inline void rd_unlock_noyield(pthread_rwlock_t *lock)
static inline void _rd_unlock_noyield(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
{
rw_unlock(lock);
_rw_unlock(lock, file, func, line);
}
static inline void wr_unlock_noyield(pthread_rwlock_t *lock)
static inline void _wr_unlock_noyield(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
{
rw_unlock(lock);
_rw_unlock(lock, file, func, line);
}
static inline void rd_unlock(pthread_rwlock_t *lock)
static inline void _rd_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
{
rw_unlock(lock);
_rw_unlock(lock, file, func, line);
sched_yield();
}
static inline void wr_unlock(pthread_rwlock_t *lock)
static inline void _wr_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
{
rw_unlock(lock);
_rw_unlock(lock, file, func, line);
sched_yield();
}
@ -813,86 +883,88 @@ static inline void _mutex_init(pthread_mutex_t *lock, const char *file, const ch @@ -813,86 +883,88 @@ static inline void _mutex_init(pthread_mutex_t *lock, const char *file, const ch
{
if (unlikely(pthread_mutex_init(lock, NULL)))
quitfrom(1, file, func, line, "Failed to pthread_mutex_init errno=%d", errno);
INITLOCK(lock, CGLOCK_MUTEX, file, func, line);
}
static inline void _rwlock_init(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
{
if (unlikely(pthread_rwlock_init(lock, NULL)))
quitfrom(1, file, func, line, "Failed to pthread_rwlock_init errno=%d", errno);
INITLOCK(lock, CGLOCK_RW, file, func, line);
}
static inline void cglock_init(cglock_t *lock)
static inline void _cglock_init(cglock_t *lock, const char *file, const char *func, const int line)
{
mutex_init(&lock->mutex);
rwlock_init(&lock->rwlock);
_mutex_init(&lock->mutex, file, func, line);
_rwlock_init(&lock->rwlock, file, func, line);
}
/* Read lock variant of cglock. Cannot be promoted. */
static inline void cg_rlock(cglock_t *lock)
static inline void _cg_rlock(cglock_t *lock, const char *file, const char *func, const int line)
{
mutex_lock(&lock->mutex);
rd_lock(&lock->rwlock);
mutex_unlock_noyield(&lock->mutex);
_mutex_lock(&lock->mutex, file, func, line);
_rd_lock(&lock->rwlock, file, func, line);
_mutex_unlock_noyield(&lock->mutex, file, func, line);
}
/* Intermediate variant of cglock - behaves as a read lock but can be promoted
* to a write lock or demoted to read lock. */
static inline void cg_ilock(cglock_t *lock)
static inline void _cg_ilock(cglock_t *lock, const char *file, const char *func, const int line)
{
mutex_lock(&lock->mutex);
_mutex_lock(&lock->mutex, file, func, line);
}
/* Upgrade intermediate variant to a write lock */
static inline void cg_ulock(cglock_t *lock)
static inline void _cg_ulock(cglock_t *lock, const char *file, const char *func, const int line)
{
wr_lock(&lock->rwlock);
_wr_lock(&lock->rwlock, file, func, line);
}
/* Write lock variant of cglock */
static inline void cg_wlock(cglock_t *lock)
static inline void _cg_wlock(cglock_t *lock, const char *file, const char *func, const int line)
{
mutex_lock(&lock->mutex);
wr_lock(&lock->rwlock);
_mutex_lock(&lock->mutex, file, func, line);
_wr_lock(&lock->rwlock, file, func, line);
}
/* Downgrade write variant to a read lock */
static inline void cg_dwlock(cglock_t *lock)
static inline void _cg_dwlock(cglock_t *lock, const char *file, const char *func, const int line)
{
wr_unlock_noyield(&lock->rwlock);
rd_lock(&lock->rwlock);
mutex_unlock_noyield(&lock->mutex);
_wr_unlock_noyield(&lock->rwlock, file, func, line);
_rd_lock(&lock->rwlock, file, func, line);
_mutex_unlock_noyield(&lock->mutex, file, func, line);
}
/* Demote a write variant to an intermediate variant */
static inline void cg_dwilock(cglock_t *lock)
static inline void _cg_dwilock(cglock_t *lock, const char *file, const char *func, const int line)
{
wr_unlock(&lock->rwlock);
_wr_unlock(&lock->rwlock, file, func, line);
}
/* Downgrade intermediate variant to a read lock */
static inline void cg_dlock(cglock_t *lock)
static inline void _cg_dlock(cglock_t *lock, const char *file, const char *func, const int line)
{
rd_lock(&lock->rwlock);
mutex_unlock_noyield(&lock->mutex);
_rd_lock(&lock->rwlock, file, func, line);
_mutex_unlock_noyield(&lock->mutex, file, func, line);
}
static inline void cg_runlock(cglock_t *lock)
static inline void _cg_runlock(cglock_t *lock, const char *file, const char *func, const int line)
{
rd_unlock(&lock->rwlock);
_rd_unlock(&lock->rwlock, file, func, line);
}
/* This drops the read lock and grabs a write lock. It does NOT protect data
* between the two locks! */
static inline void cg_ruwlock(cglock_t *lock)
static inline void _cg_ruwlock(cglock_t *lock, const char *file, const char *func, const int line)
{
rd_unlock_noyield(&lock->rwlock);
cg_wlock(lock);
_rd_unlock_noyield(&lock->rwlock, file, func, line);
_cg_wlock(lock, file, func, line);
}
static inline void cg_wunlock(cglock_t *lock)
static inline void _cg_wunlock(cglock_t *lock, const char *file, const char *func, const int line)
{
wr_unlock_noyield(&lock->rwlock);
mutex_unlock(&lock->mutex);
_wr_unlock_noyield(&lock->rwlock, file, func, line);
_mutex_unlock(&lock->mutex, file, func, line);
}
struct pool;
@ -943,6 +1015,10 @@ extern bool opt_bfl_noncerange; @@ -943,6 +1015,10 @@ extern bool opt_bfl_noncerange;
#endif
extern int swork_id;
#if LOCK_TRACKING
extern pthread_mutex_t lockstat_lock;
#endif
extern pthread_rwlock_t netacc_lock;
extern const uint32_t sha256_init_state[];
@ -1066,6 +1142,7 @@ extern struct pool **pools; @@ -1066,6 +1142,7 @@ extern struct pool **pools;
extern struct strategies strategies[];
extern enum pool_strategy pool_strategy;
extern int opt_rotate_period;
extern double total_rolling;
extern double total_mhashes_done;
extern unsigned int new_blocks;
extern unsigned int found_blocks;
@ -1306,7 +1383,6 @@ struct work { @@ -1306,7 +1383,6 @@ struct work {
bool stale;
bool mandatory;
bool block;
bool queued;
bool stratum;
char *job_id;
@ -1330,6 +1406,8 @@ struct work { @@ -1330,6 +1406,8 @@ struct work {
int subid;
// Allow devices to flag work for their own purposes
bool devflag;
// Allow devices to timestamp work for their own purposes
struct timeval tv_stamp;
struct timeval tv_getwork;
struct timeval tv_getwork_reply;
@ -1391,6 +1469,7 @@ extern struct work *get_queued(struct cgpu_info *cgpu); @@ -1391,6 +1469,7 @@ extern struct work *get_queued(struct cgpu_info *cgpu);
extern struct work *__find_work_bymidstate(struct work *que, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen);
extern struct work *find_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen);
extern struct work *clone_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen);
extern void __work_completed(struct cgpu_info *cgpu, struct work *work);
extern void work_completed(struct cgpu_info *cgpu, struct work *work);
extern struct work *take_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate, size_t midstatelen, char *data, int offset, size_t datalen);
extern void hash_driver_work(struct thr_info *mythr);

85
usbutils.c

@ -330,6 +330,18 @@ static struct usb_find_devices find_dev[] = { @@ -330,6 +330,18 @@ static struct usb_find_devices find_dev[] = {
.timeout = AVALON_TIMEOUT_MS,
.latency = 10,
INTINFO(ava_ints) },
{
.drv = DRIVER_avalon,
.name = "BBF",
.ident = IDENT_BBF,
.idVendor = IDVENDOR_FTDI,
.idProduct = 0x6001,
.iManufacturer = "Burnin Electronics",
.iProduct = "BitBurner Fury",
.config = 1,
.timeout = AVALON_TIMEOUT_MS,
.latency = 10,
INTINFO(ava_ints) },
{
.drv = DRIVER_avalon,
.name = "AVA",
@ -833,11 +845,11 @@ static void usb_full(ssize_t *count, libusb_device *dev, char **buf, size_t *off @@ -833,11 +845,11 @@ static void usb_full(ssize_t *count, libusb_device *dev, char **buf, size_t *off
err = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, man, STRBUFLEN);
if (err < 0)
snprintf((char *)man, sizeof(man), "** err(%d)%s", err, libusb_error_name(err));
snprintf((char *)man, sizeof(man), "** err:(%d) %s", err, libusb_error_name(err));
err = libusb_get_string_descriptor_ascii(handle, desc.iProduct, prod, STRBUFLEN);
if (err < 0)
snprintf((char *)prod, sizeof(prod), "** err(%d)%s", err, libusb_error_name(err));
snprintf((char *)prod, sizeof(prod), "** err:(%d) %s", err, libusb_error_name(err));
if (level == 0) {
libusb_close(handle);
@ -913,7 +925,7 @@ static void usb_full(ssize_t *count, libusb_device *dev, char **buf, size_t *off @@ -913,7 +925,7 @@ static void usb_full(ssize_t *count, libusb_device *dev, char **buf, size_t *off
err = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, ser, STRBUFLEN);
if (err < 0)
snprintf((char *)ser, sizeof(ser), "** err(%d)%s", err, libusb_error_name(err));
snprintf((char *)ser, sizeof(ser), "** err:(%d) %s", err, libusb_error_name(err));
snprintf(tmp, sizeof(tmp), EOL " dev %d: More Info:" EOL "\tManufacturer: '%s'" EOL
"\tProduct: '%s'" EOL "\tSerial '%s'",
@ -933,7 +945,7 @@ void usb_all(int level) @@ -933,7 +945,7 @@ void usb_all(int level)
count = libusb_get_device_list(NULL, &list);
if (count < 0) {
applog(LOG_ERR, "USB all: failed, err %d%s", (int)count, libusb_error_name((int)count));
applog(LOG_ERR, "USB all: failed, err:(%d) %s", (int)count, libusb_error_name((int)count));
return;
}
@ -2242,6 +2254,12 @@ static void init_usb_transfer(struct usb_transfer *ut) @@ -2242,6 +2254,12 @@ static void init_usb_transfer(struct usb_transfer *ut)
ut->transfer->user_data = ut;
}
static void complete_usb_transfer(struct usb_transfer *ut)
{
cgsem_destroy(&ut->cgsem);
libusb_free_transfer(ut->transfer);
}
static void LIBUSB_CALL transfer_callback(struct libusb_transfer *transfer)
{
struct usb_transfer *ut = transfer->user_data;
@ -2265,7 +2283,7 @@ static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int @@ -2265,7 +2283,7 @@ static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int
cgsem_wait(&ut->cgsem);
}
ret = transfer->status;
if (ret == LIBUSB_TRANSFER_CANCELLED)
if (ret == LIBUSB_TRANSFER_CANCELLED || ret == LIBUSB_TRANSFER_TIMED_OUT)
ret = LIBUSB_ERROR_TIMEOUT;
/* No need to sort out mutexes here since they won't be reused */
@ -2294,6 +2312,11 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, @@ -2294,6 +2312,11 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
usb_epinfo = &(cgpu->usbdev->found->intinfos[intinfo].epinfos[epinfo]);
endpoint = usb_epinfo->ep;
/* Avoid any async transfers during shutdown to allow the polling
* thread to be shut down after all existing transfers are complete */
if (unlikely(cgpu->shutdown))
return libusb_bulk_transfer(dev_handle, endpoint, data, length, transferred, timeout);
/* Limit length of transfer to the largest this descriptor supports
* and leave the higher level functions to transfer more if needed. */
if (usb_epinfo->PrefPacketSize)
@ -2308,10 +2331,15 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, @@ -2308,10 +2331,15 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
USBDEBUG("USB debug: @usb_bulk_transfer(%s (nodev=%s),intinfo=%d,epinfo=%d,data=%p,length=%d,timeout=%u,mode=%d,cmd=%s,seq=%d) endpoint=%d", cgpu->drv->name, bool_str(cgpu->usbinfo.nodev), intinfo, epinfo, data, length, timeout, mode, usb_cmdname(cmd), seq, (int)endpoint);
init_usb_transfer(&ut);
#ifdef LINUX
/* We give the transfer no timeout since we manage timeouts ourself */
libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length,
transfer_callback, &ut, 0);
#else
/* All other OSes not so lucky */
libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length,
transfer_callback, &ut, timeout);
#endif
STATS_TIMEVAL(&tv_start);
cg_rlock(&cgusb_fd_lock);
err = libusb_submit_transfer(ut.transfer);
@ -2319,7 +2347,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo, @@ -2319,7 +2347,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
errn = errno;
if (!err)
err = callback_wait(&ut, transferred, timeout);
libusb_free_transfer(ut.transfer);
complete_usb_transfer(&ut);
STATS_TIMEVAL(&tv_finish);
USB_STATS(cgpu, &tv_start, &tv_finish, err, mode, cmd, seq, timeout);
@ -2612,8 +2640,8 @@ int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t @@ -2612,8 +2640,8 @@ int _usb_read(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_t
out_unlock:
if (err && err != LIBUSB_ERROR_TIMEOUT) {
applog(LOG_WARNING, "%s %i usb read error: %s", cgpu->drv->name, cgpu->device_id,
libusb_error_name(err));
applog(LOG_WARNING, "%s %i usb read err:(%d) %s", cgpu->drv->name, cgpu->device_id,
err, libusb_error_name(err));
if (cgpu->usbinfo.continuous_ioerr_count > USB_RETRY_MAX)
err = LIBUSB_ERROR_OTHER;
}
@ -2712,8 +2740,8 @@ int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_ @@ -2712,8 +2740,8 @@ int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_
*processed = tot;
if (err) {
applog(LOG_WARNING, "%s %i usb write error: %s", cgpu->drv->name, cgpu->device_id,
libusb_error_name(err));
applog(LOG_WARNING, "%s %i usb write err:(%d) %s", cgpu->drv->name, cgpu->device_id,
err, libusb_error_name(err));
if (cgpu->usbinfo.continuous_ioerr_count > USB_RETRY_MAX)
err = LIBUSB_ERROR_OTHER;
}
@ -2731,7 +2759,7 @@ out_noerrmsg: @@ -2731,7 +2759,7 @@ out_noerrmsg:
/* As we do for bulk reads, emulate a sync function for control transfers using
* our own timeouts that takes the same parameters as libusb_control_transfer.
*/
static int usb_control_transfer(libusb_device_handle *dev_handle, uint8_t bmRequestType,
static int usb_control_transfer(struct cgpu_info *cgpu, libusb_device_handle *dev_handle, uint8_t bmRequestType,
uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
unsigned char *buffer, uint16_t wLength, unsigned int timeout)
{
@ -2739,25 +2767,35 @@ static int usb_control_transfer(libusb_device_handle *dev_handle, uint8_t bmRequ @@ -2739,25 +2767,35 @@ static int usb_control_transfer(libusb_device_handle *dev_handle, uint8_t bmRequ
unsigned char buf[70];
int err, transferred;
if (unlikely(cgpu->shutdown))
return libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, buffer, wLength, timeout);
init_usb_transfer(&ut);
libusb_fill_control_setup(buf, bmRequestType, bRequest, wValue,
wIndex, wLength);
if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT)
memcpy(buf + LIBUSB_CONTROL_SETUP_SIZE, buffer, wLength);
#ifdef LINUX
libusb_fill_control_transfer(ut.transfer, dev_handle, buf, transfer_callback,
&ut, 0);
#else
libusb_fill_control_transfer(ut.transfer, dev_handle, buf, transfer_callback,
&ut, timeout);
#endif
err = libusb_submit_transfer(ut.transfer);
if (!err)
err = callback_wait(&ut, &transferred, timeout);
if (!err && transferred) {
unsigned char *ofbuf = libusb_control_transfer_get_data(ut.transfer);
memcpy(buffer, ofbuf, transferred);
if (err == LIBUSB_TRANSFER_COMPLETED && transferred) {
if ((bmRequestType & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
memcpy(buffer, libusb_control_transfer_get_data(ut.transfer),
transferred);
err = transferred;
goto out;
}
if ((err) == LIBUSB_TRANSFER_CANCELLED)
err = LIBUSB_ERROR_TIMEOUT;
out:
libusb_free_transfer(ut.transfer);
complete_usb_transfer(&ut);
return err;
}
@ -2817,8 +2855,8 @@ int __usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bReques @@ -2817,8 +2855,8 @@ int __usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bReques
}
STATS_TIMEVAL(&tv_start);
cg_rlock(&cgusb_fd_lock);
err = usb_control_transfer(usbdev->handle, request_type,
bRequest, wValue, wIndex, buf, (uint16_t)siz, timeout);
err = usb_control_transfer(cgpu, usbdev->handle, request_type, bRequest,
wValue, wIndex, buf, (uint16_t)siz, timeout);
cg_runlock(&cgusb_fd_lock);
STATS_TIMEVAL(&tv_finish);
USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_CTRL_WRITE, cmd, SEQ0, timeout);
@ -2828,7 +2866,7 @@ int __usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bReques @@ -2828,7 +2866,7 @@ int __usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bReques
IOERR_CHECK(cgpu, err);
if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
applog(LOG_WARNING, "%s %i usb transfer error(%d): %s", cgpu->drv->name, cgpu->device_id,
applog(LOG_WARNING, "%s %i usb transfer err:(%d) %s", cgpu->drv->name, cgpu->device_id,
err, libusb_error_name(err));
}
out_:
@ -2899,9 +2937,8 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe @@ -2899,9 +2937,8 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe
memset(tbuf, 0, 64);
STATS_TIMEVAL(&tv_start);
cg_rlock(&cgusb_fd_lock);
err = usb_control_transfer(usbdev->handle, request_type,
bRequest, wValue, wIndex,
tbuf, (uint16_t)bufsiz, timeout);
err = usb_control_transfer(cgpu, usbdev->handle, request_type, bRequest,
wValue, wIndex, tbuf, (uint16_t)bufsiz, timeout);
cg_runlock(&cgusb_fd_lock);
STATS_TIMEVAL(&tv_finish);
USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_CTRL_READ, cmd, SEQ0, timeout);
@ -2916,7 +2953,7 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe @@ -2916,7 +2953,7 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe
err = 0;
}
if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
applog(LOG_WARNING, "%s %i usb transfer read error(%d): %s", cgpu->drv->name, cgpu->device_id,
applog(LOG_WARNING, "%s %i usb transfer read err:(%d) %s", cgpu->drv->name, cgpu->device_id,
err, libusb_error_name(err));
}
out_noerrmsg:

1
usbutils.h

@ -145,6 +145,7 @@ enum sub_ident { @@ -145,6 +145,7 @@ enum sub_ident {
IDENT_AVA,
IDENT_BTB,
IDENT_HFA,
IDENT_BBF,
IDENT_KLN,
IDENT_ICA,
IDENT_AMU,

41
util.c

@ -2485,3 +2485,44 @@ void _cgsem_destroy(cgsem_t *cgsem) @@ -2485,3 +2485,44 @@ void _cgsem_destroy(cgsem_t *cgsem)
sem_destroy(cgsem);
}
#endif
/* Provide a completion_timeout helper function for unreliable functions that
* may die due to driver issues etc that time out if the function fails and
* can then reliably return. */
struct cg_completion {
cgsem_t cgsem;
void (*fn)(void *fnarg);
void *fnarg;
};
void *completion_thread(void *arg)
{
struct cg_completion *cgc = (struct cg_completion *)arg;
pthread_detach(pthread_self());
cgc->fn(cgc->fnarg);
cgsem_post(&cgc->cgsem);
return NULL;
}
bool cg_completion_timeout(void *fn, void *fnarg, int timeout)
{
struct cg_completion *cgc;
pthread_t pthread;
bool ret = false;
cgc = malloc(sizeof(struct cg_completion));
if (unlikely(!cgc))
return ret;
cgsem_init(&cgc->cgsem);
cgc->fn = fn;
cgc->fnarg = fnarg;
pthread_create(&pthread, NULL, completion_thread, (void *)cgc);
ret = cgsem_mswait(&cgc->cgsem, timeout);
if (!ret)
free(cgc);
return !ret;
}

1
util.h

@ -135,6 +135,7 @@ void _cgsem_post(cgsem_t *cgsem, const char *file, const char *func, const int l @@ -135,6 +135,7 @@ void _cgsem_post(cgsem_t *cgsem, const char *file, const char *func, const int l
void _cgsem_wait(cgsem_t *cgsem, const char *file, const char *func, const int line);
int _cgsem_mswait(cgsem_t *cgsem, int ms, const char *file, const char *func, const int line);
void _cgsem_destroy(cgsem_t *cgsem);
bool cg_completion_timeout(void *fn, void *fnarg, int timeout);
#define cgsem_init(_sem) _cgsem_init(_sem, __FILE__, __func__, __LINE__)
#define cgsem_post(_sem) _cgsem_post(_sem, __FILE__, __func__, __LINE__)

Loading…
Cancel
Save