Browse Source

Merge branch 'win_autoscan' into bfgminer

Luke Dashjr 12 years ago
parent
commit
c37369aa97
6 changed files with 330 additions and 3 deletions
  1. 3 0
      Makefile.am
  2. 31 2
      configure.ac
  3. 253 0
      fpgautils.c
  4. 23 0
      logging.h
  5. 16 1
      util.c
  6. 4 0
      util.h

+ 3 - 0
Makefile.am

@@ -53,6 +53,9 @@ bfgminer_CPPFLAGS += @JANSSON_CFLAGS@
 bfgminer_CPPFLAGS += $(PTHREAD_FLAGS)
 bfgminer_CPPFLAGS += $(NCURSES_CPPFLAGS)
 
+bfgminer_CPPFLAGS += $(AUTOSCAN_CPPFLAGS)
+bfgminer_LDADD += $(AUTOSCAN_LIBS)
+
 bfgminer_LDADD += $(libblkmaker_LIBS)
 bfgminer_LDFLAGS += $(libblkmaker_LDFLAGS)
 bfgminer_CPPFLAGS += $(libblkmaker_CFLAGS)

+ 31 - 2
configure.ac

@@ -115,6 +115,8 @@ need_lowlevel=no
 have_cygwin=false
 have_win32=false
 have_macho=false
+AUTOSCAN_CPPFLAGS=""
+AUTOSCAN_LIBS=""
 DLOPEN_FLAGS="-ldl"
 WS2_LIBS=""
 MM_LIBS=""
@@ -714,6 +716,30 @@ if test x$need_fpgautils = xyes; then
 	
 	if $have_win32; then
 		echo '#include <iospeeds.h>' >iospeeds_local.h
+		
+		found_ddkusb=false
+		AC_CHECK_HEADER([usbiodef.h],[
+			found_ddkusb=true
+		],[
+			AC_CHECK_HEADER([ddk/usbiodef.h],[
+				found_ddkusb=true
+				AUTOSCAN_CPPFLAGS="-I"`echo '#include <ddk/usbiodef.h>' | ${CPP} -M - 2>/dev/null | tr -d '\\n\\r\\\\' | sed -e 's/^.*[[:space:]:]\(\/[^[:space:]]*\)usbiodef\.h[[:space:]].*$/\1/' -e t -e d`
+			],[
+				true
+			],[
+				#include <windows.h>
+				#include <ddk/usbioctl.h>
+				AC_INCLUDES_DEFAULT
+			])
+		],[
+			#include <windows.h>
+			#include <usbioctl.h>
+			AC_INCLUDES_DEFAULT
+		])
+		if $found_ddkusb; then
+			AUTOSCAN_LIBS="-lsetupapi"
+			AC_DEFINE([HAVE_WIN_DDKUSB],[1],[Defined to 1 if Windows DDK USB headers are being used])
+		fi
 	else
 		AC_MSG_CHECKING([what baud rates your system supports])
 		echo '#include <termios.h>' | ${CPP} -dM - 2>/dev/null | sed 's/.*[ 	]B\([0-9][0-9]*\)[ 	].*/IOSPEED(\1)/' | grep IOSPEED >iospeeds_local.h
@@ -890,6 +916,7 @@ AM_CONDITIONAL([HAVE_SENSORS], [test x$with_sensors = xyes])
 AM_CONDITIONAL([HAVE_CYGWIN], [test x$have_cygwin = xtrue])
 AM_CONDITIONAL([HAVE_WINDOWS], [test x$have_win32 = xtrue])
 AM_CONDITIONAL([HAVE_x86_64], [test x$have_x86_64 = xtrue])
+AM_CONDITIONAL([HAVE_WIN_DDKUSB], [test x$found_ddkusb = xtrue])
 AM_CONDITIONAL([HAS_FPGA], [test x$bitforce$icarus$modminer$x6500$ztex != xnonononono])
 AM_CONDITIONAL([HAS_ASIC], [test x$avalon$bfsb$bigpic$icarus$httpsrv$metabank != xnononononono])
 
@@ -1221,6 +1248,8 @@ AC_DEFINE_UNQUOTED([DIABLO_KERNNAME], ["diablo130302"], [Filename for diablo ker
 AC_DEFINE_UNQUOTED([SCRYPT_KERNNAME], ["scrypt130511"], [Filename for scrypt kernel])
 
 
+AC_SUBST(AUTOSCAN_CPPFLAGS)
+AC_SUBST(AUTOSCAN_LIBS)
 AC_SUBST(PTHREAD_FLAGS)
 AC_SUBST(DLOPEN_FLAGS)
 AC_SUBST(PTHREAD_LIBS)
@@ -1293,8 +1322,8 @@ BFG_PRINT_LIST([Options...],[optlist])
 
 echo
 echo "Compilation............: make (or gmake)"
-echo "  CFLAGS...............: $CPPFLAGS $NCURSES_CPPFLAGS $PTHREAD_FLAGS $CFLAGS $LIBUSB_CFLAGS $JANSSON_CFLAGS $PTHREAD_FLAGS $libblkmaker_CFLAGS $hidapi_CFLAGS"
-echo "  LDFLAGS..............: $LDFLAGS $PTHREAD_FLAGS $libblkmaker_LDFLAGS $PTHREAD_LIBS $LIBS $DLOPEN_FLAGS $LIBCURL_LIBS $JANSSON_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $UDEV_LIBS $LIBUSB_LIBS $RT_LIBS $sensors_LIBS $libblkmaker_LIBS"
+echo "  CFLAGS...............: $CPPFLAGS $AUTOSCAN_CPPFLAGS $NCURSES_CPPFLAGS $PTHREAD_FLAGS $CFLAGS $LIBUSB_CFLAGS $JANSSON_CFLAGS $PTHREAD_FLAGS $libblkmaker_CFLAGS $hidapi_CFLAGS"
+echo "  LDFLAGS..............: $LDFLAGS $AUTOSCAN_LIBS $PTHREAD_FLAGS $libblkmaker_LDFLAGS $PTHREAD_LIBS $LIBS $DLOPEN_FLAGS $LIBCURL_LIBS $JANSSON_LIBS $NCURSES_LIBS $PDCURSES_LIBS $WS2_LIBS $MATH_LIBS $UDEV_LIBS $LIBUSB_LIBS $RT_LIBS $sensors_LIBS $libblkmaker_LIBS"
 echo
 echo "Installation...........: make install$maybe_ldconfig #(as root if needed, with 'su' or 'sudo')"
 echo "  prefix...............: $prefix"

+ 253 - 0
fpgautils.c

@@ -47,6 +47,13 @@
 #endif
 #else  /* WIN32 */
 #include <windows.h>
+
+#ifdef HAVE_WIN_DDKUSB
+#include <setupapi.h>
+#include <usbioctl.h>
+#include <usbiodef.h>
+#endif
+
 #include <io.h>
 
 #include <utlist.h>
@@ -77,6 +84,8 @@ enum {
 
 #include "logging.h"
 #include "miner.h"
+#include "util.h"
+
 #include "fpgautils.h"
 
 #define SEARCH_NEEDLES_BEGIN()  {  \
@@ -381,6 +390,247 @@ int _serial_autodetect_sysfs(detectone_func_t detectone, va_list needles)
 #	define _serial_autodetect_sysfs(...)  (0)
 #endif
 
+#ifdef HAVE_WIN_DDKUSB
+
+static const GUID WIN_GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3ABF6F2D, 0x71C4, 0x462A, {0x8A, 0x92, 0x1E, 0x68, 0x61, 0xE6, 0xAF, 0x27} };
+
+static
+char *windows_usb_get_port_path(HANDLE hubh, const int portno)
+{
+	size_t namesz;
+	ULONG rsz;
+	
+	{
+		USB_NODE_CONNECTION_NAME pathinfo = {
+			.ConnectionIndex = portno,
+		};
+		if (!(DeviceIoControl(hubh, IOCTL_USB_GET_NODE_CONNECTION_NAME, &pathinfo, sizeof(pathinfo), &pathinfo, sizeof(pathinfo), &rsz, NULL) && rsz >= sizeof(pathinfo)))
+			applogfailinfor(NULL, LOG_ERR, "ioctl (1)", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+		namesz = pathinfo.ActualLength;
+	}
+	
+	const size_t bufsz = sizeof(USB_NODE_CONNECTION_NAME) + namesz;
+	uint8_t buf[bufsz];
+	USB_NODE_CONNECTION_NAME *path = (USB_NODE_CONNECTION_NAME *)buf;
+	*path = (USB_NODE_CONNECTION_NAME){
+		.ConnectionIndex = portno,
+	};
+	
+	if (!(DeviceIoControl(hubh, IOCTL_USB_GET_NODE_CONNECTION_NAME, path, bufsz, path, bufsz, &rsz, NULL) && rsz >= sizeof(*path)))
+		applogfailinfor(NULL, LOG_ERR, "ioctl (2)", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+	
+	return ucs2tochar_dup(path->NodeName, path->ActualLength);
+}
+
+static
+char *windows_usb_get_string(HANDLE hubh, const int portno, const uint8_t descid)
+{
+	if (!descid)
+		return NULL;
+	
+	const size_t descsz_max = sizeof(USB_STRING_DESCRIPTOR) + MAXIMUM_USB_STRING_LENGTH;
+	const size_t reqsz = sizeof(USB_DESCRIPTOR_REQUEST) + descsz_max;
+	uint8_t buf[reqsz];
+	
+	USB_DESCRIPTOR_REQUEST * const req = (USB_DESCRIPTOR_REQUEST *)buf;
+	USB_STRING_DESCRIPTOR * const desc = (USB_STRING_DESCRIPTOR *)&req[1];
+	*req = (USB_DESCRIPTOR_REQUEST){
+		.ConnectionIndex = portno,
+		.SetupPacket = {
+			.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8) | descid,
+			.wIndex = 0,
+			.wLength = descsz_max,
+		},
+	};
+	// Need to explicitly zero the output memory
+	memset(desc, '\0', descsz_max);
+	
+	ULONG descsz;
+	if (!DeviceIoControl(hubh, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, req, reqsz, req, reqsz, &descsz, NULL))
+		applogfailinfor(NULL, LOG_DEBUG, "ioctl", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+	
+	if (descsz < 2 || desc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE || desc->bLength > descsz - sizeof(USB_DESCRIPTOR_REQUEST) || desc->bLength % 2)
+		applogfailr(NULL, LOG_ERR, "sanity check");
+	
+	return ucs2tochar_dup(desc->bString, desc->bLength);
+}
+
+static void _serial_autodetect_windows__hub(detectone_func_t, va_list, int *, const char *);
+
+static
+void _serial_autodetect_windows__hubport(detectone_func_t detectone, va_list needles, int * const foundp, HANDLE hubh, const int portno)
+{
+	const size_t conninfosz = sizeof(USB_NODE_CONNECTION_INFORMATION) + (sizeof(USB_PIPE_INFO) * 30);
+	uint8_t buf[conninfosz];
+	USB_NODE_CONNECTION_INFORMATION * const conninfo = (USB_NODE_CONNECTION_INFORMATION *)buf;
+	
+	conninfo->ConnectionIndex = portno;
+	
+	ULONG respsz;
+	if (!DeviceIoControl(hubh, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, conninfo, conninfosz, conninfo, conninfosz, &respsz, NULL))
+		applogfailinfor(, LOG_ERR, "ioctl", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+	
+	if (conninfo->ConnectionStatus != DeviceConnected)
+		return;
+	
+	if (conninfo->DeviceIsHub)
+	{
+		const char * const hubpath = windows_usb_get_port_path(hubh, portno);
+		if (hubpath)
+			_serial_autodetect_windows__hub(detectone, needles, foundp, hubpath);
+		return;
+	}
+	
+	const USB_DEVICE_DESCRIPTOR * const devdesc = &conninfo->DeviceDescriptor;
+	char * const product = windows_usb_get_string(hubh, portno, devdesc->iProduct);
+	if (!product)
+		return;
+	char *serial = NULL;
+	if (!search_needles(product, needles))
+	{
+out:
+		free(product);
+		free(serial);
+		return;
+	}
+	
+	serial = windows_usb_get_string(hubh, portno, devdesc->iSerialNumber);
+	if (!serial)
+		goto out;
+	const size_t slen = strlen(serial);
+	char subkey[52 + slen + 18 + 1];
+	sprintf(subkey, "SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%04x&PID_%04x\\%s\\Device Parameters",
+	        (unsigned)devdesc->idVendor, (unsigned)devdesc->idProduct, serial);
+	HKEY hkey;
+	int e;
+	if (ERROR_SUCCESS != (e = RegOpenKey(HKEY_LOCAL_MACHINE, subkey, &hkey)))
+	{
+		applogfailinfo(LOG_ERR, "open Device Parameters registry key", "%s", bfg_strerror(e, BST_SYSTEM));
+		goto out;
+	}
+	char devpath[0x10] = "\\\\.\\";
+	DWORD type, sz = sizeof(devpath) - 4;
+	if (ERROR_SUCCESS != (e = RegQueryValueExA(hkey, "PortName", NULL, &type, (LPBYTE)&devpath[4], &sz)))
+	{
+		applogfailinfo(LOG_ERR, "get PortName registry key value", "%s", bfg_strerror(e, BST_SYSTEM));
+		RegCloseKey(hkey);
+		goto out;
+	}
+	RegCloseKey(hkey);
+	if (type != REG_SZ)
+	{
+		applogfailinfor(, LOG_ERR, "get expected type for PortName registry key value", "%ld", (long)type);
+		goto out;
+	}
+	
+	char * const manuf = windows_usb_get_string(hubh, portno, devdesc->iManufacturer);
+	
+	detectone_meta_info = (struct detectone_meta_info_t){
+		.manufacturer = manuf,
+		.product = product,
+		.serial = serial,
+	};
+	
+	if (detectone(devpath))
+		++*foundp;
+	
+	clear_detectone_meta_info();
+	free(manuf);
+	goto out;
+}
+
+static
+void _serial_autodetect_windows__hub(detectone_func_t detectone, va_list needles, int * const foundp, const char * const hubpath)
+{
+	HANDLE hubh;
+	USB_NODE_INFORMATION nodeinfo;
+	
+	{
+		char deviceName[4 + strlen(hubpath) + 1];
+		sprintf(deviceName, "\\\\.\\%s", hubpath);
+		hubh = CreateFile(deviceName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+		if (hubh == INVALID_HANDLE_VALUE)
+			applogr(, LOG_ERR, "Error opening USB hub device %s for autodetect: %s", deviceName, bfg_strerror(GetLastError(), BST_SYSTEM));
+	}
+	
+	ULONG nBytes;
+	if (!DeviceIoControl(hubh, IOCTL_USB_GET_NODE_INFORMATION, &nodeinfo, sizeof(nodeinfo), &nodeinfo, sizeof(nodeinfo), &nBytes, NULL))
+		applogfailinfor(, LOG_ERR, "ioctl", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+	
+	const int portcount = nodeinfo.u.HubInformation.HubDescriptor.bNumberOfPorts;
+	for (int i = 1; i <= portcount; ++i)
+		_serial_autodetect_windows__hubport(detectone, needles, foundp, hubh, i);
+	
+	CloseHandle(hubh);
+}
+
+static
+char *windows_usb_get_root_hub_path(HANDLE hcntlrh)
+{
+	size_t namesz;
+	ULONG rsz;
+	
+	{
+		USB_ROOT_HUB_NAME pathinfo;
+		if (!(DeviceIoControl(hcntlrh, IOCTL_USB_GET_ROOT_HUB_NAME, 0, 0, &pathinfo, sizeof(pathinfo), &rsz, NULL) && rsz >= sizeof(pathinfo)))
+			applogfailinfor(NULL, LOG_ERR, "ioctl (1)", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+		namesz = pathinfo.ActualLength;
+	}
+	
+	const size_t bufsz = sizeof(USB_ROOT_HUB_NAME) + namesz;
+	uint8_t buf[bufsz];
+	USB_ROOT_HUB_NAME *hubpath = (USB_ROOT_HUB_NAME *)buf;
+	
+	if (!(DeviceIoControl(hcntlrh, IOCTL_USB_GET_ROOT_HUB_NAME, NULL, 0, hubpath, bufsz, &rsz, NULL) && rsz >= sizeof(*hubpath)))
+		applogfailinfor(NULL, LOG_ERR, "ioctl (2)", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+	
+	return ucs2tochar_dup(hubpath->RootHubName, hubpath->ActualLength);
+}
+
+static
+void _serial_autodetect_windows__hcntlr(detectone_func_t detectone, va_list needles, int * const foundp, HDEVINFO *devinfo, const int i)
+{
+	SP_DEVICE_INTERFACE_DATA devifacedata = {
+		.cbSize = sizeof(devifacedata),
+	};
+	if (!SetupDiEnumDeviceInterfaces(*devinfo, 0, (LPGUID)&WIN_GUID_DEVINTERFACE_USB_HOST_CONTROLLER, i, &devifacedata))
+		applogfailinfor(, LOG_ERR, "SetupDiEnumDeviceInterfaces", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+	DWORD detailsz;
+	if (!(!SetupDiGetDeviceInterfaceDetail(*devinfo, &devifacedata, NULL, 0, &detailsz, NULL) && GetLastError() == ERROR_INSUFFICIENT_BUFFER))
+		applogfailinfor(, LOG_ERR, "SetupDiEnumDeviceInterfaceDetail (1)", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+	PSP_DEVICE_INTERFACE_DETAIL_DATA detail = alloca(detailsz);
+	detail->cbSize = sizeof(*detail);
+	if (!SetupDiGetDeviceInterfaceDetail(*devinfo, &devifacedata, detail, detailsz, &detailsz, NULL))
+		applogfailinfor(, LOG_ERR, "SetupDiEnumDeviceInterfaceDetail (2)", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+	HANDLE hcntlrh = CreateFile(detail->DevicePath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+	if (hcntlrh == INVALID_HANDLE_VALUE)
+		applogfailinfor(, LOG_DEBUG, "open USB host controller device", "%s", bfg_strerror(GetLastError(), BST_SYSTEM));
+	char * const hubpath = windows_usb_get_root_hub_path(hcntlrh);
+	CloseHandle(hcntlrh);
+	_serial_autodetect_windows__hub(detectone, needles, foundp, hubpath);
+	free(hubpath);
+}
+
+static
+int _serial_autodetect_windows(detectone_func_t detectone, va_list needles)
+{
+	int found = 0;
+	HDEVINFO devinfo;
+	devinfo = SetupDiGetClassDevs(&WIN_GUID_DEVINTERFACE_USB_HOST_CONTROLLER, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
+	SP_DEVINFO_DATA devinfodata = {
+		.cbSize = sizeof(devinfodata),
+	};
+	
+	for (int i = 0; SetupDiEnumDeviceInfo(devinfo, i, &devinfodata); ++i)
+		_serial_autodetect_windows__hcntlr(detectone, needles, &found, &devinfo, i);
+	SetupDiDestroyDeviceInfoList(devinfo);
+	
+	return found;
+}
+
+#endif
+
+
 #ifdef WIN32
 #define LOAD_SYM(sym)  do { \
 	if (!(sym = dlsym(dll, #sym))) {  \
@@ -489,6 +739,9 @@ int _serial_autodetect(detectone_func_t detectone, ...)
 		_serial_autodetect_udev     (detectone, needles) ?:
 		_serial_autodetect_sysfs    (detectone, needles) ?:
 		_serial_autodetect_devserial(detectone, needles) ?:
+#ifdef HAVE_WIN_DDKUSB
+		_serial_autodetect_windows  (detectone, needles) ?:
+#endif
 		_serial_autodetect_ftdi     (detectone, needles) ?:
 		0);
 	va_end(needles);

+ 23 - 0
logging.h

@@ -80,6 +80,29 @@ extern void _applog(int prio, const char *str);
 
 #define perror(s)  appperror(LOG_ERR, s)
 
+#define applogfailinfo(prio, failed, fmt, ...)  do {  \
+	applog(prio, "Failed to %s"IN_FMT_FFL": "fmt,  \
+	       failed,  \
+	       __FILE__, __func__, __LINE__,  \
+	       __VA_ARGS__);  \
+} while (0)
+
+#define applogfailinfor(rv, prio, failed, fmt, ...)  do {  \
+	applogfailinfo(prio, failed, fmt, __VA_ARGS__);  \
+	return rv;  \
+} while (0)
+
+#define applogfail(prio, failed)  do {  \
+	applog(prio, "Failed to %s"IN_FMT_FFL,  \
+	       failed,  \
+	       __FILE__, __func__, __LINE__);  \
+} while (0)
+
+#define applogfailr(rv, prio, failed)  do {  \
+	applogfail(prio, failed);  \
+	return rv;  \
+} while (0)
+
 extern void _bfg_clean_up(void);
 
 #define quit(status, fmt, ...) do { \

+ 16 - 1
util.c

@@ -724,6 +724,20 @@ badchar:
 	return likely(!hexstr[0]);
 }
 
+void ucs2tochar(char * const out, const uint16_t * const in, const size_t sz)
+{
+	for (int i = 0; i < sz; ++i)
+		out[i] = in[i];
+}
+
+char *ucs2tochar_dup(uint16_t * const in, const size_t sz)
+{
+	char *out = malloc(sz + 1);
+	ucs2tochar(out, in, sz);
+	out[sz] = '\0';
+	return out;
+}
+
 void hash_data(unsigned char *out_hash, const unsigned char *data)
 {
 	unsigned char blkheader[80];
@@ -2571,9 +2585,10 @@ const char *bfg_strerror(int e, enum bfg_strerror_type type)
 #endif
 			break;
 		case BST_SOCKET:
+		case BST_SYSTEM:
 		{
 #ifdef WIN32
-			// Windows has a different namespace for socket errors
+			// Windows has a different namespace for system and socket errors
 			LPSTR *msg = &bfgtls->bfg_strerror_socketresult;
 			if (*msg)
 				LocalFree(*msg);

+ 4 - 0
util.h

@@ -113,6 +113,9 @@ extern json_t *json_rpc_call_completed(CURL *, int rc, bool probe, int *rolltime
 
 extern char *absolute_uri(char *uri, const char *ref);  // ref must be a root URI
 
+extern void ucs2tochar(char *out, const uint16_t *in, size_t sz);
+extern char *ucs2tochar_dup(uint16_t *in, size_t sz);
+
 extern void gen_hash(unsigned char *data, unsigned char *hash, int len);
 extern void hash_data(unsigned char *out_hash, const unsigned char *data);
 extern void real_block_target(unsigned char *target, const unsigned char *data);
@@ -169,6 +172,7 @@ enum bfg_strerror_type {
 	BST_ERRNO,
 	BST_SOCKET,
 	BST_LIBUSB,
+	BST_SYSTEM,
 };
 extern const char *bfg_strerror(int, enum bfg_strerror_type);