Browse Source

Abstract generally useful FPGA code into fpgautils.c

Luke Dashjr 13 years ago
parent
commit
d3fa59d76f
10 changed files with 364 additions and 232 deletions
  1. 4 0
      Makefile.am
  2. 1 1
      README
  3. 24 7
      cgminer.c
  4. 1 0
      configure.ac
  5. 7 141
      driver-bitforce.c
  6. 7 77
      driver-icarus.c
  7. 273 0
      fpgautils.c
  8. 39 0
      fpgautils.h
  9. 7 6
      libztex.c
  10. 1 0
      miner.h

+ 4 - 0
Makefile.am

@@ -68,6 +68,10 @@ endif # HAVE_x86_64
 endif # HAS_YASM
 endif # HAS_YASM
 endif # HAS_CPUMINE
 endif # HAS_CPUMINE
 
 
+if NEED_FPGAUTILS
+cgminer_SOURCES += fpgautils.c
+endif
+
 if HAS_BITFORCE
 if HAS_BITFORCE
 cgminer_SOURCES += driver-bitforce.c
 cgminer_SOURCES += driver-bitforce.c
 endif
 endif

+ 1 - 1
README

@@ -129,6 +129,7 @@ Options for both config file and command line:
 --debug|-D          Enable debug output
 --debug|-D          Enable debug output
 --expiry|-E <arg>   Upper bound on how many seconds after getting work we consider a share from it stale (default: 120)
 --expiry|-E <arg>   Upper bound on how many seconds after getting work we consider a share from it stale (default: 120)
 --failover-only     Don't leak work to backup pools when primary pool is lagging
 --failover-only     Don't leak work to backup pools when primary pool is lagging
+--kernel-path|-K <arg> Specify a path to where bitstream and kernel files are (default: "/usr/local/bin")
 --load-balance      Change multipool strategy from failover to even load balance
 --load-balance      Change multipool strategy from failover to even load balance
 --log|-l <arg>      Interval in seconds between log output (default: 5)
 --log|-l <arg>      Interval in seconds between log output (default: 5)
 --monitor|-m <arg>  Use custom pipe cmd for output messages
 --monitor|-m <arg>  Use custom pipe cmd for output messages
@@ -184,7 +185,6 @@ GPU only options:
 --gpu-vddc <arg>    Set the GPU voltage in Volts - one value for all or separate by commas for per card.
 --gpu-vddc <arg>    Set the GPU voltage in Volts - one value for all or separate by commas for per card.
 --intensity|-I <arg> Intensity of GPU scanning (d or -10 -> 10, default: d to maintain desktop interactivity)
 --intensity|-I <arg> Intensity of GPU scanning (d or -10 -> 10, default: d to maintain desktop interactivity)
 --kernel|-k <arg>   Override kernel to use (diablo, poclbm, phatk or diakgcn) - one value or comma separated
 --kernel|-k <arg>   Override kernel to use (diablo, poclbm, phatk or diakgcn) - one value or comma separated
---kernel-path|-K <arg> Specify a path to where the kernel .cl files are (default: "/usr/local/bin")
 --ndevs|-n          Enumerate number of detected GPUs and exit
 --ndevs|-n          Enumerate number of detected GPUs and exit
 --no-restart        Do not attempt to restart GPUs that hang
 --no-restart        Do not attempt to restart GPUs that hang
 --temp-hysteresis <arg> Set how much the temperature can fluctuate outside limits when automanaging speeds (default: 3)
 --temp-hysteresis <arg> Set how much the temperature can fluctuate outside limits when automanaging speeds (default: 3)

+ 24 - 7
cgminer.c

@@ -54,6 +54,13 @@
 	#include <sys/wait.h>
 	#include <sys/wait.h>
 #endif
 #endif
 
 
+#if defined(USE_BITFORCE) || defined(USE_ICARUS) || defined(USE_MODMINER)
+#	define USE_FPGA
+#	define USE_FPGA_SERIAL
+#elif defined(USE_ZTEX)
+#	define USE_FPGA
+#endif
+
 enum workio_commands {
 enum workio_commands {
 	WC_GET_WORK,
 	WC_GET_WORK,
 	WC_SUBMIT_WORK,
 	WC_SUBMIT_WORK,
@@ -468,7 +475,7 @@ static char *set_int_1_to_10(const char *arg, int *i)
 	return set_int_range(arg, i, 1, 10);
 	return set_int_range(arg, i, 1, 10);
 }
 }
 
 
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#ifdef USE_FPGA_SERIAL
 static char *add_serial(char *arg)
 static char *add_serial(char *arg)
 {
 {
 	string_elist_add(arg, &scan_devices);
 	string_elist_add(arg, &scan_devices);
@@ -768,7 +775,7 @@ static struct opt_table opt_config_table[] = {
 			opt_hidden
 			opt_hidden
 #endif
 #endif
 	),
 	),
-#if defined(WANT_CPUMINE) && (defined(HAVE_OPENCL) || defined(USE_BITFORCE) || defined(USE_ICARUS))
+#if defined(WANT_CPUMINE) && (defined(HAVE_OPENCL) || defined(USE_FPGA))
 	OPT_WITHOUT_ARG("--enable-cpu|-C",
 	OPT_WITHOUT_ARG("--enable-cpu|-C",
 			opt_set_bool, &opt_usecpu,
 			opt_set_bool, &opt_usecpu,
 			"Enable CPU mining with other mining (default: no CPU mining if other devices exist)"),
 			"Enable CPU mining with other mining (default: no CPU mining if other devices exist)"),
@@ -818,9 +825,13 @@ static struct opt_table opt_config_table[] = {
 	OPT_WITH_ARG("--intensity|-I",
 	OPT_WITH_ARG("--intensity|-I",
 		     set_intensity, NULL, NULL,
 		     set_intensity, NULL, NULL,
 		     "Intensity of GPU scanning (d or " _MIN_INTENSITY_STR " -> " _MAX_INTENSITY_STR ", default: d to maintain desktop interactivity)"),
 		     "Intensity of GPU scanning (d or " _MIN_INTENSITY_STR " -> " _MAX_INTENSITY_STR ", default: d to maintain desktop interactivity)"),
+#endif
+#if defined(HAVE_OPENCL) || defined(HAVE_MODMINER)
 	OPT_WITH_ARG("--kernel-path|-K",
 	OPT_WITH_ARG("--kernel-path|-K",
 		     opt_set_charp, opt_show_charp, &opt_kernel_path,
 		     opt_set_charp, opt_show_charp, &opt_kernel_path,
-	             "Specify a path to where the kernel .cl files are"),
+	             "Specify a path to where bitstream and kernel files are"),
+#endif
+#ifdef HAVE_OPENCL
 	OPT_WITH_ARG("--kernel|-k",
 	OPT_WITH_ARG("--kernel|-k",
 		     set_kernel, NULL, NULL,
 		     set_kernel, NULL, NULL,
 		     "Override kernel to use (diablo, poclbm, phatk or diakgcn) - one value or comma separated"),
 		     "Override kernel to use (diablo, poclbm, phatk or diakgcn) - one value or comma separated"),
@@ -899,7 +910,7 @@ static struct opt_table opt_config_table[] = {
 	OPT_WITHOUT_ARG("--round-robin",
 	OPT_WITHOUT_ARG("--round-robin",
 		     set_rr, &pool_strategy,
 		     set_rr, &pool_strategy,
 		     "Change multipool strategy from failover to round robin on failure"),
 		     "Change multipool strategy from failover to round robin on failure"),
-#if defined(USE_BITFORCE) || defined(USE_ICARUS)
+#ifdef USE_FPGA_SERIAL
 	OPT_WITH_ARG("--scan-serial|-S",
 	OPT_WITH_ARG("--scan-serial|-S",
 		     add_serial, NULL, NULL,
 		     add_serial, NULL, NULL,
 		     "Serial port to probe for FPGA Mining device"),
 		     "Serial port to probe for FPGA Mining device"),
@@ -927,7 +938,7 @@ static struct opt_table opt_config_table[] = {
 			opt_set_bool, &use_syslog,
 			opt_set_bool, &use_syslog,
 			"Use system log for output messages (default: standard error)"),
 			"Use system log for output messages (default: standard error)"),
 #endif
 #endif
-#if defined(HAVE_ADL) || defined(USE_BITFORCE)
+#if defined(HAVE_ADL) || defined(USE_BITFORCE) || defined(USE_MODMINER)
 	OPT_WITH_ARG("--temp-cutoff",
 	OPT_WITH_ARG("--temp-cutoff",
 		     set_temp_cutoff, opt_show_intval, &opt_cutofftemp,
 		     set_temp_cutoff, opt_show_intval, &opt_cutofftemp,
 		     "Temperature where a device will be automatically disabled, one value or comma separated list"),
 		     "Temperature where a device will be automatically disabled, one value or comma separated list"),
@@ -3729,15 +3740,21 @@ bool hashtest(const struct work *work)
 
 
 }
 }
 
 
-bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
+bool test_nonce(struct work *work, uint32_t nonce)
 {
 {
 	work->data[64 + 12 + 0] = (nonce >> 0) & 0xff;
 	work->data[64 + 12 + 0] = (nonce >> 0) & 0xff;
 	work->data[64 + 12 + 1] = (nonce >> 8) & 0xff;
 	work->data[64 + 12 + 1] = (nonce >> 8) & 0xff;
 	work->data[64 + 12 + 2] = (nonce >> 16) & 0xff;
 	work->data[64 + 12 + 2] = (nonce >> 16) & 0xff;
 	work->data[64 + 12 + 3] = (nonce >> 24) & 0xff;
 	work->data[64 + 12 + 3] = (nonce >> 24) & 0xff;
 
 
+	return hashtest(work);
+}
+
+bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce)
+{
 	/* Do one last check before attempting to submit the work */
 	/* Do one last check before attempting to submit the work */
-	if (!hashtest(work)) {
+	/* Side effect: sets work->data for us */
+	if (!test_nonce(work, nonce)) {
 		applog(LOG_INFO, "Share below target");
 		applog(LOG_INFO, "Share below target");
 		return true;
 		return true;
 	}
 	}

+ 1 - 0
configure.ac

@@ -245,6 +245,7 @@ else
 fi
 fi
 
 
 
 
+AM_CONDITIONAL([NEED_FPGAUTILS], [test x$icarus$bitforce$ztex != xnonono])
 AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes])
 AM_CONDITIONAL([HAVE_CURSES], [test x$curses = xyes])
 AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue])
 AM_CONDITIONAL([WANT_JANSSON], [test x$request_jansson = xtrue])
 AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue])
 AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue])

+ 7 - 141
driver-bitforce.c

@@ -13,62 +13,17 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <strings.h>
 #include <strings.h>
 #include <sys/time.h>
 #include <sys/time.h>
-#include <sys/types.h>
-#include <dirent.h>
-#ifndef WIN32
-#include <termios.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#ifndef O_CLOEXEC
-#define O_CLOEXEC 0
-#endif
-#else
-#include <windows.h>
-#include <io.h>
-#endif
 #include <unistd.h>
 #include <unistd.h>
 
 
 #include "config.h"
 #include "config.h"
 
 
-#ifdef HAVE_LIBUDEV
-#include <libudev.h>
-#endif
-
-#include "elist.h"
+#include "fpgautils.h"
 #include "miner.h"
 #include "miner.h"
 
 
 
 
 struct device_api bitforce_api;
 struct device_api bitforce_api;
 
 
-static int BFopen(const char *devpath)
-{
-#ifdef WIN32
-	HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
-	if (unlikely(hSerial == INVALID_HANDLE_VALUE))
-		return -1;
-	
-	COMMTIMEOUTS cto = {30000, 0, 30000, 0, 30000};
-	SetCommTimeouts(hSerial, &cto);
-	
-	return _open_osfhandle((LONG)hSerial, 0);
-#else
-	int fdDev = open(devpath, O_RDWR | O_CLOEXEC | O_NOCTTY);
-	if (likely(fdDev != -1)) {
-		struct termios pattr;
-		
-		tcgetattr(fdDev, &pattr);
-		pattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
-		pattr.c_oflag &= ~OPOST;
-		pattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
-		pattr.c_cflag &= ~(CSIZE | PARENB);
-		pattr.c_cflag |= CS8;
-		tcsetattr(fdDev, TCSANOW, &pattr);
-	}
-	tcflush(fdDev, TCOFLUSH);
-	tcflush(fdDev, TCIFLUSH);
-	return fdDev;
-#endif
-}
+#define BFopen(devpath)  serial_open(devpath, 0, -1, true)
 
 
 static void BFgets(char *buf, size_t bufLen, int fd)
 static void BFgets(char *buf, size_t bufLen, int fd)
 {
 {
@@ -98,9 +53,6 @@ static bool bitforce_detect_one(const char *devpath)
 	char *s;
 	char *s;
 	char pdevbuf[0x100];
 	char pdevbuf[0x100];
 
 
-	if (total_devices == MAX_DEVICES)
-		return false;
-
 	int fdDev = BFopen(devpath);
 	int fdDev = BFopen(devpath);
 	if (unlikely(fdDev == -1)) {
 	if (unlikely(fdDev == -1)) {
 		applog(LOG_DEBUG, "BitForce Detect: Failed to open %s", devpath);
 		applog(LOG_DEBUG, "BitForce Detect: Failed to open %s", devpath);
@@ -134,103 +86,17 @@ static bool bitforce_detect_one(const char *devpath)
 	return add_cgpu(bitforce);
 	return add_cgpu(bitforce);
 }
 }
 
 
-static bool bitforce_detect_auto_udev()
+static char bitforce_detect_auto()
 {
 {
-#ifdef HAVE_LIBUDEV
-	struct udev *udev = udev_new();
-	struct udev_enumerate *enumerate = udev_enumerate_new(udev);
-	struct udev_list_entry *list_entry;
-	bool foundany = false;
-	
-	udev_enumerate_add_match_subsystem(enumerate, "tty");
-	udev_enumerate_add_match_property(enumerate, "ID_MODEL", "BitFORCE*SHA256");
-	udev_enumerate_scan_devices(enumerate);
-	udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
-		struct udev_device *device = udev_device_new_from_syspath(
-			udev_enumerate_get_udev(enumerate),
-			udev_list_entry_get_name(list_entry)
-		);
-		if (!device)
-			continue;
-		
-		const char *devpath = udev_device_get_devnode(device);
-		if (devpath) {
-			foundany = true;
-			bitforce_detect_one(devpath);
-		}
-		
-		udev_device_unref(device);
-	}
-	udev_enumerate_unref(enumerate);
-	udev_unref(udev);
-	
-	return foundany;
-#else
-	return false;
-#endif
-}
-
-static bool bitforce_detect_auto_devserial()
-{
-#ifndef WIN32
-	DIR *D;
-	struct dirent *de;
-	const char udevdir[] = "/dev/serial/by-id";
-	char devpath[sizeof(udevdir) + 1 + NAME_MAX];
-	char *devfile = devpath + sizeof(udevdir);
-	bool foundany = false;
-	
-	D = opendir(udevdir);
-	if (!D)
-		return false;
-	memcpy(devpath, udevdir, sizeof(udevdir) - 1);
-	devpath[sizeof(udevdir) - 1] = '/';
-	while ( (de = readdir(D)) ) {
-		if (!strstr(de->d_name, "BitFORCE_SHA256"))
-			continue;
-		foundany = true;
-		strcpy(devfile, de->d_name);
-		bitforce_detect_one(devpath);
-	}
-	closedir(D);
-	
-	return foundany;
-#else
-	return false;
-#endif
-}
-
-static void bitforce_detect_auto()
-{
-	bitforce_detect_auto_udev() ?:
-	bitforce_detect_auto_devserial() ?:
+	return
+	serial_autodetect_udev     (bitforce_detect_one, "BitFORCE*SHA256") ?:
+	serial_autodetect_devserial(bitforce_detect_one, "BitFORCE_SHA256") ?:
 	0;
 	0;
 }
 }
 
 
 static void bitforce_detect()
 static void bitforce_detect()
 {
 {
-	struct string_elist *iter, *tmp;
-	const char*s;
-	bool found = false;
-	bool autoscan = false;
-
-	list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
-		s = iter->string;
-		if (!strncmp("bitforce:", iter->string, 9))
-			s += 9;
-		if (!strcmp(s, "auto"))
-			autoscan = true;
-		else
-		if (!strcmp(s, "noauto"))
-			found = true;
-		else if (bitforce_detect_one(s)) {
-			string_elist_del(iter);
-			found = true;
-		}
-	}
-
-	if (autoscan || !found)
-		bitforce_detect_auto();
+	serial_detect_auto("bitforce", bitforce_detect_one, bitforce_detect_auto);
 }
 }
 
 
 static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)
 static void get_bitforce_statline_before(char *buf, struct cgpu_info *bitforce)

+ 7 - 77
driver-icarus.c

@@ -49,6 +49,7 @@
 #endif
 #endif
 
 
 #include "elist.h"
 #include "elist.h"
+#include "fpgautils.h"
 #include "miner.h"
 #include "miner.h"
 
 
 // The serial I/O speed - Linux uses a define 'B115200' in bits/termios.h
 // The serial I/O speed - Linux uses a define 'B115200' in bits/termios.h
@@ -69,10 +70,8 @@ ASSERT1(sizeof(uint32_t) == 4);
 // Fraction of a second, USB timeout is measured in
 // Fraction of a second, USB timeout is measured in
 // i.e. 10 means 1/10 of a second
 // i.e. 10 means 1/10 of a second
 #define TIME_FACTOR 10
 #define TIME_FACTOR 10
-// In Linux it's 10 per second, thus value = 10/TIME_FACTOR =
-#define LINUX_TIMEOUT_VALUE 1
-// In Windows it's 1000 per second, thus value = 1000/TIME_FACTOR =
-#define WINDOWS_TIMEOUT_VALUE 100
+// It's 10 per second, thus value = 10/TIME_FACTOR =
+#define ICARUS_READ_FAULT_DECISECONDS 1
 
 
 // In timing mode: Default starting value until an estimate can be obtained
 // In timing mode: Default starting value until an estimate can be obtained
 // 5 seconds allows for up to a ~840MH/s device
 // 5 seconds allows for up to a ~840MH/s device
@@ -196,63 +195,8 @@ static void rev(unsigned char *s, size_t l)
 	}
 	}
 }
 }
 
 
-static int icarus_open(const char *devpath)
-{
-#ifndef WIN32
-	struct termios my_termios;
-
-	int serialfd = open(devpath, O_RDWR | O_CLOEXEC | O_NOCTTY);
-
-	if (serialfd == -1)
-		return -1;
-
-	tcgetattr(serialfd, &my_termios);
-	my_termios.c_cflag = B115200;
-	my_termios.c_cflag |= CS8;
-	my_termios.c_cflag |= CREAD;
-	my_termios.c_cflag |= CLOCAL;
-	my_termios.c_cflag &= ~(CSIZE | PARENB);
-
-	my_termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK |
-				ISTRIP | INLCR | IGNCR | ICRNL | IXON);
-	my_termios.c_oflag &= ~OPOST;
-	my_termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
-	my_termios.c_cc[VTIME] = LINUX_TIMEOUT_VALUE; /* how long to block */
-	my_termios.c_cc[VMIN] = 0;
-	tcsetattr(serialfd, TCSANOW, &my_termios);
-
-	tcflush(serialfd, TCOFLUSH);
-	tcflush(serialfd, TCIFLUSH);
-
-	return serialfd;
-#else
-	COMMCONFIG comCfg;
-
-	HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0,
-				    NULL, OPEN_EXISTING, 0, NULL);
-	if (unlikely(hSerial == INVALID_HANDLE_VALUE))
-		return -1;
-
-	// thanks to af_newbie for pointers about this
-	memset(&comCfg, 0 , sizeof(comCfg));
-	comCfg.dwSize = sizeof(COMMCONFIG);
-	comCfg.wVersion = 1;
-	comCfg.dcb.DCBlength = sizeof(DCB);
-	comCfg.dcb.BaudRate = ICARUS_IO_SPEED;
-	comCfg.dcb.fBinary = 1;
-	comCfg.dcb.fDtrControl = DTR_CONTROL_ENABLE;
-	comCfg.dcb.fRtsControl = RTS_CONTROL_ENABLE;
-	comCfg.dcb.ByteSize = 8;
-
-	SetCommConfig(hSerial, &comCfg, sizeof(comCfg));
-
-	// How long to block
-	COMMTIMEOUTS cto = {WINDOWS_TIMEOUT_VALUE, 0, WINDOWS_TIMEOUT_VALUE, 0, WINDOWS_TIMEOUT_VALUE};
-	SetCommTimeouts(hSerial, &cto);
-
-	return _open_osfhandle((LONG)hSerial, 0);
-#endif
-}
+#define icarus_open2(devpath, purge)  serial_open(devpath, 115200, ICARUS_READ_FAULT_DECISECONDS, purge)
+#define icarus_open(devpath)  icarus_open2(devpath, false)
 
 
 static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, int thr_id, int read_count)
 static int icarus_gets(unsigned char *buf, int fd, struct timeval *tv_finish, int thr_id, int read_count)
 {
 {
@@ -435,10 +379,7 @@ static bool icarus_detect_one(const char *devpath)
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
 	unsigned char ob_bin[64], nonce_bin[ICARUS_READ_SIZE];
 	char *nonce_hex;
 	char *nonce_hex;
 
 
-	if (total_devices == MAX_DEVICES)
-		return false;
-
-	fd = icarus_open(devpath);
+	fd = icarus_open2(devpath, true);
 	if (unlikely(fd == -1)) {
 	if (unlikely(fd == -1)) {
 		applog(LOG_ERR, "Icarus Detect: Failed to open %s", devpath);
 		applog(LOG_ERR, "Icarus Detect: Failed to open %s", devpath);
 		return false;
 		return false;
@@ -503,18 +444,7 @@ static bool icarus_detect_one(const char *devpath)
 
 
 static void icarus_detect()
 static void icarus_detect()
 {
 {
-	struct string_elist *iter, *tmp;
-	const char*s;
-
-	list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
-		s = iter->string;
-		if (!strncmp("icarus:", iter->string, 7))
-			s += 7;
-		if (!strcmp(s, "auto") || !strcmp(s, "noauto"))
-			continue;
-		if (icarus_detect_one(s))
-			string_elist_del(iter);
-	}
+	serial_detect("icarus", icarus_detect_one);
 }
 }
 
 
 static bool icarus_prepare(struct thr_info *thr)
 static bool icarus_prepare(struct thr_info *thr)

+ 273 - 0
fpgautils.c

@@ -0,0 +1,273 @@
+/*
+ * Copyright 2012 Luke Dashjr
+ * Copyright 2012 Andrew Smith
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <termios.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+#else
+#include <windows.h>
+#include <io.h>
+#endif
+
+#ifdef HAVE_LIBUDEV
+#include <libudev.h>
+#endif
+
+#include "elist.h"
+#include "fpgautils.h"
+#include "logging.h"
+#include "miner.h"
+
+char
+serial_autodetect_udev(detectone_func_t detectone, const char*prodname)
+{
+#ifdef HAVE_LIBUDEV
+	if (total_devices == MAX_DEVICES)
+		return 0;
+
+	struct udev *udev = udev_new();
+	struct udev_enumerate *enumerate = udev_enumerate_new(udev);
+	struct udev_list_entry *list_entry;
+	char found = 0;
+
+	udev_enumerate_add_match_subsystem(enumerate, "tty");
+	udev_enumerate_add_match_property(enumerate, "ID_MODEL", prodname);
+	udev_enumerate_scan_devices(enumerate);
+	udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) {
+		struct udev_device *device = udev_device_new_from_syspath(
+			udev_enumerate_get_udev(enumerate),
+			udev_list_entry_get_name(list_entry)
+		);
+		if (!device)
+			continue;
+
+		const char *devpath = udev_device_get_devnode(device);
+		if (devpath && detectone(devpath))
+			++found;
+
+		udev_device_unref(device);
+
+		if (total_devices == MAX_DEVICES)
+			break;
+	}
+	udev_enumerate_unref(enumerate);
+	udev_unref(udev);
+
+	return found;
+#else
+	return 0;
+#endif
+}
+
+char
+serial_autodetect_devserial(detectone_func_t detectone, const char*prodname)
+{
+#ifndef WIN32
+	if (total_devices == MAX_DEVICES)
+		return 0;
+
+	DIR *D;
+	struct dirent *de;
+	const char udevdir[] = "/dev/serial/by-id";
+	char devpath[sizeof(udevdir) + 1 + NAME_MAX];
+	char *devfile = devpath + sizeof(udevdir);
+	char found = 0;
+
+	D = opendir(udevdir);
+	if (!D)
+		return 0;
+	memcpy(devpath, udevdir, sizeof(udevdir) - 1);
+	devpath[sizeof(udevdir) - 1] = '/';
+	while ( (de = readdir(D)) ) {
+		if (!strstr(de->d_name, prodname))
+			continue;
+		strcpy(devfile, de->d_name);
+		if (detectone(devpath)) {
+			++found;
+			if (total_devices == MAX_DEVICES)
+				break;
+		}
+	}
+	closedir(D);
+
+	return found;
+#else
+	return 0;
+#endif
+}
+
+char
+_serial_detect(const char*dnamec, size_t dnamel, detectone_func_t detectone, autoscan_func_t autoscan, bool force_autoscan)
+{
+	if (total_devices == MAX_DEVICES)
+		return 0;
+
+	struct string_elist *iter, *tmp;
+	const char*s;
+	bool inhibitauto = false;
+	bool forceauto = false;
+	char found = 0;
+
+	list_for_each_entry_safe(iter, tmp, &scan_devices, list) {
+		s = iter->string;
+		if (!strncmp(dnamec, iter->string, dnamel))
+			s += dnamel;
+		if (!strcmp(s, "auto"))
+			forceauto = true;
+		else
+		if (!strcmp(s, "noauto"))
+			inhibitauto = true;
+		else
+		if (detectone(s)) {
+			string_elist_del(iter);
+			inhibitauto = true;
+			++found;
+			if (total_devices == MAX_DEVICES)
+				break;
+		}
+	}
+
+	if ((forceauto || !inhibitauto) && autoscan && total_devices < MAX_DEVICES)
+		found += autoscan();
+
+	return found;
+}
+
+int
+serial_open(const char*devpath, unsigned long baud, signed short timeout, bool purge)
+{
+#ifdef WIN32
+	HANDLE hSerial = CreateFile(devpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+	if (unlikely(hSerial == INVALID_HANDLE_VALUE))
+		return -1;
+
+	// thanks to af_newbie for pointers about this
+	COMMCONFIG comCfg = {0};
+	comCfg.dwSize = sizeof(COMMCONFIG);
+	comCfg.wVersion = 1;
+	comCfg.dcb.DCBlength = sizeof(DCB);
+	comCfg.dcb.BaudRate = baud;
+	comCfg.dcb.fBinary = 1;
+	comCfg.dcb.fDtrControl = DTR_CONTROL_ENABLE;
+	comCfg.dcb.fRtsControl = RTS_CONTROL_ENABLE;
+	comCfg.dcb.ByteSize = 8;
+
+	SetCommConfig(hSerial, &comCfg, sizeof(comCfg));
+
+	const DWORD ctoms = (timeout == -1) ? 30000 : (timeout * 100);
+	COMMTIMEOUTS cto = {ctoms, 0, ctoms, 0, ctoms};
+	SetCommTimeouts(hSerial, &cto);
+
+	if (purge) {
+		PurgeComm(hSerial, PURGE_RXABORT);
+		PurgeComm(hSerial, PURGE_TXABORT);
+		PurgeComm(hSerial, PURGE_RXCLEAR);
+		PurgeComm(hSerial, PURGE_TXCLEAR);
+	}
+
+	return _open_osfhandle((LONG)hSerial, 0);
+#else
+	int fdDev = open(devpath, O_RDWR | O_CLOEXEC | O_NOCTTY);
+
+	if (unlikely(fdDev == -1))
+		return -1;
+
+	struct termios pattr;
+	tcgetattr(fdDev, &pattr);
+	pattr.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
+	pattr.c_oflag &= ~OPOST;
+	pattr.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+	pattr.c_cflag &= ~(CSIZE | PARENB);
+	pattr.c_cflag |= CS8;
+
+	switch (baud) {
+	case 0: break;
+	case 115200: pattr.c_cflag = B115200; break;
+	default:
+		applog(LOG_WARNING, "Unrecognized baud rate: %lu", baud);
+	}
+	pattr.c_cflag |= CREAD | CLOCAL;
+
+	if (timeout >= 0) {
+		pattr.c_cc[VTIME] = (cc_t)timeout;
+		pattr.c_cc[VMIN] = 0;
+	}
+
+	tcsetattr(fdDev, TCSANOW, &pattr);
+	if (purge)
+		tcflush(fdDev, TCIOFLUSH);
+	return fdDev;
+#endif
+}
+
+ssize_t
+_serial_read(int fd, char *buf, size_t bufsiz, char *eol)
+{
+	ssize_t len, tlen = 0;
+	while (bufsiz) {
+		len = read(fd, buf, eol ? 1 : bufsiz);
+		if (len < 1)
+			break;
+		tlen += len;
+		if (eol && *eol == buf[0])
+			break;
+		buf += len;
+		bufsiz -= len;
+	}
+	return tlen;
+}
+
+static FILE*
+_open_bitstream(const char*path, const char*subdir, const char*filename)
+{
+	char fullpath[PATH_MAX];
+	strcpy(fullpath, path);
+	strcat(fullpath, "/");
+	if (subdir) {
+		strcat(fullpath, subdir);
+		strcat(fullpath, "/");
+	}
+	strcat(fullpath, filename);
+	return fopen(fullpath, "rb");
+}
+#define _open_bitstream(path, subdir)  do {  \
+	f = _open_bitstream(path, subdir, filename);  \
+	if (f)  \
+		return f;  \
+} while(0)
+
+#define _open_bitstream3(path)  do {  \
+	_open_bitstream(path, dname);  \
+	_open_bitstream(path, "bitstreams");  \
+	_open_bitstream(path, NULL);  \
+} while(0)
+
+FILE*
+open_bitstream(const char*dname, const char*filename)
+{
+	FILE *f;
+
+	_open_bitstream3(opt_kernel_path);
+	_open_bitstream3(cgminer_path);
+	_open_bitstream3(".");
+
+	return NULL;
+}

+ 39 - 0
fpgautils.h

@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Luke Dashjr
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.  See COPYING for more details.
+ */
+
+#ifndef FPGAUTILS_H
+#define FPGAUTILS_H
+
+#include <stdbool.h>
+#include <stdio.h>
+
+typedef bool(*detectone_func_t)(const char*);
+typedef char(*autoscan_func_t)();
+
+extern char _serial_detect(const char*dnamec, size_t dnamel, detectone_func_t, autoscan_func_t, bool force_autoscan);
+#define serial_detect_fauto(dname, detectone, autoscan)  \
+	_serial_detect(dname ":", sizeof(dname)+1, detectone, autoscan, true)
+#define serial_detect_auto(dname, detectone, autoscan)  \
+	_serial_detect(dname ":", sizeof(dname)+1, detectone, autoscan, false)
+#define serial_detect(dname, detectone)  \
+	_serial_detect(dname ":", sizeof(dname)+1, detectone,     NULL, false)
+extern char serial_autodetect_devserial(detectone_func_t, const char*prodname);
+extern char serial_autodetect_udev     (detectone_func_t, const char*prodname);
+
+extern int serial_open(const char*devpath, unsigned long baud, signed short timeout, bool purge);
+extern ssize_t _serial_read(int fd, char *buf, size_t buflen, char*eol);
+#define serial_read(fd, buf, count)  \
+	_serial_read(fd, (char*)(buf), count, NULL)
+#define serial_read_line(fd, buf, bufsiz, eol)  \
+	_serial_read(fd, buf, count, &eol)
+#define serial_close(fd)  close(fd)
+
+extern FILE*open_bitstream(const char*dname, const char*filename);
+
+#endif

+ 7 - 6
libztex.c

@@ -22,6 +22,8 @@
 
 
 #include <stdio.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <unistd.h>
+
+#include "fpgautils.h"
 #include "miner.h"
 #include "miner.h"
 #include "libztex.h"
 #include "libztex.h"
 
 
@@ -150,7 +152,7 @@ static int libztex_configureFpgaHS(struct libztex_device *ztex, const char* firm
 	libusb_claim_interface(ztex->hndl, settings[1]);
 	libusb_claim_interface(ztex->hndl, settings[1]);
 
 
 	for (tries = 3; tries > 0; tries--) {
 	for (tries = 3; tries > 0; tries--) {
-		fp = fopen(firmware, "rb");
+		fp = open_bitstream("ztex", firmware);
 		if (!fp) {
 		if (!fp) {
 			applog(LOG_ERR, "%s: failed to read firmware '%s'", ztex->repr, firmware);
 			applog(LOG_ERR, "%s: failed to read firmware '%s'", ztex->repr, firmware);
 			return -2;
 			return -2;
@@ -245,7 +247,7 @@ static int libztex_configureFpgaLS(struct libztex_device *ztex, const char* firm
 	}
 	}
 
 
 	for (tries = 10; tries > 0; tries--) {
 	for (tries = 10; tries > 0; tries--) {
-		fp = fopen(firmware, "rb");
+		fp = open_bitstream("ztex", firmware);
 		if (!fp) {
 		if (!fp) {
 			applog(LOG_ERR, "%s: failed to read firmware '%s'", ztex->repr, firmware);
 			applog(LOG_ERR, "%s: failed to read firmware '%s'", ztex->repr, firmware);
 			return -2;
 			return -2;
@@ -316,12 +318,11 @@ static int libztex_configureFpgaLS(struct libztex_device *ztex, const char* firm
 
 
 int libztex_configureFpga(struct libztex_device *ztex)
 int libztex_configureFpga(struct libztex_device *ztex)
 {
 {
-	char buf[256] = "bitstreams/";
+	char buf[256];
 	int rv;
 	int rv;
 
 
-	memset(&buf[11], 0, 245);
-	strcpy(&buf[11], ztex->bitFileName);
-	strcpy(&buf[strlen(buf)], ".bit");
+	strcpy(buf, ztex->bitFileName);
+	strcat(buf, ".bit");
 	rv = libztex_configureFpgaHS(ztex, buf, true, 2); 
 	rv = libztex_configureFpgaHS(ztex, buf, true, 2); 
 	if (rv != 0)
 	if (rv != 0)
 		rv = libztex_configureFpgaLS(ztex, buf, true, 2); 
 		rv = libztex_configureFpgaLS(ztex, buf, true, 2); 

+ 1 - 0
miner.h

@@ -743,6 +743,7 @@ struct work {
 };
 };
 
 
 extern void get_datestamp(char *, struct timeval *);
 extern void get_datestamp(char *, struct timeval *);
+extern bool test_nonce(struct work *work, uint32_t nonce);
 bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
 bool submit_nonce(struct thr_info *thr, struct work *work, uint32_t nonce);
 extern void tailsprintf(char *f, const char *fmt, ...);
 extern void tailsprintf(char *f, const char *fmt, ...);
 extern void wlogprint(const char *f, ...);
 extern void wlogprint(const char *f, ...);