Browse Source

Merge branch 'master' into hashfast

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

+ 16 - 0
API-README

@@ -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
                                AVA+BTB opt=freq val=256 to 1024 - chip frequency
                                BTB opt=millivolts val=1000 to 1400 - corevoltage
                                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
 When you enable, disable or restart a GPU, PGA or ASC, you will also get
 Thread messages in the cgminer status window
 Thread messages in the cgminer status window
 
 
@@ -491,6 +497,16 @@ miner.php - an example web page to access the API
 Feature Changelog for external applications using the API:
 Feature Changelog for external applications using the API:
 
 
 
 
+API V1.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)
 API V1.30 (cgminer v3.4.3)
 
 
 Added API command:
 Added API command:

+ 1 - 1
Makefile.am

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

+ 99 - 1
NEWS

@@ -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
 - 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
 libusb_handle_events in the polling thread and use a bool to know if we should
 continue polling.
 continue polling.

+ 402 - 1
api.c

@@ -136,7 +136,7 @@ static const char SEPARATOR = '|';
 #define SEPSTR "|"
 #define SEPSTR "|"
 static const char GPUSEP = ',';
 static const char GPUSEP = ',';
 
 
-static const char *APIVERSION = "1.30";
+static const char *APIVERSION = "1.31";
 static const char *DEAD = "Dead";
 static const char *DEAD = "Dead";
 #if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA) || defined(HAVE_AN_ASIC)
 #if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA) || defined(HAVE_AN_ASIC)
 static const char *SICK = "Sick";
 static const char *SICK = "Sick";
@@ -431,6 +431,8 @@ static const char *JSON_PARAMETER = "parameter";
 
 
 #define MSG_INVNEG 121
 #define MSG_INVNEG 121
 #define MSG_SETQUOTA 122
 #define MSG_SETQUOTA 122
+#define MSG_LOCKOK 123
+#define MSG_LOCKDIS 124
 
 
 enum code_severity {
 enum code_severity {
 	SEVERITY_ERR,
 	SEVERITY_ERR,
@@ -635,6 +637,8 @@ struct CODES {
  { SEVERITY_SUCC,  MSG_ASCSETOK, PARAM_BOTH,	"ASC %d set OK" },
  { SEVERITY_SUCC,  MSG_ASCSETOK, PARAM_BOTH,	"ASC %d set OK" },
  { SEVERITY_ERR,   MSG_ASCSETERR, PARAM_BOTH,	"ASC %d set failed: %s" },
  { SEVERITY_ERR,   MSG_ASCSETERR, PARAM_BOTH,	"ASC %d set failed: %s" },
 #endif
 #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 }
  { SEVERITY_FAIL, 0, 0, NULL }
 };
 };
 
 
@@ -1432,6 +1436,399 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p
 		io_add(io_data, JSON_CLOSE);
 		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)
 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;
 	struct api_data *root = NULL;
@@ -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_elapsed(root, "Elapsed", &(total_secs), true);
 	root = api_add_mhs(root, "MHS av", &(mhs), false);
 	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_uint(root, "Found Blocks", &(found_blocks), true);
 	root = api_add_int(root, "Getworks", &(total_getworks), true);
 	root = api_add_int(root, "Getworks", &(total_getworks), true);
 	root = api_add_int(root, "Accepted", &(total_accepted), true);
 	root = api_add_int(root, "Accepted", &(total_accepted), true);
@@ -3878,6 +4278,7 @@ struct CMDS {
 	{ "ascset",		ascset,		true },
 	{ "ascset",		ascset,		true },
 #endif
 #endif
 	{ "asccount",		asccount,	false },
 	{ "asccount",		asccount,	false },
+	{ "lockstats",		lockstats,	true },
 	{ NULL,			NULL,		false }
 	{ NULL,			NULL,		false }
 };
 };
 
 

+ 3 - 14
autogen.sh

@@ -1,20 +1,9 @@
 #!/bin/sh
 #!/bin/sh
 bs_dir="$(dirname $(readlink -f $0))"
 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
 if test -z "$NOCONFIGURE" ; then
 	echo 'Configuring...'
 	echo 'Configuring...'

+ 89 - 82
cgminer.c

@@ -212,6 +212,10 @@ static int new_devices;
 static int new_threads;
 static int new_threads;
 int hotplug_time = 5;
 int hotplug_time = 5;
 
 
+#if LOCK_TRACKING
+pthread_mutex_t lockstat_lock;
+#endif
+
 #ifdef USE_USBUTILS
 #ifdef USE_USBUTILS
 pthread_mutex_t cgusb_lock;
 pthread_mutex_t cgusb_lock;
 pthread_mutex_t cgusbres_lock;
 pthread_mutex_t cgusbres_lock;
@@ -237,6 +241,7 @@ pthread_cond_t restart_cond;
 
 
 pthread_cond_t gws_cond;
 pthread_cond_t gws_cond;
 
 
+double total_rolling;
 double total_mhashes_done;
 double total_mhashes_done;
 static struct timeval total_tv_start, total_tv_end;
 static struct timeval total_tv_start, total_tv_end;
 
 
@@ -1249,7 +1254,10 @@ static struct opt_table opt_config_table[] = {
 		     "Set avalon target temperature"),
 		     "Set avalon target temperature"),
 	OPT_WITH_ARG("--bitburner-voltage",
 	OPT_WITH_ARG("--bitburner-voltage",
 		     opt_set_intval, NULL, &opt_bitburner_core_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
 #endif
 #ifdef USE_KLONDIKE
 #ifdef USE_KLONDIKE
 	OPT_WITH_ARG("--klondike-options",
 	OPT_WITH_ARG("--klondike-options",
@@ -3148,6 +3156,35 @@ static void disable_curses(void)
 }
 }
 #endif
 #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)
 static void __kill_work(void)
 {
 {
 	struct thr_info *thr;
 	struct thr_info *thr;
@@ -3164,19 +3201,19 @@ static void __kill_work(void)
 	if (!opt_scrypt) {
 	if (!opt_scrypt) {
 		applog(LOG_DEBUG, "Killing off HotPlug thread");
 		applog(LOG_DEBUG, "Killing off HotPlug thread");
 		thr = &control_thr[hotplug_thr_id];
 		thr = &control_thr[hotplug_thr_id];
-		thr_info_cancel(thr);
+		kill_timeout(thr);
 	}
 	}
 #endif
 #endif
 
 
 	applog(LOG_DEBUG, "Killing off watchpool thread");
 	applog(LOG_DEBUG, "Killing off watchpool thread");
 	/* Kill the watchpool thread */
 	/* Kill the watchpool thread */
 	thr = &control_thr[watchpool_thr_id];
 	thr = &control_thr[watchpool_thr_id];
-	thr_info_cancel(thr);
+	kill_timeout(thr);
 
 
 	applog(LOG_DEBUG, "Killing off watchdog thread");
 	applog(LOG_DEBUG, "Killing off watchdog thread");
 	/* Kill the watchdog thread */
 	/* Kill the watchdog thread */
 	thr = &control_thr[watchdog_thr_id];
 	thr = &control_thr[watchdog_thr_id];
-	thr_info_cancel(thr);
+	kill_timeout(thr);
 
 
 	applog(LOG_DEBUG, "Shutting down mining threads");
 	applog(LOG_DEBUG, "Shutting down mining threads");
 	for (i = 0; i < mining_threads; i++) {
 	for (i = 0; i < mining_threads; i++) {
@@ -3194,43 +3231,27 @@ static void __kill_work(void)
 
 
 	sleep(1);
 	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");
 	applog(LOG_DEBUG, "Killing off stage thread");
 	/* Stop the others */
 	/* Stop the others */
 	thr = &control_thr[stage_thr_id];
 	thr = &control_thr[stage_thr_id];
-	thr_info_cancel(thr);
+	kill_timeout(thr);
 
 
 	applog(LOG_DEBUG, "Killing off API thread");
 	applog(LOG_DEBUG, "Killing off API thread");
 	thr = &control_thr[api_thr_id];
 	thr = &control_thr[api_thr_id];
-	thr_info_cancel(thr);
+	kill_timeout(thr);
 
 
 #ifdef USE_USBUTILS
 #ifdef USE_USBUTILS
 	/* Release USB resources in case it's a restart
 	/* Release USB resources in case it's a restart
 	 * and not a QUIT */
 	 * and not a QUIT */
 	if (!opt_scrypt) {
 	if (!opt_scrypt) {
 		applog(LOG_DEBUG, "Releasing all USB devices");
 		applog(LOG_DEBUG, "Releasing all USB devices");
-		usb_cleanup();
+		cg_completion_timeout(&usb_cleanup, NULL, 1000);
 
 
 		applog(LOG_DEBUG, "Killing off usbres thread");
 		applog(LOG_DEBUG, "Killing off usbres thread");
 		thr = &control_thr[usbres_thr_id];
 		thr = &control_thr[usbres_thr_id];
-		thr_info_cancel(thr);
+		kill_timeout(thr);
 	}
 	}
 #endif
 #endif
 
 
@@ -4505,6 +4526,7 @@ void zero_stats(void)
 	int i;
 	int i;
 
 
 	cgtime(&total_tv_start);
 	cgtime(&total_tv_start);
+	total_rolling = 0;
 	total_mhashes_done = 0;
 	total_mhashes_done = 0;
 	total_getworks = 0;
 	total_getworks = 0;
 	total_accepted = 0;
 	total_accepted = 0;
@@ -5003,7 +5025,6 @@ static void hashmeter(int thr_id, struct timeval *diff,
 	double secs;
 	double secs;
 	double local_secs;
 	double local_secs;
 	static double local_mhashes_done = 0;
 	static double local_mhashes_done = 0;
-	static double rolling = 0;
 	double local_mhashes;
 	double local_mhashes;
 	bool showlog = false;
 	bool showlog = false;
 	char displayed_hashes[16], displayed_rolling[16];
 	char displayed_hashes[16], displayed_rolling[16];
@@ -5076,15 +5097,15 @@ static void hashmeter(int thr_id, struct timeval *diff,
 	cgtime(&total_tv_end);
 	cgtime(&total_tv_end);
 
 
 	local_secs = (double)total_diff.tv_sec + ((double)total_diff.tv_usec / 1000000.0);
 	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);
 	timersub(&total_tv_end, &total_tv_start, &total_diff);
 	total_secs = (double)total_diff.tv_sec +
 	total_secs = (double)total_diff.tv_sec +
 		((double)total_diff.tv_usec / 1000000.0);
 		((double)total_diff.tv_usec / 1000000.0);
 
 
 	dh64 = (double)total_mhashes_done / total_secs * 1000000ull;
 	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(dh64, displayed_hashes, sizeof(displayed_hashes), 4);
 	suffix_string(dr64, displayed_rolling, sizeof(displayed_rolling), 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)
 	work->thr_id = thr_id;
 	work->thr_id = thr_id;
 	thread_reportin(thr);
 	thread_reportin(thr);
 	work->mined = true;
 	work->mined = true;
+	work->device_diff = MIN(thr->cgpu->drv->max_diff, work->work_difficulty);
 	return work;
 	return work;
 }
 }
 
 
@@ -6326,56 +6348,39 @@ static void hash_sole_work(struct thr_info *mythr)
 	cgpu->deven = DEV_DISABLED;
 	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)
 static void fill_queue(struct thr_info *mythr, struct cgpu_info *cgpu, struct device_drv *drv, const int thr_id)
 {
 {
 	do {
 	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
 		/* The queue_full function should be used by the driver to
 		 * actually place work items on the physical device if it
 		 * actually place work items on the physical device if it
 		 * does have a queue. */
 		 * does have a queue. */
 	} while (!drv->queue_full(cgpu));
 	} 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 *get_queued(struct cgpu_info *cgpu)
 {
 {
-	struct work *work, *tmp, *ret = NULL;
+	struct work *work = NULL;
 
 
 	wr_lock(&cgpu->qlock);
 	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);
 	wr_unlock(&cgpu->qlock);
 
 
-	return ret;
+	return work;
 }
 }
 
 
 /* This function is for finding an already queued work item in the
 /* 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
 	struct work *work, *tmp, *ret = NULL;
 	struct work *work, *tmp, *ret = NULL;
 
 
 	HASH_ITER(hh, que, work, tmp) {
 	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) {
 		    memcmp(work->data + offset, data, datalen) == 0) {
 			ret = work;
 			ret = work;
 			break;
 			break;
@@ -6427,10 +6431,9 @@ struct work *clone_queued_work_bymidstate(struct cgpu_info *cgpu, char *midstate
 	return ret;
 	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);
 	HASH_DEL(cgpu->queued_work, work);
 }
 }
 /* This function should be used by queued device drivers when they're sure
 /* 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,
 
 
 static void flush_queue(struct cgpu_info *cgpu)
 static void flush_queue(struct cgpu_info *cgpu)
 {
 {
-	struct work *work, *tmp;
-	int discarded = 0;
+	struct work *work = NULL;
 
 
 	wr_lock(&cgpu->qlock);
 	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);
 	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
 /* This version of hash work is for devices that are fast enough to always
@@ -7799,12 +7796,16 @@ static void probe_pools(void)
 #ifdef USE_USBUTILS
 #ifdef USE_USBUTILS
 static void *libusb_poll_thread(void __maybe_unused *arg)
 static void *libusb_poll_thread(void __maybe_unused *arg)
 {
 {
-	struct timeval tv_end = {0, 200000};
+	struct timeval tv_end = {0, 100000};
 
 
 	RenameThread("usbpoll");
 	RenameThread("usbpoll");
 
 
 	while (usb_polling)
 	while (usb_polling)
 		libusb_handle_events_timeout_completed(NULL, &tv_end, NULL);
 		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;
 	return NULL;
 }
 }
@@ -7840,6 +7841,12 @@ int main(int argc, char *argv[])
 	if (unlikely(curl_global_init(CURL_GLOBAL_ALL)))
 	if (unlikely(curl_global_init(CURL_GLOBAL_ALL)))
 		quit(1, "Failed to curl_global_init");
 		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));
 	initial_args = malloc(sizeof(char *) * (argc + 1));
 	for  (i = 0; i < argc; i++)
 	for  (i = 0; i < argc; i++)
 		initial_args[i] = strdup(argv[i]);
 		initial_args[i] = strdup(argv[i]);

+ 1 - 1
compat/Makefile.am

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

+ 554 - 0
compat/jansson-2.5/CHANGES

@@ -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

+ 1 - 1
compat/jansson/LICENSE → compat/jansson-2.5/LICENSE

@@ -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
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 of this software and associated documentation files (the "Software"), to deal

+ 17 - 0
compat/jansson-2.5/Makefile.am

@@ -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 - 0
compat/jansson-2.5/README.rst

@@ -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 - 0
compat/jansson-2.5/configure.ac

@@ -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 - 0
compat/jansson-2.5/jansson.pc.in

@@ -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 - 0
compat/jansson-2.5/m4/.gitignore


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

@@ -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

+ 8 - 2
compat/jansson/dump.c → compat/jansson-2.5/src/dump.c

@@ -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
  * Jansson is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
  * it under the terms of the MIT license. See LICENSE for details.
  */
  */
 
 
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
+
 #include <stdio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdlib.h>
 #include <string.h>
 #include <string.h>
@@ -38,7 +41,7 @@ static int dump_to_file(const char *buffer, size_t size, void *data)
 }
 }
 
 
 /* 32 spaces (the maximum indentation size) */
 /* 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)
 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)
 static int do_dump(const json_t *json, size_t flags, int depth,
 static int do_dump(const json_t *json, size_t flags, int depth,
                    json_dump_callback_t dump, void *data)
                    json_dump_callback_t dump, void *data)
 {
 {
+    if(!json)
+        return -1;
+
     switch(json_typeof(json)) {
     switch(json_typeof(json)) {
         case JSON_NULL:
         case JSON_NULL:
             return dump("null", 4, data);
             return dump("null", 4, data);

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


+ 2 - 2
compat/jansson/hashtable.c → compat/jansson-2.5/src/hashtable.c

@@ -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
  * This library is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
  * 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,
     }
     }
 }
 }
 
 
-static size_t primes[] = {
+static const size_t primes[] = {
     5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
     5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
     49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
     49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
     12582917, 25165843, 50331653, 100663319, 201326611, 402653189,
     12582917, 25165843, 50331653, 100663319, 201326611, 402653189,

+ 1 - 1
compat/jansson/hashtable.h → compat/jansson-2.5/src/hashtable.h

@@ -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
  * This library is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
  * it under the terms of the MIT license. See LICENSE for details.

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

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

+ 20 - 12
compat/jansson/jansson.h → compat/jansson-2.5/src/jansson.h

@@ -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
  * Jansson is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
  * it under the terms of the MIT license. See LICENSE for details.
@@ -21,11 +21,11 @@ extern "C" {
 /* version */
 /* version */
 
 
 #define JANSSON_MAJOR_VERSION  2
 #define JANSSON_MAJOR_VERSION  2
-#define JANSSON_MINOR_VERSION  4
+#define JANSSON_MINOR_VERSION  5
 #define JANSSON_MICRO_VERSION  0
 #define JANSSON_MICRO_VERSION  0
 
 
 /* Micro version is omitted if it's 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
 /* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this
    for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
    for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */
@@ -47,11 +47,12 @@ typedef enum {
     JSON_NULL
     JSON_NULL
 } json_type;
 } json_type;
 
 
-typedef struct {
+typedef struct json_t {
     json_type type;
     json_type type;
     size_t refcount;
     size_t refcount;
 } json_t;
 } json_t;
 
 
+#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
 #if JSON_INTEGER_IS_LONG_LONG
 #if JSON_INTEGER_IS_LONG_LONG
 #ifdef _WIN32
 #ifdef _WIN32
 #define JSON_INTEGER_FORMAT "I64d"
 #define JSON_INTEGER_FORMAT "I64d"
@@ -63,6 +64,7 @@ typedef long long json_int_t;
 #define JSON_INTEGER_FORMAT "ld"
 #define JSON_INTEGER_FORMAT "ld"
 typedef long json_int_t;
 typedef long json_int_t;
 #endif /* JSON_INTEGER_IS_LONG_LONG */
 #endif /* JSON_INTEGER_IS_LONG_LONG */
+#endif
 
 
 #define json_typeof(json)      ((json)->type)
 #define json_typeof(json)      ((json)->type)
 #define json_is_object(json)   (json && json_typeof(json) == JSON_OBJECT)
 #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);
         key && (value = json_object_iter_value(json_object_key_to_iter(key))); \
         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))))
         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
 static JSON_INLINE
 int json_object_set(json_t *object, const char *key, json_t *value)
 int json_object_set(json_t *object, const char *key, json_t *value)
 {
 {
@@ -174,9 +181,9 @@ int json_array_clear(json_t *array);
 int json_array_extend(json_t *array, json_t *other);
 int json_array_extend(json_t *array, json_t *other);
 
 
 static JSON_INLINE
 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
 static JSON_INLINE
@@ -186,9 +193,9 @@ int json_array_append(json_t *array, json_t *value)
 }
 }
 
 
 static JSON_INLINE
 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);
 const char *json_string_value(const json_t *string);
@@ -224,14 +231,15 @@ int json_equal(json_t *value1, json_t *value2);
 /* copying */
 /* copying */
 
 
 json_t *json_copy(json_t *value);
 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 */
 /* 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);
 typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data);
 
 

+ 1 - 1
compat/jansson/jansson_config.h.in → compat/jansson-2.5/src/jansson_config.h.in

@@ -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
  * Jansson is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
  * it under the terms of the MIT license. See LICENSE for details.

+ 2 - 1
compat/jansson/jansson_private.h → compat/jansson-2.5/src/jansson_private.h

@@ -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
  * Jansson is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
  * 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);
 /* Wrappers for custom memory functions */
 /* Wrappers for custom memory functions */
 void* jsonp_malloc(size_t size);
 void* jsonp_malloc(size_t size);
 void jsonp_free(void *ptr);
 void jsonp_free(void *ptr);
+char *jsonp_strndup(const char *str, size_t length);
 char *jsonp_strdup(const char *str);
 char *jsonp_strdup(const char *str);
 
 
 /* Windows compatibility */
 /* Windows compatibility */

+ 28 - 5
compat/jansson/load.c → compat/jansson-2.5/src/load.c

@@ -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
  * Jansson is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
  * it under the terms of the MIT license. See LICENSE for details.
  */
  */
 
 
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
+
 #include <errno.h>
 #include <errno.h>
 #include <limits.h>
 #include <limits.h>
 #include <stdio.h>
 #include <stdio.h>
@@ -37,7 +40,7 @@
 #define l_isalpha(c)  (l_isupper(c) || l_islower(c))
 #define l_isalpha(c)  (l_isupper(c) || l_islower(c))
 #define l_isdigit(c)  ('0' <= (c) && (c) <= '9')
 #define l_isdigit(c)  ('0' <= (c) && (c) <= '9')
 #define l_isxdigit(c) \
 #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
 /* Read one byte from stream, convert to unsigned char, then int, and
    return. return EOF on end of file. This corresponds to the
    return. return EOF on end of file. This corresponds to the
@@ -250,9 +253,18 @@ static void lex_unget(lex_t *lex, int c)
 static void lex_unget_unsave(lex_t *lex, int c)
 static void lex_unget_unsave(lex_t *lex, int c)
 {
 {
     if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) {
     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;
         char d;
+        #endif
         stream_unget(&lex->stream, c);
         stream_unget(&lex->stream, c);
-        d = strbuffer_pop(&lex->saved_text);
+        #ifndef NDEBUG
+        d = 
+        #endif
+            strbuffer_pop(&lex->saved_text);
         assert(c == d);
         assert(c == d);
     }
     }
 }
 }
@@ -446,8 +458,9 @@ out:
     jsonp_free(lex->value.string);
     jsonp_free(lex->value.string);
 }
 }
 
 
+#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */
 #if JSON_INTEGER_IS_LONG_LONG
 #if JSON_INTEGER_IS_LONG_LONG
-#ifdef _MSC_VER // Microsoft Visual Studio
+#ifdef _MSC_VER  /* Microsoft Visual Studio */
 #define json_strtoint     _strtoi64
 #define json_strtoint     _strtoi64
 #else
 #else
 #define json_strtoint     strtoll
 #define json_strtoint     strtoll
@@ -455,6 +468,7 @@ out:
 #else
 #else
 #define json_strtoint     strtol
 #define json_strtoint     strtol
 #endif
 #endif
+#endif
 
 
 static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
 static int lex_scan_number(lex_t *lex, int c, json_error_t *error)
 {
 {
@@ -770,6 +784,7 @@ error:
 static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
 static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
 {
 {
     json_t *json;
     json_t *json;
+    double value;
 
 
     switch(lex->token) {
     switch(lex->token) {
         case TOKEN_STRING: {
         case TOKEN_STRING: {
@@ -778,7 +793,15 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error)
         }
         }
 
 
         case TOKEN_INTEGER: {
         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;
             break;
         }
         }
 
 

+ 8 - 3
compat/jansson/memory.c → compat/jansson-2.5/src/memory.c

@@ -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>
  * Copyright (c) 2011-2012 Basile Starynkevitch <basile@starynkevitch.net>
  *
  *
  * Jansson is free software; you can redistribute it and/or modify it
  * Jansson is free software; you can redistribute it and/or modify it
@@ -35,12 +35,17 @@ void jsonp_free(void *ptr)
 char *jsonp_strdup(const char *str)
 char *jsonp_strdup(const char *str)
 {
 {
     char *new_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)
     if(!new_str)
         return NULL;
         return NULL;
 
 
-    strcpy(new_str, str);
+    memcpy(new_str, str, len + 1);
     return new_str;
     return new_str;
 }
 }
 
 

+ 172 - 57
compat/jansson/pack_unpack.c → compat/jansson-2.5/src/pack_unpack.c

@@ -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>
  * Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca>
  *
  *
  * Jansson is free software; you can redistribute it and/or modify
  * Jansson is free software; you can redistribute it and/or modify
@@ -11,17 +11,29 @@
 #include "jansson_private.h"
 #include "jansson_private.h"
 #include "utf.h"
 #include "utf.h"
 
 
+typedef struct {
+    int line;
+    int column;
+    size_t pos;
+    char token;
+} token_t;
+
 typedef struct {
 typedef struct {
     const char *start;
     const char *start;
     const char *fmt;
     const char *fmt;
-    char token;
+    token_t prev_token;
+    token_t token;
+    token_t next_token;
     json_error_t *error;
     json_error_t *error;
     size_t flags;
     size_t flags;
     int line;
     int line;
     int column;
     int column;
+    size_t pos;
 } scanner_t;
 } scanner_t;
 
 
-static const char *type_names[] = {
+#define token(scanner) ((scanner)->token.token)
+
+static const char * const type_names[] = {
     "object",
     "object",
     "array",
     "array",
     "string",
     "string",
@@ -34,7 +46,7 @@ static const char *type_names[] = {
 
 
 #define type_name(x) type_names[json_typeof(x)]
 #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,
 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->error = error;
     s->flags = flags;
     s->flags = flags;
     s->fmt = s->start = fmt;
     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->line = 1;
     s->column = 0;
     s->column = 0;
+    s->pos = 0;
 }
 }
 
 
 static void next_token(scanner_t *s)
 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->column++;
+    s->pos++;
 
 
     /* skip space and ignored chars */
     /* skip space and ignored chars */
     while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') {
     while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') {
@@ -61,23 +87,32 @@ static void next_token(scanner_t *s)
         else
         else
             s->column++;
             s->column++;
 
 
+        s->pos++;
         t++;
         t++;
     }
     }
 
 
-    s->token = *t;
+    s->token.token = *t;
+    s->token.line = s->line;
+    s->token.column = s->column;
+    s->token.pos = s->pos;
 
 
     t++;
     t++;
     s->fmt = 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, ...)
 static void set_error(scanner_t *s, const char *source, const char *fmt, ...)
 {
 {
     va_list ap;
     va_list ap;
-    size_t pos;
     va_start(ap, fmt);
     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);
     jsonp_error_set_source(s->error, source);
 
 
@@ -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);
 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)
 static json_t *pack_object(scanner_t *s, va_list *ap)
 {
 {
     json_t *object = json_object();
     json_t *object = json_object();
     next_token(s);
     next_token(s);
 
 
-    while(s->token != '}') {
-        const char *key;
+    while(token(s) != '}') {
+        char *key;
+        int ours;
         json_t *value;
         json_t *value;
 
 
-        if(!s->token) {
+        if(!token(s)) {
             set_error(s, "<format>", "Unexpected end of format string");
             set_error(s, "<format>", "Unexpected end of format string");
             goto error;
             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;
             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;
             goto error;
-        }
-
-        if(!utf8_check_string(key, -1)) {
-            set_error(s, "<args>", "Invalid UTF-8 in object key");
-            goto error;
-        }
 
 
         next_token(s);
         next_token(s);
 
 
@@ -123,10 +230,16 @@ static json_t *pack_object(scanner_t *s, va_list *ap)
             goto error;
             goto error;
 
 
         if(json_object_set_new_nocheck(object, key, value)) {
         if(json_object_set_new_nocheck(object, key, value)) {
+            if(ours)
+                jsonp_free(key);
+
             set_error(s, "<internal>", "Unable to add key \"%s\"", key);
             set_error(s, "<internal>", "Unable to add key \"%s\"", key);
             goto error;
             goto error;
         }
         }
 
 
+        if(ours)
+            jsonp_free(key);
+
         next_token(s);
         next_token(s);
     }
     }
 
 
@@ -142,10 +255,10 @@ static json_t *pack_array(scanner_t *s, va_list *ap)
     json_t *array = json_array();
     json_t *array = json_array();
     next_token(s);
     next_token(s);
 
 
-    while(s->token != ']') {
+    while(token(s) != ']') {
         json_t *value;
         json_t *value;
 
 
-        if(!s->token) {
+        if(!token(s)) {
             set_error(s, "<format>", "Unexpected end of format string");
             set_error(s, "<format>", "Unexpected end of format string");
             goto error;
             goto error;
         }
         }
@@ -170,25 +283,27 @@ error:
 
 
 static json_t *pack(scanner_t *s, va_list *ap)
 static json_t *pack(scanner_t *s, va_list *ap)
 {
 {
-    switch(s->token) {
+    switch(token(s)) {
         case '{':
         case '{':
             return pack_object(s, ap);
             return pack_object(s, ap);
 
 
         case '[':
         case '[':
             return pack_array(s, ap);
             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 NULL;
-            }
-            return json_string_nocheck(str);
+
+            result = json_string_nocheck(str);
+            if(ours)
+                jsonp_free(str);
+
+            return result;
         }
         }
 
 
         case 'n': /* null */
         case 'n': /* null */
@@ -214,7 +329,7 @@ static json_t *pack(scanner_t *s, va_list *ap)
 
 
         default:
         default:
             set_error(s, "<format>", "Unexpected format character '%c'",
             set_error(s, "<format>", "Unexpected format character '%c'",
-                      s->token);
+                      token(s));
             return NULL;
             return NULL;
     }
     }
 }
 }
@@ -245,30 +360,30 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
     }
     }
     next_token(s);
     next_token(s);
 
 
-    while(s->token != '}') {
+    while(token(s) != '}') {
         const char *key;
         const char *key;
         json_t *value;
         json_t *value;
         int opt = 0;
         int opt = 0;
 
 
         if(strict != 0) {
         if(strict != 0) {
             set_error(s, "<format>", "Expected '}' after '%c', got '%c'",
             set_error(s, "<format>", "Expected '}' after '%c', got '%c'",
-                      (strict == 1 ? '!' : '*'), s->token);
+                      (strict == 1 ? '!' : '*'), token(s));
             goto out;
             goto out;
         }
         }
 
 
-        if(!s->token) {
+        if(!token(s)) {
             set_error(s, "<format>", "Unexpected end of format string");
             set_error(s, "<format>", "Unexpected end of format string");
             goto out;
             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);
             next_token(s);
             continue;
             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;
             goto out;
         }
         }
 
 
@@ -280,7 +395,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap)
 
 
         next_token(s);
         next_token(s);
 
 
-        if(s->token == '?') {
+        if(token(s) == '?') {
             opt = 1;
             opt = 1;
             next_token(s);
             next_token(s);
         }
         }
@@ -331,30 +446,30 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap)
     }
     }
     next_token(s);
     next_token(s);
 
 
-    while(s->token != ']') {
+    while(token(s) != ']') {
         json_t *value;
         json_t *value;
 
 
         if(strict != 0) {
         if(strict != 0) {
             set_error(s, "<format>", "Expected ']' after '%c', got '%c'",
             set_error(s, "<format>", "Expected ']' after '%c', got '%c'",
                       (strict == 1 ? '!' : '*'),
                       (strict == 1 ? '!' : '*'),
-                      s->token);
+                      token(s));
             return -1;
             return -1;
         }
         }
 
 
-        if(!s->token) {
+        if(!token(s)) {
             set_error(s, "<format>", "Unexpected end of format string");
             set_error(s, "<format>", "Unexpected end of format string");
             return -1;
             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);
             next_token(s);
             continue;
             continue;
         }
         }
 
 
-        if(!strchr(unpack_value_starters, s->token)) {
+        if(!strchr(unpack_value_starters, token(s))) {
             set_error(s, "<format>", "Unexpected format character '%c'",
             set_error(s, "<format>", "Unexpected format character '%c'",
-                      s->token);
+                      token(s));
             return -1;
             return -1;
         }
         }
 
 
@@ -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)
 static int unpack(scanner_t *s, json_t *root, va_list *ap)
 {
 {
-    switch(s->token)
+    switch(token(s))
     {
     {
         case '{':
         case '{':
             return unpack_object(s, root, ap);
             return unpack_object(s, root, ap);
@@ -521,7 +636,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap)
 
 
         default:
         default:
             set_error(s, "<format>", "Unexpected format character '%c'",
             set_error(s, "<format>", "Unexpected format character '%c'",
-                      s->token);
+                      token(s));
             return -1;
             return -1;
     }
     }
 }
 }
@@ -551,7 +666,7 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags,
         return NULL;
         return NULL;
 
 
     next_token(&s);
     next_token(&s);
-    if(s.token) {
+    if(token(&s)) {
         json_decref(value);
         json_decref(value);
         set_error(&s, "<format>", "Garbage after format string");
         set_error(&s, "<format>", "Garbage after format string");
         return NULL;
         return NULL;
@@ -614,7 +729,7 @@ int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags,
     va_end(ap_copy);
     va_end(ap_copy);
 
 
     next_token(&s);
     next_token(&s);
-    if(s.token) {
+    if(token(&s)) {
         set_error(&s, "<format>", "Garbage after format string");
         set_error(&s, "<format>", "Garbage after format string");
         return -1;
         return -1;
     }
     }

+ 8 - 3
compat/jansson/strbuffer.c → compat/jansson-2.5/src/strbuffer.c

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

+ 3 - 1
compat/jansson/strbuffer.h → compat/jansson-2.5/src/strbuffer.h

@@ -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
  * Jansson is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
  * it under the terms of the MIT license. See LICENSE for details.
@@ -20,6 +20,8 @@ void strbuffer_close(strbuffer_t *strbuff);
 void strbuffer_clear(strbuffer_t *strbuff);
 void strbuffer_clear(strbuffer_t *strbuff);
 
 
 const char *strbuffer_value(const 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);
 char *strbuffer_steal_value(strbuffer_t *strbuff);
 
 
 int strbuffer_append(strbuffer_t *strbuff, const char *string);
 int strbuffer_append(strbuffer_t *strbuff, const char *string);

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

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

+ 1 - 1
compat/jansson/utf.c → compat/jansson-2.5/src/utf.c

@@ -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
  * Jansson is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
  * it under the terms of the MIT license. See LICENSE for details.

+ 1 - 1
compat/jansson/utf.h → compat/jansson-2.5/src/utf.h

@@ -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
  * Jansson is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
  * it under the terms of the MIT license. See LICENSE for details.

+ 26 - 13
compat/jansson/value.c → compat/jansson-2.5/src/value.c

@@ -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
  * Jansson is free software; you can redistribute it and/or modify
  * it under the terms of the MIT license. See LICENSE for details.
  * it under the terms of the MIT license. See LICENSE for details.
  */
  */
 
 
+#ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #define _GNU_SOURCE
+#endif
 
 
 #include <stddef.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <stdlib.h>
@@ -290,19 +292,27 @@ static json_t *json_object_copy(json_t *object)
     return result;
     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;
     json_t *result;
-
-    const char *key;
-    json_t *value;
+    void *iter;
 
 
     result = json_object();
     result = json_object();
     if(!result)
     if(!result)
         return NULL;
         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));
         json_object_set_new_nocheck(result, key, json_deep_copy(value));
+        iter = json_object_iter_next((json_t *)object, iter);
+    }
 
 
     return result;
     return result;
 }
 }
@@ -509,7 +519,10 @@ int json_array_remove(json_t *json, size_t index)
 
 
     json_decref(array->table[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--;
     array->entries--;
 
 
     return 0;
     return 0;
@@ -590,7 +603,7 @@ static json_t *json_array_copy(json_t *array)
     return result;
     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;
     json_t *result;
     size_t i;
     size_t i;
@@ -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;
     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));
     return json_string_nocheck(json_string_value(string));
 }
 }
@@ -729,7 +742,7 @@ static int json_integer_equal(json_t *integer1, json_t *integer2)
     return json_integer_value(integer1) == json_integer_value(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));
     return json_integer(json_integer_value(integer));
 }
 }
@@ -781,7 +794,7 @@ static int json_real_equal(json_t *real1, json_t *real2)
     return json_real_value(real1) == json_real_value(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));
     return json_real(json_real_value(real));
 }
 }
@@ -907,7 +920,7 @@ json_t *json_copy(json_t *json)
     return NULL;
     return NULL;
 }
 }
 
 
-json_t *json_deep_copy(json_t *json)
+json_t *json_deep_copy(const json_t *json)
 {
 {
     if(!json)
     if(!json)
         return NULL;
         return NULL;
@@ -931,7 +944,7 @@ json_t *json_deep_copy(json_t *json)
         return json_real_copy(json);
         return json_real_copy(json);
 
 
     if(json_is_true(json) || json_is_false(json) || json_is_null(json))
     if(json_is_true(json) || json_is_false(json) || json_is_null(json))
-        return json;
+        return (json_t *)json;
 
 
     return NULL;
     return NULL;
 }
 }

+ 0 - 3
compat/jansson/.gitignore

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

+ 0 - 21
compat/jansson/Makefile.am

@@ -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

+ 0 - 39
compat/jansson/jansson_config.h

@@ -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

+ 0 - 13
compat/jansson/util.h

@@ -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

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

@@ -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
-

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

@@ -1,1294 +0,0 @@
-# Doxyfile 1.5.3
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project
-#
-# All text after a hash (#) is considered a comment and will be ignored
-# The format is:
-#       TAG = value [value, ...]
-# For lists items can also be appended using:
-#       TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ")
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file that 
-# follow. The default is UTF-8 which is also the encoding used for all text before 
-# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into 
-# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of 
-# possible encodings.
-
-DOXYFILE_ENCODING      = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
-# by quotes) that should identify the project.
-
-PROJECT_NAME           = libusb
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
-# This could be handy for archiving the generated documentation or 
-# if some version control system is used.
-
-PROJECT_NUMBER         = 
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
-# base path where the generated documentation will be put. 
-# If a relative path is entered, it will be relative to the location 
-# where doxygen was started. If left blank the current directory will be used.
-
-OUTPUT_DIRECTORY       = 
-
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 
-# 4096 sub-directories (in 2 levels) under the output directory of each output 
-# format and will distribute the generated files over these directories. 
-# Enabling this option can be useful when feeding doxygen a huge amount of 
-# source files, where putting all generated files in the same directory would 
-# otherwise cause performance problems for the file system.
-
-CREATE_SUBDIRS         = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
-# documentation generated by doxygen is written. Doxygen will use this 
-# information to generate all constant output in the proper language. 
-# The default language is English, other supported languages are: 
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, 
-# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, 
-# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, 
-# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, 
-# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian.
-
-OUTPUT_LANGUAGE        = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
-# include brief member descriptions after the members that are listed in 
-# the file and class documentation (similar to JavaDoc). 
-# Set to NO to disable this.
-
-BRIEF_MEMBER_DESC      = YES
-
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
-# the brief description of a member or function before the detailed description. 
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
-# brief descriptions will be completely suppressed.
-
-REPEAT_BRIEF           = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator 
-# that is used to form the text in various listings. Each string 
-# in this list, if found as the leading text of the brief description, will be 
-# stripped from the text and the result after processing the whole list, is 
-# used as the annotated text. Otherwise, the brief description is used as-is. 
-# If left blank, the following values are used ("$name" is automatically 
-# replaced with the name of the entity): "The $name class" "The $name widget" 
-# "The $name file" "is" "provides" "specifies" "contains" 
-# "represents" "a" "an" "the"
-
-ABBREVIATE_BRIEF       = 
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
-# Doxygen will generate a detailed section even if there is only a brief 
-# description.
-
-ALWAYS_DETAILED_SEC    = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all 
-# inherited members of a class in the documentation of that class as if those 
-# members were ordinary class members. Constructors, destructors and assignment 
-# operators of the base classes will not be shown.
-
-INLINE_INHERITED_MEMB  = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
-# path before files name in the file list and in the header files. If set 
-# to NO the shortest path that makes the file name unique will be used.
-
-FULL_PATH_NAMES        = NO
-
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
-# can be used to strip a user-defined part of the path. Stripping is 
-# only done if one of the specified strings matches the left-hand part of 
-# the path. The tag can be used to show relative paths in the file list. 
-# If left blank the directory from which doxygen is run is used as the 
-# path to strip.
-
-STRIP_FROM_PATH        = 
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of 
-# the path mentioned in the documentation of a class, which tells 
-# the reader which header file to include in order to use a class. 
-# If left blank only the name of the header file containing the class 
-# definition is used. Otherwise one should specify the include paths that 
-# are normally passed to the compiler using the -I flag.
-
-STRIP_FROM_INC_PATH    = 
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
-# (but less readable) file names. This can be useful is your file systems 
-# doesn't support long names like on DOS, Mac, or CD-ROM.
-
-SHORT_NAMES            = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
-# will interpret the first line (until the first dot) of a JavaDoc-style 
-# comment as the brief description. If set to NO, the JavaDoc 
-# comments will behave just like regular Qt-style comments 
-# (thus requiring an explicit @brief command for a brief description.)
-
-JAVADOC_AUTOBRIEF      = YES
-
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will 
-# interpret the first line (until the first dot) of a Qt-style 
-# comment as the brief description. If set to NO, the comments 
-# will behave just like regular Qt-style comments (thus requiring 
-# an explicit \brief command for a brief description.)
-
-QT_AUTOBRIEF           = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
-# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
-# comments) as a brief description. This used to be the default behaviour. 
-# The new default is to treat a multi-line C++ comment block as a detailed 
-# description. Set this tag to YES if you prefer the old behaviour instead.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
-# will output the detailed description near the top, like JavaDoc.
-# If set to NO, the detailed description appears after the member 
-# documentation.
-
-DETAILS_AT_TOP         = NO
-
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
-# member inherits the documentation from any documented member that it 
-# re-implements.
-
-INHERIT_DOCS           = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce 
-# a new page for each member. If set to NO, the documentation of a member will 
-# be part of the file/class/namespace that contains it.
-
-SEPARATE_MEMBER_PAGES  = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
-# Doxygen uses this value to replace tabs by spaces in code fragments.
-
-TAB_SIZE               = 4
-
-# This tag can be used to specify a number of aliases that acts 
-# as commands in the documentation. An alias has the form "name=value". 
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
-# put the command \sideeffect (or @sideeffect) in the documentation, which 
-# will result in a user-defined paragraph with heading "Side Effects:". 
-# You can put \n's in the value part of an alias to insert newlines.
-
-ALIASES                = 
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C 
-# sources only. Doxygen will then generate output that is more tailored for C. 
-# For instance, some of the names that are used will be different. The list 
-# of all members will be omitted, etc.
-
-OPTIMIZE_OUTPUT_FOR_C  = YES
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java 
-# sources only. Doxygen will then generate output that is more tailored for Java. 
-# For instance, namespaces will be presented as packages, qualified scopes 
-# will look different, etc.
-
-OPTIMIZE_OUTPUT_JAVA   = NO
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to 
-# include (a tag file for) the STL sources as input, then you should 
-# set this tag to YES in order to let doxygen match functions declarations and 
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. 
-# func(std::string) {}). This also make the inheritance and collaboration 
-# diagrams that involve STL classes more complete and accurate.
-
-BUILTIN_STL_SUPPORT    = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-
-CPP_CLI_SUPPORT        = NO
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
-# tag is set to YES, then doxygen will reuse the documentation of the first 
-# member in the group (if any) for the other members of the group. By default 
-# all members of a group must be documented explicitly.
-
-DISTRIBUTE_GROUP_DOC   = NO
-
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of 
-# the same type (for instance a group of public functions) to be put as a 
-# subgroup of that type (e.g. under the Public Functions section). Set it to 
-# NO to prevent subgrouping. Alternatively, this can be done per class using 
-# the \nosubgrouping command.
-
-SUBGROUPING            = YES
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
-# documentation are documented, even if no documentation was available. 
-# Private class members and static file members will be hidden unless 
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
-
-EXTRACT_ALL            = NO
-
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
-# will be included in the documentation.
-
-EXTRACT_PRIVATE        = NO
-
-# If the EXTRACT_STATIC tag is set to YES all static members of a file 
-# will be included in the documentation.
-
-EXTRACT_STATIC         = YES
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
-# defined locally in source files will be included in the documentation. 
-# If set to NO only classes defined in header files are included.
-
-EXTRACT_LOCAL_CLASSES  = YES
-
-# This flag is only useful for Objective-C code. When set to YES local 
-# methods, which are defined in the implementation section but not in 
-# the interface are included in the documentation. 
-# If set to NO (the default) only methods in the interface are included.
-
-EXTRACT_LOCAL_METHODS  = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be extracted 
-# and appear in the documentation as a namespace called 'anonymous_namespace{file}', 
-# where file will be replaced with the base name of the file that contains the anonymous 
-# namespace. By default anonymous namespace are hidden.
-
-EXTRACT_ANON_NSPACES   = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
-# undocumented members of documented classes, files or namespaces. 
-# If set to NO (the default) these members will be included in the 
-# various overviews, but no documentation section is generated. 
-# This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_MEMBERS     = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
-# undocumented classes that are normally visible in the class hierarchy. 
-# If set to NO (the default) these classes will be included in the various 
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
-
-HIDE_UNDOC_CLASSES     = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
-# friend (class|struct|union) declarations. 
-# If set to NO (the default) these declarations will be included in the 
-# documentation.
-
-HIDE_FRIEND_COMPOUNDS  = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any 
-# documentation blocks found inside the body of a function. 
-# If set to NO (the default) these blocks will be appended to the 
-# function's detailed documentation block.
-
-HIDE_IN_BODY_DOCS      = NO
-
-# The INTERNAL_DOCS tag determines if documentation 
-# that is typed after a \internal command is included. If the tag is set 
-# to NO (the default) then the documentation will be excluded. 
-# Set it to YES to include the internal documentation.
-
-INTERNAL_DOCS          = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
-# file names in lower-case letters. If set to YES upper-case letters are also 
-# allowed. This is useful if you have classes or files whose names only differ 
-# in case and if your file system supports case sensitive file names. Windows 
-# and Mac users are advised to set this option to NO.
-
-CASE_SENSE_NAMES       = YES
-
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
-# will show members with their full class and namespace scopes in the 
-# documentation. If set to YES the scope will be hidden.
-
-HIDE_SCOPE_NAMES       = NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
-# will put a list of the files that are included by a file in the documentation 
-# of that file.
-
-SHOW_INCLUDE_FILES     = YES
-
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
-# is inserted in the documentation for inline members.
-
-INLINE_INFO            = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
-# will sort the (detailed) documentation of file and class members 
-# alphabetically by member name. If set to NO the members will appear in 
-# declaration order.
-
-SORT_MEMBER_DOCS       = NO
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the 
-# brief documentation of file, namespace and class members alphabetically 
-# by member name. If set to NO (the default) the members will appear in 
-# declaration order.
-
-SORT_BRIEF_DOCS        = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be 
-# sorted by fully-qualified names, including namespaces. If set to 
-# NO (the default), the class list will be sorted only by class name, 
-# not including the namespace part. 
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the 
-# alphabetical list.
-
-SORT_BY_SCOPE_NAME     = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or 
-# disable (NO) the todo list. This list is created by putting \todo 
-# commands in the documentation.
-
-GENERATE_TODOLIST      = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or 
-# disable (NO) the test list. This list is created by putting \test 
-# commands in the documentation.
-
-GENERATE_TESTLIST      = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or 
-# disable (NO) the bug list. This list is created by putting \bug 
-# commands in the documentation.
-
-GENERATE_BUGLIST       = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
-# disable (NO) the deprecated list. This list is created by putting 
-# \deprecated commands in the documentation.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional 
-# documentation sections, marked by \if sectionname ... \endif.
-
-ENABLED_SECTIONS       = 
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
-# the initial value of a variable or define consists of for it to appear in 
-# the documentation. If the initializer consists of more lines than specified 
-# here it will be hidden. Use a value of 0 to hide initializers completely. 
-# The appearance of the initializer of individual variables and defines in the 
-# documentation can be controlled using \showinitializer or \hideinitializer 
-# command in the documentation regardless of this setting.
-
-MAX_INITIALIZER_LINES  = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
-# at the bottom of the documentation of classes and structs. If set to YES the 
-# list will mention the files that were used to generate the documentation.
-
-SHOW_USED_FILES        = YES
-
-# If the sources in your project are distributed over multiple directories 
-# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy 
-# in the documentation. The default is NO.
-
-SHOW_DIRECTORIES       = NO
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that 
-# doxygen should invoke to get the current version for each file (typically from the 
-# version control system). Doxygen will invoke the program by executing (via 
-# popen()) the command <command> <input-file>, where <command> is the value of 
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file 
-# provided by doxygen. Whatever the program writes to standard output 
-# is used as the file version. See the manual for examples.
-
-FILE_VERSION_FILTER    = 
-
-#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated 
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
-
-QUIET                  = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are 
-# generated by doxygen. Possible values are YES and NO. If left blank 
-# NO is used.
-
-WARNINGS               = YES
-
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
-# automatically be disabled.
-
-WARN_IF_UNDOCUMENTED   = YES
-
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for 
-# potential errors in the documentation, such as not documenting some 
-# parameters in a documented function, or documenting parameters that 
-# don't exist or using markup commands wrongly.
-
-WARN_IF_DOC_ERROR      = YES
-
-# This WARN_NO_PARAMDOC option can be abled to get warnings for 
-# functions that are documented, but have no documentation for their parameters 
-# or return value. If set to NO (the default) doxygen will only warn about 
-# wrong or incomplete parameter documentation, but not about the absence of 
-# documentation.
-
-WARN_NO_PARAMDOC       = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that 
-# doxygen can produce. The string should contain the $file, $line, and $text 
-# tags, which will be replaced by the file and line number from which the 
-# warning originated and the warning text. Optionally the format may contain 
-# $version, which will be replaced by the version of the file (if it could 
-# be obtained via FILE_VERSION_FILTER)
-
-WARN_FORMAT            = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning 
-# and error messages should be written. If left blank the output is written 
-# to stderr.
-
-WARN_LOGFILE           = 
-
-#---------------------------------------------------------------------------
-# configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag can be used to specify the files and/or directories that contain 
-# documented source files. You may enter file names like "myfile.cpp" or 
-# directories like "/usr/src/myproject". Separate the files or directories 
-# with spaces.
-
-INPUT                  = @top_srcdir@/libusb
-
-# This tag can be used to specify the character encoding of the source files that 
-# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default 
-# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. 
-# See http://www.gnu.org/software/libiconv for the list of possible encodings.
-
-INPUT_ENCODING         = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the 
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
-# and *.h) to filter out the source-files in the directories. If left 
-# blank the following patterns are tested: 
-# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx 
-# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py
-
-FILE_PATTERNS          = 
-
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
-# should be searched for input files as well. Possible values are YES and NO. 
-# If left blank NO is used.
-
-RECURSIVE              = NO
-
-# The EXCLUDE tag can be used to specify files and/or directories that should 
-# excluded from the INPUT source files. This way you can easily exclude a 
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-
-EXCLUDE                = @top_srcdir@/libusb/libusbi.h @top_srcdir@/libusb/hotplug.h
-
-# The EXCLUDE_SYMLINKS tag can be used select whether or not files or 
-# directories that are symbolic links (a Unix filesystem feature) are excluded 
-# from the input.
-
-EXCLUDE_SYMLINKS       = NO
-
-# If the value of the INPUT tag contains directories, you can use the 
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
-# certain files from those directories. Note that the wildcards are matched 
-# against the file with absolute path, so to exclude all test directories 
-# for example use the pattern */test/*
-
-EXCLUDE_PATTERNS       = 
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 
-# (namespaces, classes, functions, etc.) that should be excluded from the output. 
-# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, 
-# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test
-
-EXCLUDE_SYMBOLS        = 
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or 
-# directories that contain example code fragments that are included (see 
-# the \include command).
-
-EXAMPLE_PATH           = 
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
-# and *.h) to filter out the source-files in the directories. If left 
-# blank all files are included.
-
-EXAMPLE_PATTERNS       = 
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
-# searched for input files to be used with the \include or \dontinclude 
-# commands irrespective of the value of the RECURSIVE tag. 
-# Possible values are YES and NO. If left blank NO is used.
-
-EXAMPLE_RECURSIVE      = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or 
-# directories that contain image that are included in the documentation (see 
-# the \image command).
-
-IMAGE_PATH             = 
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should 
-# invoke to filter for each input file. Doxygen will invoke the filter program 
-# by executing (via popen()) the command <filter> <input-file>, where <filter> 
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
-# input file. Doxygen will then use the output that the filter program writes 
-# to standard output.  If FILTER_PATTERNS is specified, this tag will be 
-# ignored.
-
-INPUT_FILTER           = 
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 
-# basis.  Doxygen will compare the file name with each pattern and apply the 
-# filter if there is a match.  The filters are a list of the form: 
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further 
-# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER 
-# is applied to all files.
-
-FILTER_PATTERNS        = 
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
-# INPUT_FILTER) will be used to filter the input files when producing source 
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
-
-FILTER_SOURCE_FILES    = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
-# be generated. Documented entities will be cross-referenced with these sources. 
-# Note: To get rid of all source code in the generated output, make sure also 
-# VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH 
-# then you must also enable this option. If you don't then doxygen will produce 
-# a warning and turn it on anyway
-
-SOURCE_BROWSER         = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body 
-# of functions and classes directly in the documentation.
-
-INLINE_SOURCES         = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
-# doxygen to hide any special comment blocks from generated source code 
-# fragments. Normal C and C++ comments will always remain visible.
-
-STRIP_CODE_COMMENTS    = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
-# then for each documented function all documented 
-# functions referencing it will be listed.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES (the default) 
-# then for each documented function all documented entities 
-# called/used by that function will be listed.
-
-REFERENCES_RELATION    = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.  Otherwise they will link to the documentstion.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code 
-# will point to the HTML generated by the htags(1) tool instead of doxygen 
-# built-in source browser. The htags tool is part of GNU's global source 
-# tagging system (see http://www.gnu.org/software/global/global.html). You 
-# will need version 4.8.6 or higher.
-
-USE_HTAGS              = NO
-
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
-# will generate a verbatim copy of the header file for each class for 
-# which an include is specified. Set to NO to disable this.
-
-VERBATIM_HEADERS       = YES
-
-#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
-# of all compounds will be generated. Enable this if the project 
-# contains a lot of classes, structs, unions or interfaces.
-
-ALPHABETICAL_INDEX     = YES
-
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
-# in which this list will be split (can be a number in the range [1..20])
-
-COLS_IN_ALPHA_INDEX    = 5
-
-# In case all classes in a project start with a common prefix, all 
-# classes will be put under the same header in the alphabetical index. 
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
-# should be ignored while generating the index headers.
-
-IGNORE_PREFIX          = 
-
-#---------------------------------------------------------------------------
-# configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
-# generate HTML output.
-
-GENERATE_HTML          = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `html' will be used as the default path.
-
-HTML_OUTPUT            = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
-# doxygen will generate files with .html extension.
-
-HTML_FILE_EXTENSION    = .html
-
-# The HTML_HEADER tag can be used to specify a personal HTML header for 
-# each generated HTML page. If it is left blank doxygen will generate a 
-# standard header.
-
-HTML_HEADER            = 
-
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
-# each generated HTML page. If it is left blank doxygen will generate a 
-# standard footer.
-
-HTML_FOOTER            = 
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading 
-# style sheet that is used by each HTML page. It can be used to 
-# fine-tune the look of the HTML output. If the tag is left blank doxygen 
-# will generate a default style sheet. Note that doxygen will try to copy 
-# the style sheet file to the HTML output directory, so don't put your own 
-# stylesheet in the HTML output directory as well, or it will be erased!
-
-HTML_STYLESHEET        = 
-
-# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
-# files or namespaces will be aligned in HTML using tables. If set to 
-# NO a bullet list will be used.
-
-HTML_ALIGN_MEMBERS     = YES
-
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
-# will be generated that can be used as input for tools like the 
-# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
-# of the generated HTML documentation.
-
-GENERATE_HTMLHELP      = NO
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML 
-# documentation will contain sections that can be hidden and shown after the 
-# page has loaded. For this to work a browser that supports 
-# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox 
-# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
-
-HTML_DYNAMIC_SECTIONS  = YES
-
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
-# be used to specify the file name of the resulting .chm file. You 
-# can add a path in front of the file if the result should not be 
-# written to the html output directory.
-
-CHM_FILE               = 
-
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
-# be used to specify the location (absolute path including file name) of 
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run 
-# the HTML help compiler on the generated index.hhp.
-
-HHC_LOCATION           = 
-
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
-# controls if a separate .chi index file is generated (YES) or that 
-# it should be included in the master .chm file (NO).
-
-GENERATE_CHI           = NO
-
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
-# controls whether a binary table of contents is generated (YES) or a 
-# normal table of contents (NO) in the .chm file.
-
-BINARY_TOC             = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members 
-# to the contents of the HTML help documentation and to the tree view.
-
-TOC_EXPAND             = NO
-
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
-# top of each HTML page. The value NO (the default) enables the index and 
-# the value YES disables it.
-
-DISABLE_INDEX          = NO
-
-# This tag can be used to set the number of enum values (range [1..20]) 
-# that doxygen will group on one line in the generated HTML documentation.
-
-ENUM_VALUES_PER_LINE   = 4
-
-# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
-# generated containing a tree-like index structure (just like the one that 
-# is generated for HTML Help). For this to work a browser that supports 
-# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, 
-# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are 
-# probably better off using the HTML help feature.
-
-GENERATE_TREEVIEW      = NO
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
-# used to set the initial width (in pixels) of the frame in which the tree 
-# is shown.
-
-TREEVIEW_WIDTH         = 250
-
-#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
-# generate Latex output.
-
-GENERATE_LATEX         = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `latex' will be used as the default path.
-
-LATEX_OUTPUT           = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be 
-# invoked. If left blank `latex' will be used as the default command name.
-
-LATEX_CMD_NAME         = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
-# generate index for LaTeX. If left blank `makeindex' will be used as the 
-# default command name.
-
-MAKEINDEX_CMD_NAME     = makeindex
-
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
-# LaTeX documents. This may be useful for small projects and may help to 
-# save some trees in general.
-
-COMPACT_LATEX          = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used 
-# by the printer. Possible values are: a4, a4wide, letter, legal and 
-# executive. If left blank a4wide will be used.
-
-PAPER_TYPE             = a4wide
-
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
-# packages that should be included in the LaTeX output.
-
-EXTRA_PACKAGES         = 
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
-# the generated latex document. The header should contain everything until 
-# the first chapter. If it is left blank doxygen will generate a 
-# standard header. Notice: only use this tag if you know what you are doing!
-
-LATEX_HEADER           = 
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
-# contain links (just like the HTML output) instead of page references 
-# This makes the output suitable for online browsing using a pdf viewer.
-
-PDF_HYPERLINKS         = NO
-
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
-# plain latex in the generated Makefile. Set this option to YES to get a 
-# higher quality PDF documentation.
-
-USE_PDFLATEX           = NO
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
-# command to the generated LaTeX files. This will instruct LaTeX to keep 
-# running if errors occur, instead of asking the user for help. 
-# This option is also used when generating formulas in HTML.
-
-LATEX_BATCHMODE        = NO
-
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not 
-# include the index chapters (such as File Index, Compound Index, etc.) 
-# in the output.
-
-LATEX_HIDE_INDICES     = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
-# The RTF output is optimized for Word 97 and may not look very pretty with 
-# other RTF readers or editors.
-
-GENERATE_RTF           = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `rtf' will be used as the default path.
-
-RTF_OUTPUT             = rtf
-
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
-# RTF documents. This may be useful for small projects and may help to 
-# save some trees in general.
-
-COMPACT_RTF            = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
-# will contain hyperlink fields. The RTF file will 
-# contain links (just like the HTML output) instead of page references. 
-# This makes the output suitable for online browsing using WORD or other 
-# programs which support those fields. 
-# Note: wordpad (write) and others do not support links.
-
-RTF_HYPERLINKS         = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's 
-# config file, i.e. a series of assignments. You only have to provide 
-# replacements, missing definitions are set to their default value.
-
-RTF_STYLESHEET_FILE    = 
-
-# Set optional variables used in the generation of an rtf document. 
-# Syntax is similar to doxygen's config file.
-
-RTF_EXTENSIONS_FILE    = 
-
-#---------------------------------------------------------------------------
-# configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
-# generate man pages
-
-GENERATE_MAN           = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `man' will be used as the default path.
-
-MAN_OUTPUT             = man
-
-# The MAN_EXTENSION tag determines the extension that is added to 
-# the generated man pages (default is the subroutine's section .3)
-
-MAN_EXTENSION          = .3
-
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
-# then it will generate one additional man file for each entity 
-# documented in the real man page(s). These additional files 
-# only source the real man page, but without them the man command 
-# would be unable to find the correct page. The default is NO.
-
-MAN_LINKS              = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES Doxygen will 
-# generate an XML file that captures the structure of 
-# the code including all documentation.
-
-GENERATE_XML           = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. 
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
-# put in front of it. If left blank `xml' will be used as the default path.
-
-XML_OUTPUT             = xml
-
-# The XML_SCHEMA tag can be used to specify an XML schema, 
-# which can be used by a validating XML parser to check the 
-# syntax of the XML files.
-
-XML_SCHEMA             = 
-
-# The XML_DTD tag can be used to specify an XML DTD, 
-# which can be used by a validating XML parser to check the 
-# syntax of the XML files.
-
-XML_DTD                = 
-
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will 
-# dump the program listings (including syntax highlighting 
-# and cross-referencing information) to the XML output. Note that 
-# enabling this will significantly increase the size of the XML output.
-
-XML_PROGRAMLISTING     = YES
-
-#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
-# generate an AutoGen Definitions (see autogen.sf.net) file 
-# that captures the structure of the code including all 
-# documentation. Note that this feature is still experimental 
-# and incomplete at the moment.
-
-GENERATE_AUTOGEN_DEF   = NO
-
-#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will 
-# generate a Perl module file that captures the structure of 
-# the code including all documentation. Note that this 
-# feature is still experimental and incomplete at the 
-# moment.
-
-GENERATE_PERLMOD       = NO
-
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate 
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able 
-# to generate PDF and DVI output from the Perl module output.
-
-PERLMOD_LATEX          = NO
-
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be 
-# nicely formatted so it can be parsed by a human reader.  This is useful 
-# if you want to understand what is going on.  On the other hand, if this 
-# tag is set to NO the size of the Perl module output will be much smaller 
-# and Perl will parse it just the same.
-
-PERLMOD_PRETTY         = YES
-
-# The names of the make variables in the generated doxyrules.make file 
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. 
-# This is useful so different doxyrules.make files included by the same 
-# Makefile don't overwrite each other's variables.
-
-PERLMOD_MAKEVAR_PREFIX = 
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor   
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
-# evaluate all C-preprocessor directives found in the sources and include 
-# files.
-
-ENABLE_PREPROCESSING   = YES
-
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
-# names in the source code. If set to NO (the default) only conditional 
-# compilation will be performed. Macro expansion can be done in a controlled 
-# way by setting EXPAND_ONLY_PREDEF to YES.
-
-MACRO_EXPANSION        = YES
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
-# then the macro expansion is limited to the macros specified with the 
-# PREDEFINED and EXPAND_AS_DEFINED tags.
-
-EXPAND_ONLY_PREDEF     = YES
-
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
-# in the INCLUDE_PATH (see below) will be search if a #include is found.
-
-SEARCH_INCLUDES        = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that 
-# contain include files that are not input files but should be processed by 
-# the preprocessor.
-
-INCLUDE_PATH           = 
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
-# patterns (like *.h and *.hpp) to filter out the header-files in the 
-# directories. If left blank, the patterns specified with FILE_PATTERNS will 
-# be used.
-
-INCLUDE_FILE_PATTERNS  = 
-
-# The PREDEFINED tag can be used to specify one or more macro names that 
-# are defined before the preprocessor is started (similar to the -D option of 
-# gcc). The argument of the tag is a list of macros of the form: name 
-# or name=definition (no spaces). If the definition and the = are 
-# omitted =1 is assumed. To prevent a macro definition from being 
-# undefined via #undef or recursively expanded use the := operator 
-# instead of the = operator.
-
-PREDEFINED             = API_EXPORTED= LIBUSB_CALL= DEFAULT_VISIBILITY=
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then 
-# this tag can be used to specify a list of macro names that should be expanded. 
-# The macro definition that is found in the sources will be used. 
-# Use the PREDEFINED tag if you want to use a different macro definition.
-
-EXPAND_AS_DEFINED      = 
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
-# doxygen's preprocessor will remove all function-like macros that are alone 
-# on a line, have an all uppercase name, and do not end with a semicolon. Such 
-# function macros are typically used for boiler-plate code, and will confuse 
-# the parser if not removed.
-
-SKIP_FUNCTION_MACROS   = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to external references   
-#---------------------------------------------------------------------------
-
-# The TAGFILES option can be used to specify one or more tagfiles. 
-# Optionally an initial location of the external documentation 
-# can be added for each tagfile. The format of a tag file without 
-# this location is as follows: 
-#   TAGFILES = file1 file2 ... 
-# Adding location for the tag files is done as follows: 
-#   TAGFILES = file1=loc1 "file2 = loc2" ... 
-# where "loc1" and "loc2" can be relative or absolute paths or 
-# URLs. If a location is present for each tag, the installdox tool 
-# does not have to be run to correct the links.
-# Note that each tag file must have a unique name
-# (where the name does NOT include the path)
-# If a tag file is not located in the directory in which doxygen 
-# is run, you must also specify the path to the tagfile here.
-
-TAGFILES               = 
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
-# a tag file that is based on the input files it reads.
-
-GENERATE_TAGFILE       = 
-
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
-# in the class index. If set to NO only the inherited external classes 
-# will be listed.
-
-ALLEXTERNALS           = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
-# in the modules index. If set to NO, only the current project's groups will 
-# be listed.
-
-EXTERNAL_GROUPS        = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script 
-# interpreter (i.e. the result of `which perl').
-
-PERL_PATH              = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool   
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base 
-# or super classes. Setting the tag to NO turns the diagrams off. Note that 
-# this option is superseded by the HAVE_DOT option below. This is only a 
-# fallback. It is recommended to install and use dot, since it yields more 
-# powerful graphs.
-
-CLASS_DIAGRAMS         = YES
-
-# You can define message sequence charts within doxygen comments using the \msc 
-# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to 
-# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to 
-# specify the directory where the mscgen tool resides. If left empty the tool is assumed to 
-# be found in the default search path.
-
-MSCGEN_PATH            = 
-
-# If set to YES, the inheritance and collaboration graphs will hide 
-# inheritance and usage relations if the target is undocumented 
-# or is not a class.
-
-HIDE_UNDOC_RELATIONS   = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
-# available from the path. This tool is part of Graphviz, a graph visualization 
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
-# have no effect if this option is set to NO (the default)
-
-HAVE_DOT               = NO
-
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for each documented class showing the direct and 
-# indirect inheritance relations. Setting this tag to YES will force the 
-# the CLASS_DIAGRAMS tag to NO.
-
-CLASS_GRAPH            = YES
-
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for each documented class showing the direct and 
-# indirect implementation dependencies (inheritance, containment, and 
-# class references variables) of the class with other documented classes.
-
-COLLABORATION_GRAPH    = YES
-
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen 
-# will generate a graph for groups, showing the direct groups dependencies
-
-GROUP_GRAPHS           = YES
-
-# If the UML_LOOK tag is set to YES doxygen will generate inheritance and 
-# collaboration diagrams in a style similar to the OMG's Unified Modeling 
-# Language.
-
-UML_LOOK               = NO
-
-# If set to YES, the inheritance and collaboration graphs will show the 
-# relations between templates and their instances.
-
-TEMPLATE_RELATIONS     = NO
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
-# tags are set to YES then doxygen will generate a graph for each documented 
-# file showing the direct and indirect include dependencies of the file with 
-# other documented files.
-
-INCLUDE_GRAPH          = YES
-
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
-# documented header file showing the documented files that directly or 
-# indirectly include this file.
-
-INCLUDED_BY_GRAPH      = YES
-
-# If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will 
-# generate a call dependency graph for every global function or class method. 
-# Note that enabling this option will significantly increase the time of a run. 
-# So in most cases it will be better to enable call graphs for selected 
-# functions only using the \callgraph command.
-
-CALL_GRAPH             = NO
-
-# If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will 
-# generate a caller dependency graph for every global function or class method. 
-# Note that enabling this option will significantly increase the time of a run. 
-# So in most cases it will be better to enable caller graphs for selected 
-# functions only using the \callergraph command.
-
-CALLER_GRAPH           = NO
-
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
-# will graphical hierarchy of all classes instead of a textual one.
-
-GRAPHICAL_HIERARCHY    = YES
-
-# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES 
-# then doxygen will show the dependencies a directory has on other directories 
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
-
-DIRECTORY_GRAPH        = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
-# generated by dot. Possible values are png, jpg, or gif
-# If left blank png will be used.
-
-DOT_IMAGE_FORMAT       = png
-
-# The tag DOT_PATH can be used to specify the path where the dot tool can be 
-# found. If left blank, it is assumed the dot tool can be found in the path.
-
-DOT_PATH               = 
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that 
-# contain dot files that are included in the documentation (see the 
-# \dotfile command).
-
-DOTFILE_DIRS           = 
-
-# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of 
-# nodes that will be shown in the graph. If the number of nodes in a graph 
-# becomes larger than this value, doxygen will truncate the graph, which is 
-# visualized by representing a node as a red box. Note that doxygen if the number 
-# of direct children of the root node in a graph is already larger than 
-# MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note 
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-
-DOT_GRAPH_MAX_NODES    = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the 
-# graphs generated by dot. A depth value of 3 means that only nodes reachable 
-# from the root by following a path via at most 3 edges will be shown. Nodes 
-# that lay further from the root node will be omitted. Note that setting this 
-# option to 1 or 2 may greatly reduce the computation time needed for large 
-# code bases. Also note that the size of a graph can be further restricted by 
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-
-MAX_DOT_GRAPH_DEPTH    = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent 
-# background. This is disabled by default, which results in a white background. 
-# Warning: Depending on the platform used, enabling this option may lead to 
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to 
-# read).
-
-DOT_TRANSPARENT        = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output 
-# files in one run (i.e. multiple -o and -T options on the command line). This 
-# makes dot run faster, but since only newer versions of dot (>1.8.10) 
-# support this, this feature is disabled by default.
-
-DOT_MULTI_TARGETS      = NO
-
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
-# generate a legend page explaining the meaning of the various boxes and 
-# arrows in the dot generated graphs.
-
-GENERATE_LEGEND        = YES
-
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
-# remove the intermediate dot files that are used to generate 
-# the various graphs.
-
-DOT_CLEANUP            = YES
-
-#---------------------------------------------------------------------------
-# Configuration::additions related to the search engine   
-#---------------------------------------------------------------------------
-
-# The SEARCHENGINE tag specifies whether or not a search engine should be 
-# used. If set to NO the values of all tags below this one will be ignored.
-
-SEARCHENGINE           = NO

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

@@ -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

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

@@ -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;
-}
-

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

@@ -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;
-}
-

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

@@ -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);
-}

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

@@ -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;
-}
-

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

@@ -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;
-}

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

@@ -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;
-}

+ 4 - 4
configure.ac

@@ -1,8 +1,8 @@
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
 m4_define([v_maj], [3])
 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([v_ver], [v_maj.v_min.v_mic])
 m4_define([lt_rev], m4_eval(v_maj + v_min))
 m4_define([lt_rev], m4_eval(v_maj + v_min))
@@ -359,7 +359,8 @@ else
 	LIBUSB_LIBS=""
 	LIBUSB_LIBS=""
 fi
 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()
 PKG_PROG_PKG_CONFIG()
 
 
@@ -466,7 +467,6 @@ AC_SUBST(ADL_CPPFLAGS)
 AC_CONFIG_FILES([
 AC_CONFIG_FILES([
 	Makefile
 	Makefile
 	compat/Makefile
 	compat/Makefile
-	compat/jansson/Makefile
 	ccan/Makefile
 	ccan/Makefile
 	lib/Makefile
 	lib/Makefile
 	])
 	])

+ 80 - 11
driver-avalon.c

@@ -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_min = AVALON_MIN_FREQUENCY;
 int opt_avalon_freq_max = AVALON_MAX_FREQUENCY;
 int opt_avalon_freq_max = AVALON_MAX_FREQUENCY;
 int opt_bitburner_core_voltage = BITBURNER_DEFAULT_CORE_VOLTAGE;
 int opt_bitburner_core_voltage = BITBURNER_DEFAULT_CORE_VOLTAGE;
+int opt_bitburner_fury_core_voltage = BITBURNER_FURY_DEFAULT_CORE_VOLTAGE;
 bool opt_avalon_auto;
 bool opt_avalon_auto;
 
 
 static int option_offset = -1;
 static int option_offset = -1;
@@ -209,6 +210,55 @@ static int avalon_send_task(const struct avalon_task *at, struct cgpu_info *aval
 	return ret;
 	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,
 static bool avalon_decode_nonce(struct thr_info *thr, struct cgpu_info *avalon,
 				struct avalon_info *info, struct avalon_result *ar,
 				struct avalon_info *info, struct avalon_result *ar,
 				struct work *work)
 				struct work *work)
@@ -414,12 +464,12 @@ static bool get_options(int this_option_offset, int *baud, int *miner_count,
 
 
 		if (*colon) {
 		if (*colon) {
 			tmp = atoi(colon);
 			tmp = atoi(colon);
-			if (tmp > 0 && tmp <= AVALON_DEFAULT_MINER_NUM) {
+			if (tmp > 0 && tmp <= AVALON_MAX_MINER_NUM) {
 				*miner_count = tmp;
 				*miner_count = tmp;
 			} else {
 			} else {
 				quit(1, "Invalid avalon-options for "
 				quit(1, "Invalid avalon-options for "
 					"miner_count (%s) must be 1 ~ %d",
 					"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)
 		avalon->drv->name, avalon->device_id, err);
 		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)
 static bool bitburner_set_core_voltage(struct cgpu_info *avalon, int core_voltage)
 {
 {
 	uint8_t buf[2];
 	uint8_t buf[2];
 	int err;
 	int err;
 
 
-	if (usb_ident(avalon) == IDENT_BTB) {
+	if (is_bitburner(avalon)) {
 		buf[0] = (uint8_t)core_voltage;
 		buf[0] = (uint8_t)core_voltage;
 		buf[1] = (uint8_t)(core_voltage >> 8);
 		buf[1] = (uint8_t)(core_voltage >> 8);
 		err = usb_transfer_data(avalon, FTDI_TYPE_OUT, BITBURNER_REQUEST,
 		err = usb_transfer_data(avalon, FTDI_TYPE_OUT, BITBURNER_REQUEST,
@@ -651,7 +709,7 @@ static int bitburner_get_core_voltage(struct cgpu_info *avalon)
 	int err;
 	int err;
 	int amount;
 	int amount;
 
 
-	if (usb_ident(avalon) == IDENT_BTB) {
+	if (is_bitburner(avalon)) {
 		err = usb_transfer_read(avalon, FTDI_TYPE_IN, BITBURNER_REQUEST,
 		err = usb_transfer_read(avalon, FTDI_TYPE_IN, BITBURNER_REQUEST,
 				BITBURNER_VALUE, BITBURNER_INDEX_GET_VOLTAGE,
 				BITBURNER_VALUE, BITBURNER_INDEX_GET_VOLTAGE,
 				(char *)buf, sizeof(buf), &amount,
 				(char *)buf, sizeof(buf), &amount,
@@ -780,7 +838,18 @@ static bool avalon_detect_one(libusb_device *dev, struct usb_find_devices *found
 				BITBURNER_MAX_COREMV);
 				BITBURNER_MAX_COREMV);
 		} else
 		} else
 			bitburner_set_core_voltage(avalon, opt_bitburner_core_voltage);
 			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);
 		bitburner_get_version(avalon);
 	}
 	}
 
 
@@ -1181,7 +1250,7 @@ static void *bitburner_send_tasks(void *userdata)
 				avalon_reset_auto(info);
 				avalon_reset_auto(info);
 			}
 			}
 
 
-			ret = avalon_send_task(&at, avalon);
+			ret = bitburner_send_task(&at, avalon);
 
 
 			if (unlikely(ret == AVA_SEND_ERROR)) {
 			if (unlikely(ret == AVA_SEND_ERROR)) {
 				applog(LOG_ERR, "%s%i: Comms error(buffer)",
 				applog(LOG_ERR, "%s%i: Comms error(buffer)",
@@ -1211,7 +1280,7 @@ static bool avalon_prepare(struct thr_info *thr)
 	int array_size = AVALON_ARRAY_SIZE;
 	int array_size = AVALON_ARRAY_SIZE;
 	void *(*write_thread_fn)(void *) = avalon_send_tasks;
 	void *(*write_thread_fn)(void *) = avalon_send_tasks;
 
 
-	if (usb_ident(avalon) == IDENT_BTB) {
+	if (is_bitburner(avalon)) {
 		array_size = BITBURNER_ARRAY_SIZE;
 		array_size = BITBURNER_ARRAY_SIZE;
 		write_thread_fn = bitburner_send_tasks;
 		write_thread_fn = bitburner_send_tasks;
 	}
 	}
@@ -1356,7 +1425,7 @@ static void avalon_update_temps(struct cgpu_info *avalon, struct avalon_info *in
 	info->temp_sum += avalon->temp;
 	info->temp_sum += avalon->temp;
 	applog(LOG_DEBUG, "Avalon: temp_index: %d, temp_count: %d, temp_old: %d",
 	applog(LOG_DEBUG, "Avalon: temp_index: %d, temp_count: %d, temp_old: %d",
 		info->temp_history_index, info->temp_history_count, info->temp_old);
 		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);
 		info->core_voltage = bitburner_get_core_voltage(avalon);
 	}
 	}
 	if (info->temp_history_index == info->temp_history_count) {
 	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
 	struct avalon_info *info = avalon->device_data;
 	struct avalon_info *info = avalon->device_data;
 	int lowfan = 10000;
 	int lowfan = 10000;
 
 
-	if (usb_ident(avalon) == IDENT_BTB) {
+	if (is_bitburner(avalon)) {
 		int temp = info->temp0;
 		int temp = info->temp0;
 		if (info->temp2 > temp)
 		if (info->temp2 > temp)
 			temp = info->temp2;
 			temp = info->temp2;
@@ -1464,7 +1533,7 @@ static int64_t avalon_scanhash(struct thr_info *thr)
 
 
 	/* Check for nothing but consecutive bad results or consistently less
 	/* Check for nothing but consecutive bad results or consistently less
 	 * results than we should be getting and reset the FPGA if necessary */
 	 * 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) {
 		if (avalon->results < -miner_count && !info->reset) {
 			applog(LOG_ERR, "%s%d: Result return rate low, resetting!",
 			applog(LOG_ERR, "%s%d: Result return rate low, resetting!",
 				avalon->drv->name, avalon->device_id);
 				avalon->drv->name, avalon->device_id);
@@ -1525,7 +1594,7 @@ static struct api_data *avalon_api_stats(struct cgpu_info *cgpu)
 		sprintf(mcw, "match_work_count%d", i + 1);
 		sprintf(mcw, "match_work_count%d", i + 1);
 		root = api_add_int(root, mcw, &(info->matching_work[i]), false);
 		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);
 		root = api_add_int(root, "core_voltage", &(info->core_voltage), false);
 		snprintf(buf, sizeof(buf), "%"PRIu8".%"PRIu8".%"PRIu8,
 		snprintf(buf, sizeof(buf), "%"PRIu8".%"PRIu8".%"PRIu8,
 				info->version1, info->version2, info->version3);
 				info->version1, info->version2, info->version3);
@@ -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 (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);
 			sprintf(replybuf, "%s cannot set millivolts", avalon->drv->name);
 			return replybuf;
 			return replybuf;
 		}
 		}

+ 10 - 1
driver-avalon.h

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

+ 22 - 4
driver-bflsc.c

@@ -645,18 +645,23 @@ static bool getinfo(struct cgpu_info *bflsc, int dev)
 		else if (strstr(firstname, BFLSC_DI_XLINKPRESENT))
 		else if (strstr(firstname, BFLSC_DI_XLINKPRESENT))
 			sc_dev.xlink_present = strdup(fields[0]);
 			sc_dev.xlink_present = strdup(fields[0]);
 		else if (strstr(firstname, BFLSC_DI_DEVICESINCHAIN)) {
 		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) {
 			if (sc_info->sc_count < 1 || sc_info->sc_count > 30) {
 				tmp = str_text(items[i]);
 				tmp = str_text(items[i]);
 				applogsiz(LOG_WARNING, BFLSC_APPLOGSIZ,
 				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);
 						bflsc->drv->dname, bflsc->device_path, tmp);
 				free(tmp);
 				free(tmp);
 				goto mata;
 				goto mata;
 			}
 			}
+		}
 		else if (strstr(firstname, BFLSC_DI_CHIPS))
 		else if (strstr(firstname, BFLSC_DI_CHIPS))
 			sc_dev.chips = strdup(fields[0]);
 			sc_dev.chips = strdup(fields[0]);
-		}
+
 		freebreakdown(&count, &firstname, &fields);
 		freebreakdown(&count, &firstname, &fields);
 	}
 	}
 
 
@@ -813,6 +818,19 @@ reinit:
 			break;
 			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->scan_sleep_time = BAS_SCAN_TIME;
 	sc_info->results_sleep_time = BFLSC_RES_TIME;
 	sc_info->results_sleep_time = BFLSC_RES_TIME;
 	sc_info->default_ms_work = BAS_WORK_TIME;
 	sc_info->default_ms_work = BAS_WORK_TIME;
@@ -930,7 +948,7 @@ static void flush_one_dev(struct cgpu_info *bflsc, int dev)
 	rd_lock(&bflsc->qlock);
 	rd_lock(&bflsc->qlock);
 
 
 	HASH_ITER(hh, bflsc->queued_work, work, tmp) {
 	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
 			// devflag is used to flag stale work
 			work->devflag = true;
 			work->devflag = true;
 			did = true;
 			did = true;

+ 1 - 0
driver-bflsc.h

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

+ 12 - 8
driver-icarus.c

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

+ 211 - 71
driver-klondike.c

@@ -44,6 +44,20 @@
 #define MAX_WORK_COUNT		4	// for now, must be binary multiple and match firmware
 #define MAX_WORK_COUNT		4	// for now, must be binary multiple and match firmware
 #define TACH_FACTOR		87890	// fan rpm divisor
 #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;
 struct device_drv klondike_drv;
 
 
 typedef struct klondike_header {
 typedef struct klondike_header {
@@ -152,6 +166,11 @@ typedef struct klist {
 	bool working;
 	bool working;
 } KLIST;
 } KLIST;
 
 
+typedef struct jobque {
+	int workqc;
+	struct timeval last_update;
+} JOBQUE;
+
 struct klondike_info {
 struct klondike_info {
 	bool shutdown;
 	bool shutdown;
 	pthread_rwlock_t stat_lock;
 	pthread_rwlock_t stat_lock;
@@ -165,6 +184,7 @@ struct klondike_info {
 	KLIST *status;
 	KLIST *status;
 	DEVINFO *devinfo;
 	DEVINFO *devinfo;
 	KLIST *cfg;
 	KLIST *cfg;
+	JOBQUE *jobque;
 	int noncecount;
 	int noncecount;
 	uint64_t hashcount;
 	uint64_t hashcount;
 	uint64_t errorcount;
 	uint64_t errorcount;
@@ -183,6 +203,11 @@ struct klondike_info {
 	double nonce_total;
 	double nonce_total;
 	double nonce_min;
 	double nonce_min;
 	double nonce_max;
 	double nonce_max;
+
+	int wque_size;
+	int wque_cleared;
+
+	bool initialised;
 };
 };
 
 
 static KLIST *new_klist_set(struct cgpu_info *klncgpu)
 static KLIST *new_klist_set(struct cgpu_info *klncgpu)
@@ -254,7 +279,7 @@ static KLIST *allocate_kitem(struct cgpu_info *klncgpu)
 	return kitem;
 	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);
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
 
 
@@ -279,6 +304,8 @@ static void release_kitem(struct cgpu_info *klncgpu, KLIST *kitem)
 	klninfo->used_count--;
 	klninfo->used_count--;
 
 
 	cg_wunlock(&klninfo->klist_lock);
 	cg_wunlock(&klninfo->klist_lock);
+
+	return NULL;
 }
 }
 
 
 static double cvtKlnToC(uint8_t temp)
 static double cvtKlnToC(uint8_t temp)
@@ -455,7 +482,9 @@ static bool klondike_get_stats(struct cgpu_info *klncgpu)
 
 
 	applog(LOG_DEBUG, "Klondike getting status");
 	applog(LOG_DEBUG, "Klondike getting status");
 
 
+	rd_lock(&(klninfo->stat_lock));
 	slaves = klninfo->status[0].kline.ws.slavecount;
 	slaves = klninfo->status[0].kline.ws.slavecount;
+	rd_unlock(&(klninfo->stat_lock));
 
 
 	// loop thru devices and get status for each
 	// loop thru devices and get status for each
 	for (dev = 0; dev <= slaves; dev++) {
 	for (dev = 0; dev <= slaves; dev++) {
@@ -464,10 +493,11 @@ static bool klondike_get_stats(struct cgpu_info *klncgpu)
 		kitem = SendCmdGetReply(klncgpu, &kline, 0);
 		kitem = SendCmdGetReply(klncgpu, &kline, 0);
 		if (kitem != NULL) {
 		if (kitem != NULL) {
 			wr_lock(&(klninfo->stat_lock));
 			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));
 			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)
 	KLINE kline;
 	KLINE kline;
 	int slaves, dev;
 	int slaves, dev;
 
 
+	klninfo->initialised = false;
+
 	kline.hd.cmd = 'S';
 	kline.hd.cmd = 'S';
 	kline.hd.dev = 0;
 	kline.hd.dev = 0;
 	kitem = SendCmdGetReply(klncgpu, &kline, 0);
 	kitem = SendCmdGetReply(klncgpu, &kline, 0);
@@ -490,23 +522,27 @@ static bool klondike_init(struct cgpu_info *klncgpu)
 		return false;
 		return false;
 
 
 	slaves = kitem->kline.ws.slavecount;
 	slaves = kitem->kline.ws.slavecount;
-	release_kitem(klncgpu, kitem);
-	kitem = NULL;
 	if (klninfo->status == NULL) {
 	if (klninfo->status == NULL) {
 		applog(LOG_DEBUG, "Klondike initializing data");
 		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))
 		if (unlikely(!klninfo->status))
 			quit(1, "Failed to calloc status array in klondke_get_stats");
 			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))
 		if (unlikely(!klninfo->devinfo))
 			quit(1, "Failed to calloc devinfo array in klondke_get_stats");
 			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))
 		if (unlikely(!klninfo->cfg))
 			quit(1, "Failed to calloc cfg array in klondke_get_stats");
 			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
 	// zero init triggers read back only
 	memset(&(kline.cfg), 0, sizeof(kline.cfg));
 	memset(&(kline.cfg), 0, sizeof(kline.cfg));
 	kline.cfg.cmd = 'C';
 	kline.cfg.cmd = 'C';
@@ -533,17 +569,17 @@ static bool klondike_init(struct cgpu_info *klncgpu)
 		kline.cfg.dev = dev;
 		kline.cfg.dev = dev;
 		kitem = SendCmdGetReply(klncgpu, &kline, size);
 		kitem = SendCmdGetReply(klncgpu, &kline, size);
 		if (kitem != NULL) {
 		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)",
 			applog(LOG_WARNING, "Klondike config (%d: Clk: %d, T:%.0lf, C:%.0lf, F:%d)",
 				dev, K_HASHCLOCK(klninfo->cfg[dev].kline.cfg.hashclock),
 				dev, K_HASHCLOCK(klninfo->cfg[dev].kline.cfg.hashclock),
 				cvtKlnToC(klninfo->cfg[dev].kline.cfg.temptarget),
 				cvtKlnToC(klninfo->cfg[dev].kline.cfg.temptarget),
 				cvtKlnToC(klninfo->cfg[dev].kline.cfg.tempcritical),
 				cvtKlnToC(klninfo->cfg[dev].kline.cfg.tempcritical),
 				(int)100*klninfo->cfg[dev].kline.cfg.fantarget/256);
 				(int)100*klninfo->cfg[dev].kline.cfg.fantarget/256);
-			release_kitem(klncgpu, kitem);
-			kitem = NULL;
+			kitem = release_kitem(klncgpu, kitem);
 		}
 		}
 	}
 	}
 	klondike_get_stats(klncgpu);
 	klondike_get_stats(klncgpu);
+	klninfo->initialised = true;
 	for (dev = 0; dev <= slaves; dev++) {
 	for (dev = 0; dev <= slaves; dev++) {
 		klninfo->devinfo[dev].rangesize = ((uint64_t)1<<32) / klninfo->status[dev].kline.ws.chipcount;
 		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));
 		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)
 	while (tries-- > 0) {
 	while (tries-- > 0) {
 		kitem = SendCmdGetReply(klncgpu, &kline, 1);
 		kitem = SendCmdGetReply(klncgpu, &kline, 1);
 		if (kitem) {
 		if (kitem) {
-			release_kitem(klncgpu, kitem);
-			kitem = NULL;
+			kitem = release_kitem(klncgpu, kitem);
 			ok = true;
 			ok = true;
 			break;
 			break;
 		}
 		}
+		cgsleep_ms(50);
 	}
 	}
+	cgsleep_ms(50);
 
 
 	if (!ok)
 	if (!ok)
 		applog(LOG_ERR, "%s%i: failed to enable", klncgpu->drv->name, klncgpu->device_id);
 		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)
 	return ok;
 	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)
 static bool klondike_detect_one(struct libusb_device *dev, struct usb_find_devices *found)
 {
 {
 	struct cgpu_info *klncgpu = usb_alloc_cgpu(&klondike_drv, 1);
 	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
 		KLIST kitem;
 		KLIST kitem;
 		int attempts = 0;
 		int attempts = 0;
 
 
+		control_init(klncgpu);
+
 		while (attempts++ < 3) {
 		while (attempts++ < 3) {
 			err = usb_write(klncgpu, "I", 2, &sent, C_REQUESTRESULTS);
 			err = usb_write(klncgpu, "I", 2, &sent, C_REQUESTRESULTS);
 			if (err < 0 || sent != 2) {
 			if (err < 0 || sent != 2) {
@@ -613,10 +667,11 @@ static bool klondike_detect_one(struct libusb_device *dev, struct usb_find_devic
 						klncgpu->device_path,
 						klncgpu->device_path,
 						recd);
 						recd);
 			} else if (kitem.kline.hd.cmd == 'I' && kitem.kline.hd.dev == 0) {
 			} 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->drv->dname,
-						  klncgpu->device_path);
+						  klncgpu->device_path,
+						  attempts, attempts == 1 ? "" : "s");
 				if (!add_cgpu(klncgpu))
 				if (!add_cgpu(klncgpu))
 					break;
 					break;
 				update_usb_stats(klncgpu);
 				update_usb_stats(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)
 static void klondike_check_nonce(struct cgpu_info *klncgpu, KLIST *kitem)
 {
 {
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
-	struct work *work, *tmp;
+	struct work *work, *look, *tmp;
 	KLINE *kline = &(kitem->kline);
 	KLINE *kline = &(kitem->kline);
 	struct timeval tv_now;
 	struct timeval tv_now;
 	double us_diff;
 	double us_diff;
@@ -661,43 +716,54 @@ static void klondike_check_nonce(struct cgpu_info *klncgpu, KLIST *kitem)
 	applog(LOG_DEBUG, "Klondike FOUND NONCE (%02x:%08x)",
 	applog(LOG_DEBUG, "Klondike FOUND NONCE (%02x:%08x)",
 			  kline->wr.workid, (unsigned int)nonce);
 			  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;
 				klninfo->delay_min = us_diff;
+			if (klninfo->delay_max < us_diff)
 				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));
 			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_min = us_diff;
 				klninfo->nonce_max = us_diff;
 				klninfo->nonce_max = us_diff;
 			} else {
 			} else {
@@ -706,14 +772,14 @@ static void klondike_check_nonce(struct cgpu_info *klncgpu, KLIST *kitem)
 				if (klninfo->nonce_max < us_diff)
 				if (klninfo->nonce_max < us_diff)
 					klninfo->nonce_max = us_diff;
 					klninfo->nonce_max = us_diff;
 			}
 			}
-			klninfo->nonce_count++;
 			klninfo->nonce_total += us_diff;
 			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",
 	applog(LOG_ERR, "%s%i:%d unknown work (%02x:%08x) - ignored",
@@ -730,9 +796,9 @@ static void *klondike_get_replies(void *userdata)
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
 	KLIST *kitem = NULL;
 	KLIST *kitem = NULL;
 	char *hexdata;
 	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) {
 	while (klninfo->shutdown == false) {
 		if (klncgpu->usbinfo.nodev)
 		if (klncgpu->usbinfo.nodev)
@@ -755,6 +821,22 @@ static void *klondike_get_replies(void *userdata)
 				free(hexdata);
 				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) {
 			switch (kitem->kline.hd.cmd) {
 				case '=':
 				case '=':
 					klondike_check_nonce(klncgpu, kitem);
 					klondike_check_nonce(klncgpu, kitem);
@@ -763,6 +845,25 @@ static void *klondike_get_replies(void *userdata)
 				case 'S':
 				case 'S':
 				case 'W':
 				case 'W':
 				case 'A':
 				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':
 				case 'E':
 					wr_lock(&(klninfo->stat_lock));
 					wr_lock(&(klninfo->stat_lock));
 					klninfo->errorcount += kitem->kline.ws.errorcount;
 					klninfo->errorcount += kitem->kline.ws.errorcount;
@@ -801,17 +902,20 @@ static void klondike_flush_work(struct cgpu_info *klncgpu)
 	klninfo->block_seq++;
 	klninfo->block_seq++;
 
 
 	applog(LOG_DEBUG, "Klondike flushing work");
 	applog(LOG_DEBUG, "Klondike flushing work");
+	rd_lock(&(klninfo->stat_lock));
 	slaves = klninfo->status[0].kline.ws.slavecount;
 	slaves = klninfo->status[0].kline.ws.slavecount;
+	rd_unlock(&(klninfo->stat_lock));
 	kline.hd.cmd = 'A';
 	kline.hd.cmd = 'A';
 	for (dev = 0; dev <= slaves; dev++) {
 	for (dev = 0; dev <= slaves; dev++) {
 		kline.hd.dev = dev;
 		kline.hd.dev = dev;
 		kitem = SendCmdGetReply(klncgpu, &kline, KSENDHD(0));
 		kitem = SendCmdGetReply(klncgpu, &kline, KSENDHD(0));
 		if (kitem != NULL) {
 		if (kitem != NULL) {
 			wr_lock(&(klninfo->stat_lock));
 			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));
 			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)
 		kline.hd.buf[0] = '0';
 		kline.hd.buf[0] = '0';
 		kitem = SendCmdGetReply(klncgpu, &kline, KSENDHD(1));
 		kitem = SendCmdGetReply(klncgpu, &kline, KSENDHD(1));
 		if (kitem)
 		if (kitem)
-			release_kitem(klncgpu, kitem);
+			kitem = release_kitem(klncgpu, kitem);
 	}
 	}
 	klncgpu->shutdown = klninfo->shutdown = true;
 	klncgpu->shutdown = klninfo->shutdown = true;
 }
 }
@@ -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)
 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 klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
-	struct work *tmp;
+	struct work *look, *tmp;
 	KLINE kline;
 	KLINE kline;
+	struct timeval tv_old;
+	int wque_size, wque_cleared;
 
 
 	if (klncgpu->usbinfo.nodev)
 	if (klncgpu->usbinfo.nodev)
 		return false;
 		return false;
@@ -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);
 	memcpy(kline.wt.merkle, work->data + MERKLE_OFFSET, MERKLE_BYTES);
 	kline.wt.workid = (uint8_t)(klninfo->devinfo[dev].nextworkid++ & 0xFF);
 	kline.wt.workid = (uint8_t)(klninfo->devinfo[dev].nextworkid++ & 0xFF);
 	work->subid = dev*256 + kline.wt.workid;
 	work->subid = dev*256 + kline.wt.workid;
+	cgtime(&work->tv_stamp);
 
 
 	if (opt_log_level <= LOG_DEBUG) {
 	if (opt_log_level <= LOG_DEBUG) {
 		char *hexdata = bin2hex((void *)&kline.wt, sizeof(kline.wt));
 		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 *
 	KLIST *kitem = SendCmdGetReply(klncgpu, &kline, sizeof(kline.wt));
 	KLIST *kitem = SendCmdGetReply(klncgpu, &kline, sizeof(kline.wt));
 	if (kitem != NULL) {
 	if (kitem != NULL) {
 		wr_lock(&(klninfo->stat_lock));
 		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));
 		wr_unlock(&(klninfo->stat_lock));
-		release_kitem(klncgpu, kitem);
-		kitem = NULL;
+		kitem = release_kitem(klncgpu, kitem);
 
 
 		// remove old work
 		// 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 true;
 	}
 	}
 	return false;
 	return false;
@@ -929,20 +1048,38 @@ static bool klondike_queue_full(struct cgpu_info *klncgpu)
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
 	struct klondike_info *klninfo = (struct klondike_info *)(klncgpu->device_data);
 	struct work *work = NULL;
 	struct work *work = NULL;
 	int dev, queued, slaves;
 	int dev, queued, slaves;
+	struct timeval now;
+
 
 
+	cgtime(&now);
+	rd_lock(&(klninfo->stat_lock));
 	slaves = klninfo->status[0].kline.ws.slavecount;
 	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 (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)
 				if (!work)
 					work = get_queued(klncgpu);
 					work = get_queued(klncgpu);
 				if (unlikely(!work))
 				if (unlikely(!work))
 					return false;
 					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;
 	return true;
 }
 }
@@ -1100,6 +1237,9 @@ static struct api_data *klondike_api_stats(struct cgpu_info *klncgpu)
 		avg = klninfo->nonce_total / klninfo->nonce_count;
 		avg = klninfo->nonce_total / klninfo->nonce_count;
 	root = api_add_diff(root, "KQue Nonce Avg", &avg, true);
 	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));
 	rd_unlock(&(klninfo->stat_lock));
 
 
 	return root;
 	return root;

+ 130 - 51
miner.h

@@ -575,6 +575,7 @@ struct cgpu_info {
 
 
 	pthread_rwlock_t qlock;
 	pthread_rwlock_t qlock;
 	struct work *queued_work;
 	struct work *queued_work;
+	struct work *unqueued_work;
 	unsigned int queued_count;
 	unsigned int queued_count;
 
 
 	bool shutdown;
 	bool shutdown;
@@ -738,74 +739,143 @@ endian_flip128(void __maybe_unused *dest_p, const void __maybe_unused *src_p)
 
 
 extern void _quit(int status);
 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)
 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)))
 	if (unlikely(pthread_mutex_lock(lock)))
 		quitfrom(1, file, func, line, "WTF MUTEX ERROR ON LOCK! errno=%d", errno);
 		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)
 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)))
 	if (unlikely(pthread_mutex_unlock(lock)))
 		quitfrom(1, file, func, line, "WTF MUTEX ERROR ON UNLOCK! errno=%d", errno);
 		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();
 	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)
 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)))
 	if (unlikely(pthread_rwlock_wrlock(lock)))
 		quitfrom(1, file, func, line, "WTF WRLOCK ERROR ON LOCK! errno=%d", errno);
 		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)
 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)))
 	if (unlikely(pthread_rwlock_rdlock(lock)))
 		quitfrom(1, file, func, line, "WTF RDLOCK ERROR ON LOCK! errno=%d", errno);
 		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)
 static inline void _rw_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
 {
 {
 	if (unlikely(pthread_rwlock_unlock(lock)))
 	if (unlikely(pthread_rwlock_unlock(lock)))
 		quitfrom(1, file, func, line, "WTF RWLOCK ERROR ON UNLOCK! errno=%d", errno);
 		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();
 	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();
 	sched_yield();
 }
 }
 
 
@@ -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)))
 	if (unlikely(pthread_mutex_init(lock, NULL)))
 		quitfrom(1, file, func, line, "Failed to pthread_mutex_init errno=%d", errno);
 		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)
 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)))
 	if (unlikely(pthread_rwlock_init(lock, NULL)))
 		quitfrom(1, file, func, line, "Failed to pthread_rwlock_init errno=%d", errno);
 		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. */
 /* 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
 /* Intermediate variant of cglock - behaves as a read lock but can be promoted
  * to a write lock or demoted to read lock. */
  * 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 */
 /* 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 */
 /* 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 */
 /* 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 */
 /* 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 */
 /* 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
 /* This drops the read lock and grabs a write lock. It does NOT protect data
  * between the two locks! */
  * 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;
 struct pool;
@@ -943,6 +1015,10 @@ extern bool opt_bfl_noncerange;
 #endif
 #endif
 extern int swork_id;
 extern int swork_id;
 
 
+#if LOCK_TRACKING
+extern pthread_mutex_t lockstat_lock;
+#endif
+
 extern pthread_rwlock_t netacc_lock;
 extern pthread_rwlock_t netacc_lock;
 
 
 extern const uint32_t sha256_init_state[];
 extern const uint32_t sha256_init_state[];
@@ -1066,6 +1142,7 @@ extern struct pool **pools;
 extern struct strategies strategies[];
 extern struct strategies strategies[];
 extern enum pool_strategy pool_strategy;
 extern enum pool_strategy pool_strategy;
 extern int opt_rotate_period;
 extern int opt_rotate_period;
+extern double total_rolling;
 extern double total_mhashes_done;
 extern double total_mhashes_done;
 extern unsigned int new_blocks;
 extern unsigned int new_blocks;
 extern unsigned int found_blocks;
 extern unsigned int found_blocks;
@@ -1306,7 +1383,6 @@ struct work {
 	bool		stale;
 	bool		stale;
 	bool		mandatory;
 	bool		mandatory;
 	bool		block;
 	bool		block;
-	bool		queued;
 
 
 	bool		stratum;
 	bool		stratum;
 	char 		*job_id;
 	char 		*job_id;
@@ -1330,6 +1406,8 @@ struct work {
 	int		subid;
 	int		subid;
 	// Allow devices to flag work for their own purposes
 	// Allow devices to flag work for their own purposes
 	bool		devflag;
 	bool		devflag;
+	// Allow devices to timestamp work for their own purposes
+	struct timeval	tv_stamp;
 
 
 	struct timeval	tv_getwork;
 	struct timeval	tv_getwork;
 	struct timeval	tv_getwork_reply;
 	struct timeval	tv_getwork_reply;
@@ -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_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 *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 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 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 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);
 extern void hash_driver_work(struct thr_info *mythr);

+ 61 - 24
usbutils.c

@@ -330,6 +330,18 @@ static struct usb_find_devices find_dev[] = {
 		.timeout = AVALON_TIMEOUT_MS,
 		.timeout = AVALON_TIMEOUT_MS,
 		.latency = 10,
 		.latency = 10,
 		INTINFO(ava_ints) },
 		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,
 		.drv = DRIVER_avalon,
 		.name = "AVA",
 		.name = "AVA",
@@ -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);
 	err = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer, man, STRBUFLEN);
 	if (err < 0)
 	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);
 	err = libusb_get_string_descriptor_ascii(handle, desc.iProduct, prod, STRBUFLEN);
 	if (err < 0)
 	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) {
 	if (level == 0) {
 		libusb_close(handle);
 		libusb_close(handle);
@@ -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);
 	err = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber, ser, STRBUFLEN);
 	if (err < 0)
 	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
 	snprintf(tmp, sizeof(tmp), EOL "     dev %d: More Info:" EOL "\tManufacturer: '%s'" EOL
 			"\tProduct: '%s'" EOL "\tSerial '%s'",
 			"\tProduct: '%s'" EOL "\tSerial '%s'",
@@ -933,7 +945,7 @@ void usb_all(int level)
 
 
 	count = libusb_get_device_list(NULL, &list);
 	count = libusb_get_device_list(NULL, &list);
 	if (count < 0) {
 	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;
 		return;
 	}
 	}
 
 
@@ -2242,6 +2254,12 @@ static void init_usb_transfer(struct usb_transfer *ut)
 	ut->transfer->user_data = 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)
 static void LIBUSB_CALL transfer_callback(struct libusb_transfer *transfer)
 {
 {
 	struct usb_transfer *ut = transfer->user_data;
 	struct usb_transfer *ut = transfer->user_data;
@@ -2265,7 +2283,7 @@ static int callback_wait(struct usb_transfer *ut, int *transferred, unsigned int
 		cgsem_wait(&ut->cgsem);
 		cgsem_wait(&ut->cgsem);
 	}
 	}
 	ret = transfer->status;
 	ret = transfer->status;
-	if (ret == LIBUSB_TRANSFER_CANCELLED)
+	if (ret == LIBUSB_TRANSFER_CANCELLED || ret == LIBUSB_TRANSFER_TIMED_OUT)
 		ret = LIBUSB_ERROR_TIMEOUT;
 		ret = LIBUSB_ERROR_TIMEOUT;
 
 
 	/* No need to sort out mutexes here since they won't be reused */
 	/* 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,
 	usb_epinfo = &(cgpu->usbdev->found->intinfos[intinfo].epinfos[epinfo]);
 	usb_epinfo = &(cgpu->usbdev->found->intinfos[intinfo].epinfos[epinfo]);
 	endpoint = usb_epinfo->ep;
 	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
 	/* Limit length of transfer to the largest this descriptor supports
 	 * and leave the higher level functions to transfer more if needed. */
 	 * and leave the higher level functions to transfer more if needed. */
 	if (usb_epinfo->PrefPacketSize)
 	if (usb_epinfo->PrefPacketSize)
@@ -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);
 	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);
 	init_usb_transfer(&ut);
+#ifdef LINUX
 	/* We give the transfer no timeout since we manage timeouts ourself */
 	/* We give the transfer no timeout since we manage timeouts ourself */
 	libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length,
 	libusb_fill_bulk_transfer(ut.transfer, dev_handle, endpoint, buf, length,
 				  transfer_callback, &ut, 0);
 				  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);
 	STATS_TIMEVAL(&tv_start);
 	cg_rlock(&cgusb_fd_lock);
 	cg_rlock(&cgusb_fd_lock);
 	err = libusb_submit_transfer(ut.transfer);
 	err = libusb_submit_transfer(ut.transfer);
@@ -2319,7 +2347,7 @@ usb_bulk_transfer(struct libusb_device_handle *dev_handle, int intinfo,
 	errn = errno;
 	errn = errno;
 	if (!err)
 	if (!err)
 		err = callback_wait(&ut, transferred, timeout);
 		err = callback_wait(&ut, transferred, timeout);
-	libusb_free_transfer(ut.transfer);
+	complete_usb_transfer(&ut);
 
 
 	STATS_TIMEVAL(&tv_finish);
 	STATS_TIMEVAL(&tv_finish);
 	USB_STATS(cgpu, &tv_start, &tv_finish, err, mode, cmd, seq, timeout);
 	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
 
 
 out_unlock:
 out_unlock:
 	if (err && err != LIBUSB_ERROR_TIMEOUT) {
 	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)
 		if (cgpu->usbinfo.continuous_ioerr_count > USB_RETRY_MAX)
 			err = LIBUSB_ERROR_OTHER;
 			err = LIBUSB_ERROR_OTHER;
 	}
 	}
@@ -2712,8 +2740,8 @@ int _usb_write(struct cgpu_info *cgpu, int intinfo, int epinfo, char *buf, size_
 	*processed = tot;
 	*processed = tot;
 
 
 	if (err) {
 	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)
 		if (cgpu->usbinfo.continuous_ioerr_count > USB_RETRY_MAX)
 			err = LIBUSB_ERROR_OTHER;
 			err = LIBUSB_ERROR_OTHER;
 	}
 	}
@@ -2731,7 +2759,7 @@ out_noerrmsg:
 /* As we do for bulk reads, emulate a sync function for control transfers using
 /* 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.
  * 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,
 				uint8_t bRequest, uint16_t wValue, uint16_t wIndex,
 				unsigned char *buffer, uint16_t wLength, unsigned int timeout)
 				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
 	unsigned char buf[70];
 	unsigned char buf[70];
 	int err, transferred;
 	int err, transferred;
 
 
+	if (unlikely(cgpu->shutdown))
+		return libusb_control_transfer(dev_handle, bmRequestType, bRequest, wValue, wIndex, buffer, wLength, timeout);
+
 	init_usb_transfer(&ut);
 	init_usb_transfer(&ut);
 	libusb_fill_control_setup(buf, bmRequestType, bRequest, wValue,
 	libusb_fill_control_setup(buf, bmRequestType, bRequest, wValue,
 				  wIndex, wLength);
 				  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,
 	libusb_fill_control_transfer(ut.transfer, dev_handle, buf, transfer_callback,
 				     &ut, 0);
 				     &ut, 0);
+#else
+	libusb_fill_control_transfer(ut.transfer, dev_handle, buf, transfer_callback,
+				     &ut, timeout);
+#endif
 	err = libusb_submit_transfer(ut.transfer);
 	err = libusb_submit_transfer(ut.transfer);
 	if (!err)
 	if (!err)
 		err = callback_wait(&ut, &transferred, timeout);
 		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;
 		err = transferred;
 		goto out;
 		goto out;
 	}
 	}
 	if ((err) == LIBUSB_TRANSFER_CANCELLED)
 	if ((err) == LIBUSB_TRANSFER_CANCELLED)
 		err = LIBUSB_ERROR_TIMEOUT;
 		err = LIBUSB_ERROR_TIMEOUT;
 out:
 out:
-	libusb_free_transfer(ut.transfer);
+	complete_usb_transfer(&ut);
 	return err;
 	return err;
 }
 }
 
 
@@ -2817,8 +2855,8 @@ int __usb_transfer(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bReques
 	}
 	}
 	STATS_TIMEVAL(&tv_start);
 	STATS_TIMEVAL(&tv_start);
 	cg_rlock(&cgusb_fd_lock);
 	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);
 	cg_runlock(&cgusb_fd_lock);
 	STATS_TIMEVAL(&tv_finish);
 	STATS_TIMEVAL(&tv_finish);
 	USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_CTRL_WRITE, cmd, SEQ0, timeout);
 	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
 	IOERR_CHECK(cgpu, err);
 	IOERR_CHECK(cgpu, err);
 
 
 	if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
 	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));
 		       err, libusb_error_name(err));
 	}
 	}
 out_:
 out_:
@@ -2899,9 +2937,8 @@ int _usb_transfer_read(struct cgpu_info *cgpu, uint8_t request_type, uint8_t bRe
 	memset(tbuf, 0, 64);
 	memset(tbuf, 0, 64);
 	STATS_TIMEVAL(&tv_start);
 	STATS_TIMEVAL(&tv_start);
 	cg_rlock(&cgusb_fd_lock);
 	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);
 	cg_runlock(&cgusb_fd_lock);
 	STATS_TIMEVAL(&tv_finish);
 	STATS_TIMEVAL(&tv_finish);
 	USB_STATS(cgpu, &tv_start, &tv_finish, err, MODE_CTRL_READ, cmd, SEQ0, timeout);
 	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
 		err = 0;
 		err = 0;
 	}
 	}
 	if (err < 0 && err != LIBUSB_ERROR_TIMEOUT) {
 	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));
 		       err, libusb_error_name(err));
 	}
 	}
 out_noerrmsg:
 out_noerrmsg:

+ 1 - 0
usbutils.h

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

+ 41 - 0
util.c

@@ -2485,3 +2485,44 @@ void _cgsem_destroy(cgsem_t *cgsem)
 	sem_destroy(cgsem);
 	sem_destroy(cgsem);
 }
 }
 #endif
 #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 - 0
util.h

@@ -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);
 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);
 int _cgsem_mswait(cgsem_t *cgsem, int ms, const char *file, const char *func, const int line);
 void _cgsem_destroy(cgsem_t *cgsem);
 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_init(_sem) _cgsem_init(_sem, __FILE__, __func__, __LINE__)
 #define cgsem_post(_sem) _cgsem_post(_sem, __FILE__, __func__, __LINE__)
 #define cgsem_post(_sem) _cgsem_post(_sem, __FILE__, __func__, __LINE__)